summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk23
-rw-r--r--api/current.txt1006
-rw-r--r--api/system-current.txt1095
-rw-r--r--api/test-current.txt1021
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java71
-rw-r--r--cmds/bootanimation/BootAnimation.cpp37
-rw-r--r--cmds/bootanimation/BootAnimation.h16
-rwxr-xr-xcmds/media/src/com/android/commands/media/VolumeCtrl.java22
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--cmds/screencap/screencap.cpp4
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java2
-rw-r--r--cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java2
-rw-r--r--compiled-classes-phone1750
-rw-r--r--core/java/android/accessibilityservice/AccessibilityButtonController.java223
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java185
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java118
-rw-r--r--core/java/android/accessibilityservice/FingerprintGestureController.java185
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl8
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl7
-rw-r--r--core/java/android/accounts/AbstractAccountAuthenticator.java4
-rw-r--r--core/java/android/accounts/AccountManager.java123
-rw-r--r--core/java/android/accounts/ChooseAccountActivity.java4
-rw-r--r--core/java/android/accounts/ChooseTypeAndAccountActivity.java106
-rw-r--r--core/java/android/accounts/IAccountManager.aidl13
-rw-r--r--core/java/android/animation/AnimationHandler.java3
-rw-r--r--core/java/android/animation/Animator.java82
-rw-r--r--core/java/android/animation/AnimatorSet.java1090
-rw-r--r--core/java/android/animation/ObjectAnimator.java5
-rw-r--r--core/java/android/animation/ValueAnimator.java255
-rw-r--r--core/java/android/annotation/FontRes.java37
-rw-r--r--core/java/android/app/Activity.java137
-rw-r--r--core/java/android/app/ActivityManager.java28
-rw-r--r--core/java/android/app/ActivityOptions.java3
-rw-r--r--core/java/android/app/ActivityThread.java78
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java13
-rw-r--r--core/java/android/app/ActivityTransitionState.java20
-rw-r--r--core/java/android/app/AppImportanceMonitor.java148
-rw-r--r--core/java/android/app/ApplicationPackageManager.java46
-rw-r--r--core/java/android/app/BackStackRecord.java173
-rw-r--r--core/java/android/app/ContextImpl.java99
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java10
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java6
-rw-r--r--core/java/android/app/Fragment.java51
-rw-r--r--core/java/android/app/FragmentManager.java91
-rw-r--r--core/java/android/app/FragmentTransaction.java34
-rw-r--r--core/java/android/app/FragmentTransition.java26
-rw-r--r--core/java/android/app/IActivityManager.aidl5
-rw-r--r--core/java/android/app/IApplicationThread.aidl2
-rw-r--r--core/java/android/app/INotificationManager.aidl6
-rw-r--r--core/java/android/app/IProcessObserver.aidl3
-rw-r--r--core/java/android/app/IUiModeManager.aidl7
-rw-r--r--core/java/android/app/Instrumentation.java30
-rw-r--r--core/java/android/app/LoadedApk.java212
-rw-r--r--core/java/android/app/Notification.java704
-rw-r--r--core/java/android/app/NotificationChannel.java219
-rw-r--r--core/java/android/app/NotificationChannelGroup.aidl19
-rw-r--r--core/java/android/app/NotificationChannelGroup.java187
-rw-r--r--core/java/android/app/NotificationManager.java40
-rw-r--r--core/java/android/app/ProfilerInfo.java9
-rw-r--r--core/java/android/app/RemoteAction.java53
-rw-r--r--core/java/android/app/SystemServiceRegistry.java33
-rw-r--r--core/java/android/app/TaskStackBuilder.java4
-rw-r--r--core/java/android/app/TimePickerDialog.java23
-rw-r--r--core/java/android/app/UiAutomation.java20
-rw-r--r--core/java/android/app/UiModeManager.java15
-rw-r--r--core/java/android/app/VrManager.java44
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java503
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl47
-rw-r--r--core/java/android/app/admin/SecurityLog.java3
-rw-r--r--core/java/android/app/assist/AssistStructure.java150
-rw-r--r--core/java/android/app/backup/BackupAgent.java2
-rw-r--r--core/java/android/app/backup/BackupManager.java88
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl19
-rw-r--r--core/java/android/app/backup/ISelectBackupTransportCallback.aidl41
-rw-r--r--core/java/android/app/backup/SelectBackupTransportCallback.java44
-rw-r--r--core/java/android/app/usage/StorageStatsManager.java3
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java13
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java17
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java19
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java154
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.aidl19
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java134
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl1
-rw-r--r--core/java/android/bluetooth/IBluetoothA2dp.aidl3
-rw-r--r--core/java/android/bluetooth/le/ScanFilter.java14
-rw-r--r--core/java/android/companion/AssociationRequest.aidl19
-rw-r--r--core/java/android/companion/AssociationRequest.java191
-rw-r--r--core/java/android/companion/BluetoothDeviceFilter.java202
-rw-r--r--core/java/android/companion/BluetoothDeviceFilterUtils.java107
-rw-r--r--core/java/android/companion/BluetoothLEDeviceFilter.aidl19
-rw-r--r--core/java/android/companion/BluetoothLEDeviceFilter.java151
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java141
-rw-r--r--core/java/android/companion/DeviceFilter.java46
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl35
-rw-r--r--core/java/android/companion/ICompanionDeviceManagerService.aidl29
-rw-r--r--core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl24
-rw-r--r--core/java/android/companion/IOnAssociateCallback.aidl25
-rw-r--r--core/java/android/content/ClipDescription.java36
-rw-r--r--core/java/android/content/ContentValues.java6
-rw-r--r--core/java/android/content/Context.java49
-rw-r--r--core/java/android/content/ContextWrapper.java8
-rw-r--r--core/java/android/content/Intent.java115
-rw-r--r--core/java/android/content/SyncRequest.java4
-rw-r--r--core/java/android/content/om/IOverlayManager.aidl129
-rw-r--r--core/java/android/content/om/OverlayInfo.aidl19
-rw-r--r--core/java/android/content/om/OverlayInfo.java263
-rw-r--r--core/java/android/content/pm/ActivityInfo.java79
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java85
-rw-r--r--core/java/android/content/pm/ComponentInfo.java19
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl23
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl38
-rw-r--r--core/java/android/content/pm/IShortcutService.aidl2
-rw-r--r--core/java/android/content/pm/InstantAppInfo.aidl (renamed from core/java/android/content/pm/EphemeralApplicationInfo.aidl)2
-rw-r--r--core/java/android/content/pm/InstantAppInfo.java (renamed from core/java/android/content/pm/EphemeralApplicationInfo.java)53
-rw-r--r--core/java/android/content/pm/InstrumentationInfo.java50
-rw-r--r--core/java/android/content/pm/LauncherApps.java59
-rw-r--r--core/java/android/content/pm/PackageManager.java133
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java56
-rw-r--r--core/java/android/content/pm/PackageParser.java284
-rw-r--r--core/java/android/content/pm/PermissionInfo.java1
-rw-r--r--core/java/android/content/pm/ShortcutManager.java3
-rw-r--r--core/java/android/content/pm/ShortcutServiceInternal.java2
-rw-r--r--core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl3
-rw-r--r--core/java/android/content/pm/permission/RuntimePermissionPresenter.java77
-rw-r--r--core/java/android/content/pm/split/DefaultSplitAssetLoader.java100
-rw-r--r--core/java/android/content/pm/split/SplitAssetDependencyLoader.java153
-rw-r--r--core/java/android/content/pm/split/SplitAssetLoader.java30
-rw-r--r--core/java/android/content/pm/split/SplitDependencyLoaderHelper.java149
-rw-r--r--core/java/android/content/res/AssetManager.java18
-rw-r--r--core/java/android/content/res/Configuration.java176
-rw-r--r--core/java/android/content/res/FontResourcesParser.java107
-rw-r--r--core/java/android/content/res/Resources.java13
-rw-r--r--core/java/android/content/res/ResourcesImpl.java28
-rw-r--r--core/java/android/content/res/TypedArray.java31
-rw-r--r--core/java/android/database/DatabaseUtils.java5
-rw-r--r--core/java/android/hardware/HardwareBuffer.java10
-rw-r--r--core/java/android/hardware/Sensor.java48
-rw-r--r--core/java/android/hardware/SensorDirectChannel.java168
-rw-r--r--core/java/android/hardware/SensorManager.java99
-rw-r--r--core/java/android/hardware/SystemSensorManager.java73
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java31
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java28
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java28
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java6
-rw-r--r--core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java4
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java14
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java6
-rw-r--r--core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java4
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java4
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java402
-rw-r--r--core/java/android/hardware/display/DisplayManager.java30
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java10
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java4
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl24
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl10
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/InputManager.java20
-rw-r--r--core/java/android/hardware/usb/UsbEndpoint.java4
-rw-r--r--core/java/android/hardware/usb/UsbPort.java69
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java14
-rw-r--r--core/java/android/metrics/LogMaker.java48
-rw-r--r--core/java/android/net/ConnectivityManager.java172
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/net/IpPrefix.aidl2
-rw-r--r--core/java/android/net/NetworkBadging.java152
-rw-r--r--core/java/android/net/NetworkKey.java25
-rw-r--r--core/java/android/net/NetworkRecommendationProvider.java68
-rw-r--r--core/java/android/net/NetworkRequest.java14
-rw-r--r--core/java/android/net/NetworkScorerAppManager.java58
-rw-r--r--core/java/android/net/RecommendationRequest.java4
-rw-r--r--core/java/android/net/Uri.java4
-rw-r--r--core/java/android/nfc/NdefRecord.java5
-rw-r--r--core/java/android/os/BatteryManager.java5
-rw-r--r--core/java/android/os/Build.java7
-rw-r--r--core/java/android/os/Debug.java4
-rw-r--r--core/java/android/os/Environment.java23
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/Parcel.java186
-rw-r--r--core/java/android/os/PowerManager.java9
-rw-r--r--core/java/android/os/RecoverySystem.java3
-rw-r--r--core/java/android/os/Seccomp.java (renamed from core/java/com/android/internal/logging/legacy/SysuiQueryParser.java)16
-rw-r--r--core/java/android/os/StrictMode.java52
-rw-r--r--core/java/android/os/UserManager.java30
-rw-r--r--core/java/android/os/ZygoteProcess.java10
-rw-r--r--core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java27
-rw-r--r--core/java/android/preference/Preference.java23
-rw-r--r--core/java/android/preference/PreferenceActivity.java222
-rw-r--r--core/java/android/preference/PreferenceGroup.java46
-rw-r--r--core/java/android/provider/ContactsContract.java32
-rw-r--r--core/java/android/provider/DocumentsProvider.java12
-rw-r--r--core/java/android/provider/OneTimeUseBuilder.java51
-rwxr-xr-xcore/java/android/provider/Settings.java160
-rw-r--r--core/java/android/provider/SettingsStringUtil.java174
-rw-r--r--core/java/android/provider/VoicemailContract.java12
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java8
-rw-r--r--core/java/android/security/net/config/ManifestConfigSource.java14
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfig.java5
-rw-r--r--core/java/android/security/net/config/XmlConfigSource.java10
-rw-r--r--core/java/android/service/autofill/AutoFillService.java180
-rw-r--r--core/java/android/service/autofill/AutoFillServiceInfo.java113
-rw-r--r--core/java/android/service/autofill/FillCallback.java90
-rw-r--r--core/java/android/service/autofill/IAutoFillAppCallback.aidl19
-rw-r--r--core/java/android/service/autofill/IAutoFillManagerService.aidl14
-rw-r--r--core/java/android/service/autofill/IAutoFillService.aidl11
-rw-r--r--core/java/android/service/autofill/IFillCallback.aidl (renamed from core/java/android/service/autofill/IAutoFillServerCallback.aidl)15
-rw-r--r--core/java/android/service/autofill/ISaveCallback.aidl27
-rw-r--r--core/java/android/service/autofill/SaveCallback.java60
-rw-r--r--core/java/android/service/gatekeeper/GateKeeperResponse.java48
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl2
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java32
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java120
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java2
-rw-r--r--core/java/android/service/quicksettings/TileService.java5
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java2
-rw-r--r--core/java/android/service/vr/IVrManager.aidl8
-rw-r--r--core/java/android/text/Editable.java4
-rw-r--r--core/java/android/text/FontConfig.java9
-rw-r--r--core/java/android/text/ITextClassificationService.aidl33
-rw-r--r--core/java/android/text/SpannableStringBuilder.java115
-rw-r--r--core/java/android/text/SpannableStringInternal.java47
-rw-r--r--core/java/android/text/TextUtils.java16
-rw-r--r--core/java/android/text/style/ClickableSpan.java2
-rw-r--r--core/java/android/text/style/ImageSpan.java2
-rw-r--r--core/java/android/text/style/TtsSpan.java16
-rw-r--r--core/java/android/transition/ChangeTransform.java9
-rw-r--r--core/java/android/transition/Transition.java28
-rw-r--r--core/java/android/transition/TransitionListenerAdapter.java61
-rw-r--r--core/java/android/transition/TransitionManager.java2
-rw-r--r--core/java/android/util/ByteStringUtils.java4
-rw-r--r--core/java/android/util/KeyValueListParser.java18
-rw-r--r--core/java/android/util/PackageUtils.java2
-rw-r--r--core/java/android/util/TimeUtils.java1
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java324
-rw-r--r--core/java/android/view/Display.java25
-rw-r--r--core/java/android/view/DisplayInfo.java14
-rw-r--r--core/java/android/view/FocusFinder.java132
-rw-r--r--core/java/android/view/FrameMetrics.java2
-rw-r--r--core/java/android/view/IDockedStackListener.aidl5
-rw-r--r--core/java/android/view/IPinnedStackController.aidl14
-rw-r--r--core/java/android/view/IPinnedStackListener.aidl27
-rw-r--r--core/java/android/view/IWindow.aidl5
-rw-r--r--core/java/android/view/IWindowManager.aidl13
-rw-r--r--core/java/android/view/InputDevice.java9
-rw-r--r--core/java/android/view/KeyCharacterMap.java4
-rw-r--r--core/java/android/view/NotificationHeaderView.java3
-rw-r--r--core/java/android/view/RenderNode.java19
-rw-r--r--core/java/android/view/SurfaceControl.java19
-rw-r--r--core/java/android/view/ThreadedRenderer.java9
-rw-r--r--core/java/android/view/View.java530
-rw-r--r--core/java/android/view/ViewGroup.java290
-rw-r--r--core/java/android/view/ViewOverlay.java18
-rw-r--r--core/java/android/view/ViewParent.java28
-rw-r--r--core/java/android/view/ViewRootImpl.java89
-rw-r--r--core/java/android/view/ViewStructure.java40
-rw-r--r--core/java/android/view/Window.java32
-rw-r--r--core/java/android/view/WindowCallbackWrapper.java5
-rw-r--r--core/java/android/view/WindowManager.java97
-rw-r--r--core/java/android/view/WindowManagerPolicy.java226
-rw-r--r--core/java/android/view/accessibility/AccessibilityCache.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java7
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java65
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java144
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeProvider.java21
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java4
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl3
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl10
-rw-r--r--core/java/android/view/animation/LayoutAnimationController.java2
-rw-r--r--core/java/android/view/autofill/AutoFillId.java8
-rw-r--r--core/java/android/view/autofill/AutoFillManager.java213
-rw-r--r--core/java/android/view/autofill/AutoFillSession.java166
-rw-r--r--core/java/android/view/autofill/AutoFillValue.java41
-rw-r--r--core/java/android/view/autofill/Dataset.java254
-rw-r--r--core/java/android/view/autofill/DatasetField.java86
-rw-r--r--core/java/android/view/autofill/FillResponse.java323
-rw-r--r--core/java/android/view/autofill/Helper.java16
-rw-r--r--core/java/android/view/autofill/VirtualViewDelegate.java78
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java24
-rw-r--r--core/java/android/view/textclassifier/TextClassificationManager.java37
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java311
-rw-r--r--core/java/android/view/textservice/SpellCheckerSession.java20
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java3
-rw-r--r--core/java/android/webkit/UserPackage.java10
-rw-r--r--core/java/android/webkit/WebViewClient.java3
-rw-r--r--core/java/android/webkit/WebViewFactory.java30
-rw-r--r--core/java/android/widget/AbsListView.java8
-rw-r--r--core/java/android/widget/CompoundButton.java11
-rw-r--r--core/java/android/widget/EditText.java25
-rw-r--r--core/java/android/widget/Editor.java273
-rw-r--r--core/java/android/widget/ListView.java32
-rw-r--r--core/java/android/widget/PopupWindow.java26
-rw-r--r--core/java/android/widget/ProgressBar.java12
-rw-r--r--core/java/android/widget/RadioGroup.java11
-rw-r--r--core/java/android/widget/RatingBar.java6
-rw-r--r--core/java/android/widget/RelativeLayout.java3
-rw-r--r--core/java/android/widget/RemoteViews.java4
-rw-r--r--core/java/android/widget/SearchView.java6
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java288
-rw-r--r--core/java/android/widget/TextInputTimePickerView.java249
-rw-r--r--core/java/android/widget/TextView.java387
-rw-r--r--core/java/android/widget/TimePicker.java12
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java133
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java5
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java113
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java4
-rw-r--r--core/java/com/android/internal/app/procstats/PssTable.java2
-rw-r--r--core/java/com/android/internal/appwidget/IAppWidgetService.aidl1
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java54
-rw-r--r--core/java/com/android/internal/logging/legacy/CounterParser.java54
-rw-r--r--core/java/com/android/internal/logging/legacy/EventLogCollector.java15
-rw-r--r--core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java8
-rw-r--r--core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java80
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java72
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationAlertParser.java86
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java102
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationClickedParser.java70
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java76
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationKey.java60
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java42
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java56
-rw-r--r--core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java81
-rw-r--r--core/java/com/android/internal/logging/legacy/StatusBarStateParser.java74
-rw-r--r--core/java/com/android/internal/logging/legacy/SysuiActionParser.java81
-rw-r--r--core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java58
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java18
-rw-r--r--core/java/com/android/internal/os/Zygote.java6
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java17
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java4
-rw-r--r--core/java/com/android/internal/policy/DecorView.java8
-rw-r--r--core/java/com/android/internal/policy/DividerSnapAlgorithm.java28
-rw-r--r--core/java/com/android/internal/policy/PhoneFallbackEventHandler.java6
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java41
-rw-r--r--core/java/com/android/internal/policy/PipMotionHelper.java91
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java53
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl3
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java14
-rw-r--r--core/java/com/android/internal/util/MessageUtils.java6
-rw-r--r--core/java/com/android/internal/util/NotificationColorUtil.java64
-rw-r--r--core/java/com/android/internal/util/NotificationMessagingUtil.java93
-rw-r--r--core/java/com/android/internal/util/ObjectUtils.java31
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/java/com/android/internal/view/InputMethodClient.java5
-rw-r--r--core/java/com/android/internal/widget/DrawingSpace.java76
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java4
-rw-r--r--core/jni/Android.mk3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/FontFamily.cpp111
-rw-r--r--core/jni/android/graphics/FontUtils.h54
-rw-r--r--core/jni/android/graphics/Typeface.cpp21
-rw-r--r--core/jni/android_hardware_HardwareBuffer.cpp94
-rw-r--r--core/jni/android_hardware_Radio.cpp5
-rw-r--r--core/jni/android_hardware_SensorManager.cpp63
-rw-r--r--core/jni/android_hardware_SoundTrigger.cpp2
-rw-r--r--core/jni/android_media_AudioTrack.cpp13
-rw-r--r--core/jni/android_os_HwBinder.cpp34
-rw-r--r--core/jni/android_os_HwBlob.cpp2
-rw-r--r--core/jni/android_os_seccomp.cpp249
-rw-r--r--core/jni/android_util_AssetManager.cpp5
-rw-r--r--core/jni/android_view_RenderNode.cpp77
-rw-r--r--core/jni/android_view_Surface.cpp2
-rw-r--r--core/jni/android_view_SurfaceControl.cpp23
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp37
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp33
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp2
-rw-r--r--core/jni/include/android_runtime/android_hardware_HardwareBuffer.h7
-rw-r--r--core/proto/android/os/incident.proto4
-rw-r--r--core/proto/android/service/appwidget.proto40
-rw-r--r--core/proto/android/service/battery.proto76
-rw-r--r--core/proto/android/service/netstats.proto4
-rw-r--r--core/proto/android/service/notification.proto45
-rw-r--r--core/res/AndroidManifest.xml59
-rw-r--r--core/res/res/color/text_color_secondary.xml23
-rw-r--r--core/res/res/drawable-nodpi/platlogo.xml31
-rw-r--r--core/res/res/drawable-nodpi/stat_sys_adb.xml26
-rw-r--r--core/res/res/drawable/btn_event_material.xml29
-rw-r--r--core/res/res/drawable/btn_keyboard_key_material.xml32
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_0_bars.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_1_bar.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_2_bars.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_3_bars.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_4_bars.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_4k.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_hd.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_ld.xml6
-rw-r--r--core/res/res/drawable/ic_signal_wifi_badged_sd.xml6
-rw-r--r--core/res/res/drawable/ic_wifi_signal_0.xml26
-rw-r--r--core/res/res/drawable/ic_wifi_signal_1.xml29
-rw-r--r--core/res/res/drawable/ic_wifi_signal_2.xml29
-rw-r--r--core/res/res/drawable/ic_wifi_signal_3.xml29
-rw-r--r--core/res/res/drawable/ic_wifi_signal_4.xml25
-rw-r--r--core/res/res/drawable/resolver_icon_placeholder.xml19
-rw-r--r--core/res/res/layout-land/time_picker_material.xml126
-rw-r--r--core/res/res/layout/autofill_save.xml57
-rw-r--r--core/res/res/layout/chooser_grid.xml3
-rw-r--r--core/res/res/layout/notification_template_header.xml5
-rw-r--r--core/res/res/layout/notification_template_material_ambient.xml7
-rw-r--r--core/res/res/layout/preference_list_content.xml4
-rw-r--r--core/res/res/layout/preference_list_content_material.xml4
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml1
-rw-r--r--core/res/res/layout/search_view.xml3
-rw-r--r--core/res/res/layout/time_picker_material.xml49
-rw-r--r--core/res/res/layout/time_picker_text_input_material.xml90
-rw-r--r--core/res/res/raw/accessibility_gestures.binbin8765 -> 0 bytes
-rw-r--r--core/res/res/values-af-watch/styles_material.xml35
-rw-r--r--core/res/res/values-af/strings.xml46
-rw-r--r--core/res/res/values-am-watch/styles_material.xml35
-rw-r--r--core/res/res/values-am/strings.xml46
-rw-r--r--core/res/res/values-ar-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ar/strings.xml46
-rw-r--r--core/res/res/values-az-watch/styles_material.xml35
-rw-r--r--core/res/res/values-az/strings.xml46
-rw-r--r--core/res/res/values-b+sr+Latn-watch/styles_material.xml35
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml46
-rw-r--r--core/res/res/values-be-watch/styles_material.xml35
-rw-r--r--core/res/res/values-be/strings.xml46
-rw-r--r--core/res/res/values-bg-watch/styles_material.xml35
-rw-r--r--core/res/res/values-bg/strings.xml48
-rw-r--r--core/res/res/values-bn-watch/styles_material.xml35
-rw-r--r--core/res/res/values-bn/strings.xml73
-rw-r--r--core/res/res/values-bs-watch/styles_material.xml35
-rw-r--r--core/res/res/values-bs/strings.xml47
-rw-r--r--core/res/res/values-ca-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ca/strings.xml48
-rw-r--r--core/res/res/values-cs-watch/styles_material.xml35
-rw-r--r--core/res/res/values-cs/strings.xml48
-rw-r--r--core/res/res/values-da-watch/styles_material.xml35
-rw-r--r--core/res/res/values-da/strings.xml48
-rw-r--r--core/res/res/values-de-watch/styles_material.xml35
-rw-r--r--core/res/res/values-de/strings.xml46
-rw-r--r--core/res/res/values-el-watch/styles_material.xml35
-rw-r--r--core/res/res/values-el/strings.xml48
-rw-r--r--core/res/res/values-en-rAU-watch/styles_material.xml35
-rw-r--r--core/res/res/values-en-rAU/strings.xml46
-rw-r--r--core/res/res/values-en-rGB-watch/styles_material.xml35
-rw-r--r--core/res/res/values-en-rGB/strings.xml46
-rw-r--r--core/res/res/values-en-rIN-watch/styles_material.xml35
-rw-r--r--core/res/res/values-en-rIN/strings.xml46
-rw-r--r--core/res/res/values-es-rUS-watch/styles_material.xml35
-rw-r--r--core/res/res/values-es-rUS/strings.xml46
-rw-r--r--core/res/res/values-es-watch/styles_material.xml35
-rw-r--r--core/res/res/values-es/strings.xml46
-rw-r--r--core/res/res/values-et-watch/styles_material.xml35
-rw-r--r--core/res/res/values-et/strings.xml46
-rw-r--r--core/res/res/values-eu-watch/styles_material.xml35
-rw-r--r--core/res/res/values-eu/strings.xml51
-rw-r--r--core/res/res/values-fa-watch/styles_material.xml35
-rw-r--r--core/res/res/values-fa/strings.xml46
-rw-r--r--core/res/res/values-fi-watch/styles_material.xml35
-rw-r--r--core/res/res/values-fi/strings.xml48
-rw-r--r--core/res/res/values-fr-rCA-watch/styles_material.xml35
-rw-r--r--core/res/res/values-fr-rCA/strings.xml46
-rw-r--r--core/res/res/values-fr-watch/styles_material.xml35
-rw-r--r--core/res/res/values-fr/strings.xml46
-rw-r--r--core/res/res/values-gl-watch/styles_material.xml35
-rw-r--r--core/res/res/values-gl/strings.xml47
-rw-r--r--core/res/res/values-gu-watch/styles_material.xml35
-rw-r--r--core/res/res/values-gu/strings.xml47
-rw-r--r--core/res/res/values-hi-watch/styles_material.xml35
-rw-r--r--core/res/res/values-hi/strings.xml64
-rw-r--r--core/res/res/values-hr-watch/styles_material.xml35
-rw-r--r--core/res/res/values-hr/strings.xml46
-rw-r--r--core/res/res/values-hu-watch/styles_material.xml35
-rw-r--r--core/res/res/values-hu/strings.xml46
-rw-r--r--core/res/res/values-hy-watch/styles_material.xml35
-rw-r--r--core/res/res/values-hy/strings.xml46
-rw-r--r--core/res/res/values-in-watch/styles_material.xml35
-rw-r--r--core/res/res/values-in/strings.xml48
-rw-r--r--core/res/res/values-is-watch/styles_material.xml35
-rw-r--r--core/res/res/values-is/strings.xml47
-rw-r--r--core/res/res/values-it-watch/styles_material.xml35
-rw-r--r--core/res/res/values-it/strings.xml48
-rw-r--r--core/res/res/values-iw-watch/styles_material.xml35
-rw-r--r--core/res/res/values-iw/strings.xml46
-rw-r--r--core/res/res/values-ja-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ja/strings.xml46
-rw-r--r--core/res/res/values-ka-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ka/strings.xml46
-rw-r--r--core/res/res/values-kk-watch/styles_material.xml35
-rw-r--r--core/res/res/values-kk/strings.xml47
-rw-r--r--core/res/res/values-km-watch/styles_material.xml35
-rw-r--r--core/res/res/values-km/strings.xml46
-rw-r--r--core/res/res/values-kn-watch/styles_material.xml35
-rw-r--r--core/res/res/values-kn/strings.xml47
-rw-r--r--core/res/res/values-ko-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ko/strings.xml48
-rw-r--r--core/res/res/values-ky-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ky/strings.xml47
-rw-r--r--core/res/res/values-lo-watch/styles_material.xml35
-rw-r--r--core/res/res/values-lo/strings.xml46
-rw-r--r--core/res/res/values-lt-watch/styles_material.xml35
-rw-r--r--core/res/res/values-lt/strings.xml46
-rw-r--r--core/res/res/values-lv-watch/styles_material.xml35
-rw-r--r--core/res/res/values-lv/strings.xml46
-rw-r--r--core/res/res/values-mcc208-mnc10/config.xml24
-rw-r--r--core/res/res/values-mcc334-mnc050/config.xml4
-rw-r--r--core/res/res/values-mcc334-mnc090/config.xml28
-rw-r--r--core/res/res/values-mcc704-mnc01/config.xml27
-rwxr-xr-xcore/res/res/values-mcc708-mnc001/config.xml27
-rw-r--r--core/res/res/values-mk-watch/styles_material.xml35
-rw-r--r--core/res/res/values-mk/strings.xml47
-rw-r--r--core/res/res/values-ml-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ml/strings.xml51
-rw-r--r--core/res/res/values-mn-watch/styles_material.xml35
-rw-r--r--core/res/res/values-mn/strings.xml48
-rw-r--r--core/res/res/values-mr-watch/styles_material.xml35
-rw-r--r--core/res/res/values-mr/strings.xml67
-rw-r--r--core/res/res/values-ms-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ms/strings.xml46
-rw-r--r--core/res/res/values-my-watch/styles_material.xml35
-rw-r--r--core/res/res/values-my/strings.xml47
-rw-r--r--core/res/res/values-nb-watch/styles_material.xml35
-rw-r--r--core/res/res/values-nb/strings.xml48
-rw-r--r--core/res/res/values-ne-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ne/strings.xml46
-rw-r--r--core/res/res/values-nl-watch/styles_material.xml35
-rw-r--r--core/res/res/values-nl/strings.xml46
-rw-r--r--core/res/res/values-pa-watch/styles_material.xml35
-rw-r--r--core/res/res/values-pa/strings.xml47
-rw-r--r--core/res/res/values-pl-watch/styles_material.xml35
-rw-r--r--core/res/res/values-pl/strings.xml48
-rw-r--r--core/res/res/values-pt-rBR-watch/styles_material.xml35
-rw-r--r--core/res/res/values-pt-rBR/strings.xml46
-rw-r--r--core/res/res/values-pt-rPT-watch/styles_material.xml35
-rw-r--r--core/res/res/values-pt-rPT/strings.xml46
-rw-r--r--core/res/res/values-pt-watch/styles_material.xml35
-rw-r--r--core/res/res/values-pt/strings.xml46
-rw-r--r--core/res/res/values-ro-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ro/strings.xml48
-rw-r--r--core/res/res/values-ru-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ru/strings.xml46
-rw-r--r--core/res/res/values-si-watch/styles_material.xml35
-rw-r--r--core/res/res/values-si/strings.xml46
-rw-r--r--core/res/res/values-sk-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sk/strings.xml46
-rw-r--r--core/res/res/values-sl-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sl/strings.xml48
-rw-r--r--core/res/res/values-sq-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sq/strings.xml47
-rw-r--r--core/res/res/values-sr-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sr/strings.xml46
-rw-r--r--core/res/res/values-sv-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sv/strings.xml48
-rw-r--r--core/res/res/values-sw-watch/styles_material.xml35
-rw-r--r--core/res/res/values-sw/strings.xml48
-rw-r--r--core/res/res/values-ta-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ta/strings.xml47
-rw-r--r--core/res/res/values-te-watch/styles_material.xml35
-rw-r--r--core/res/res/values-te/strings.xml47
-rw-r--r--core/res/res/values-th-watch/styles_material.xml35
-rw-r--r--core/res/res/values-th/strings.xml48
-rw-r--r--core/res/res/values-tl-watch/styles_material.xml35
-rw-r--r--core/res/res/values-tl/strings.xml46
-rw-r--r--core/res/res/values-tr-watch/styles_material.xml35
-rw-r--r--core/res/res/values-tr/strings.xml48
-rw-r--r--core/res/res/values-uk-watch/styles_material.xml35
-rw-r--r--core/res/res/values-uk/strings.xml48
-rw-r--r--core/res/res/values-ur-watch/styles_material.xml35
-rw-r--r--core/res/res/values-ur/strings.xml47
-rw-r--r--core/res/res/values-uz-watch/styles_material.xml35
-rw-r--r--core/res/res/values-uz/strings.xml47
-rw-r--r--core/res/res/values-vi-watch/styles_material.xml35
-rw-r--r--core/res/res/values-vi/strings.xml46
-rw-r--r--core/res/res/values-zh-rCN-watch/styles_material.xml35
-rw-r--r--core/res/res/values-zh-rCN/strings.xml46
-rw-r--r--core/res/res/values-zh-rHK-watch/styles_material.xml35
-rw-r--r--core/res/res/values-zh-rHK/strings.xml46
-rw-r--r--core/res/res/values-zh-rTW-watch/styles_material.xml35
-rw-r--r--core/res/res/values-zh-rTW/strings.xml46
-rw-r--r--core/res/res/values-zu-watch/styles_material.xml35
-rw-r--r--core/res/res/values-zu/strings.xml46
-rw-r--r--core/res/res/values/attrs.xml47
-rw-r--r--core/res/res/values/attrs_manifest.xml63
-rw-r--r--core/res/res/values/colors.xml6
-rw-r--r--core/res/res/values/colors_material.xml2
-rw-r--r--core/res/res/values/config.xml25
-rw-r--r--core/res/res/values/dimens.xml13
-rw-r--r--core/res/res/values/dimens_material.xml1
-rw-r--r--core/res/res/values/public.xml7
-rw-r--r--core/res/res/values/strings.xml30
-rw-r--r--core/res/res/values/styles_material.xml21
-rw-r--r--core/res/res/values/symbols.xml61
-rw-r--r--core/res/res/values/themes_material.xml10
-rw-r--r--core/tests/coretests/res/font/samplefont.ttfbin0 -> 133372 bytes
-rw-r--r--core/tests/coretests/res/font/samplefont2.ttfbin0 -> 133372 bytes
-rw-r--r--core/tests/coretests/res/font/samplefont3.ttfbin0 -> 133372 bytes
-rw-r--r--core/tests/coretests/res/font/samplefont4.ttfbin0 -> 133372 bytes
-rw-r--r--core/tests/coretests/res/font/samplexmlfont.xml7
-rw-r--r--core/tests/coretests/src/android/content/res/FontResourcesParserTest.java81
-rw-r--r--core/tests/coretests/src/android/metrics/LogMakerTest.java82
-rw-r--r--core/tests/coretests/src/android/net/NetworkKeyTest.java75
-rw-r--r--core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java48
-rw-r--r--core/tests/coretests/src/android/net/RecommendationRequestTest.java2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsTest.java550
-rw-r--r--core/tests/coretests/src/android/transition/FadeTransitionTest.java2
-rw-r--r--core/tests/coretests/src/android/view/ViewAttachTest.java42
-rw-r--r--core/tests/coretests/src/android/view/ViewInvalidateTest.java24
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java110
-rw-r--r--core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java63
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java91
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java90
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java100
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java123
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java135
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java198
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java114
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java175
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java65
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java56
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java84
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java92
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java73
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java167
-rw-r--r--core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java122
-rw-r--r--data/etc/framework-sysconfig.xml1
-rw-r--r--data/etc/platform.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--data/keyboards/qwerty.kl6
-rw-r--r--docs/html/about/versions/android-4.0.jd2
-rw-r--r--graphics/java/android/graphics/FontFamily.java66
-rw-r--r--graphics/java/android/graphics/FontListParser.java10
-rw-r--r--graphics/java/android/graphics/Outline.java2
-rw-r--r--graphics/java/android/graphics/Paint.java32
-rw-r--r--graphics/java/android/graphics/RectF.java13
-rw-r--r--graphics/java/android/graphics/Typeface.java140
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/DrawableInflater.java2
-rw-r--r--graphics/java/android/graphics/drawable/MaskableIconDrawable.java1007
-rw-r--r--graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java115
-rw-r--r--keystore/java/android/security/GateKeeper.java2
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java6
-rw-r--r--keystore/java/android/security/keystore/AttestationUtils.java228
-rw-r--r--keystore/java/android/security/keystore/DeviceIdAttestationException.java45
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java48
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java25
-rw-r--r--libs/androidfw/Android.bp4
-rw-r--r--libs/androidfw/ApkAssets.cpp20
-rw-r--r--libs/androidfw/AssetManager.cpp38
-rw-r--r--libs/androidfw/AssetManager2.cpp315
-rw-r--r--libs/androidfw/ChunkIterator.cpp2
-rw-r--r--libs/androidfw/LoadedArsc.cpp220
-rw-r--r--libs/androidfw/ResourceTypes.cpp58
-rw-r--r--libs/androidfw/Util.cpp45
-rw-r--r--libs/androidfw/include/androidfw/ApkAssets.h9
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h79
-rw-r--r--libs/androidfw/include/androidfw/Chunk.h (renamed from libs/androidfw/Chunk.h)0
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h138
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h30
-rw-r--r--libs/androidfw/include/androidfw/Util.h12
-rw-r--r--libs/androidfw/tests/ApkAssets_test.cpp22
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp175
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp256
-rw-r--r--libs/androidfw/tests/Config_test.cpp8
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp120
-rw-r--r--libs/androidfw/tests/ResTable_test.cpp6
-rw-r--r--libs/androidfw/tests/Theme_bench.cpp4
-rw-r--r--libs/androidfw/tests/Theme_test.cpp48
-rw-r--r--libs/androidfw/tests/data/basic/R.h2
-rw-r--r--libs/androidfw/tests/data/basic/basic.apkbin2959 -> 3055 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_de_fr.apkbin1516 -> 1524 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_hdpi-v4.apkbin1298 -> 1306 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_xhdpi-v4.apkbin1304 -> 1312 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apkbin1302 -> 1310 bytes
-rw-r--r--libs/androidfw/tests/data/basic/res/values/values.xml6
-rw-r--r--libs/androidfw/tests/data/feature/feature.apkbin1373 -> 1373 bytes
-rw-r--r--libs/androidfw/tests/data/lib/lib.apkbin1221 -> 0 bytes
-rw-r--r--libs/androidfw/tests/data/lib_one/AndroidManifest.xml (renamed from libs/androidfw/tests/data/lib/AndroidManifest.xml)2
-rw-r--r--libs/androidfw/tests/data/lib_one/R.h (renamed from libs/androidfw/tests/data/lib/R.h)16
-rwxr-xr-xlibs/androidfw/tests/data/lib_one/build (renamed from libs/androidfw/tests/data/lib/build)2
-rw-r--r--libs/androidfw/tests/data/lib_one/lib_one.apkbin0 -> 1414 bytes
-rw-r--r--libs/androidfw/tests/data/lib_one/res/values/values.xml32
-rw-r--r--libs/androidfw/tests/data/lib_two/AndroidManifest.xml (renamed from core/res/res/values-ldrtl/dimens.xml)9
-rw-r--r--libs/androidfw/tests/data/lib_two/R.h39
-rwxr-xr-xlibs/androidfw/tests/data/lib_two/build20
-rw-r--r--libs/androidfw/tests/data/lib_two/lib_two.apkbin0 -> 1106 bytes
-rw-r--r--libs/androidfw/tests/data/lib_two/res/values/values.xml (renamed from libs/androidfw/tests/data/lib/res/values/values.xml)10
-rw-r--r--libs/androidfw/tests/data/libclient/AndroidManifest.xml19
-rw-r--r--libs/androidfw/tests/data/libclient/R.h52
-rwxr-xr-xlibs/androidfw/tests/data/libclient/build30
-rw-r--r--libs/androidfw/tests/data/libclient/libclient.apkbin0 -> 1982 bytes
-rw-r--r--libs/androidfw/tests/data/libclient/res/values/values.xml35
-rw-r--r--libs/hwui/Android.mk5
-rw-r--r--libs/hwui/BakedOpDispatcher.cpp13
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp40
-rw-r--r--libs/hwui/DeferredLayerUpdater.h31
-rw-r--r--libs/hwui/DisplayList.cpp6
-rw-r--r--libs/hwui/DisplayList.h4
-rw-r--r--libs/hwui/FrameBuilder.cpp8
-rw-r--r--libs/hwui/GlLayer.cpp6
-rw-r--r--libs/hwui/GlLayer.h3
-rw-r--r--libs/hwui/GlopBuilder.cpp1
-rw-r--r--libs/hwui/GradientCache.cpp4
-rw-r--r--libs/hwui/Layer.cpp8
-rw-r--r--libs/hwui/Layer.h9
-rw-r--r--libs/hwui/Program.h6
-rw-r--r--libs/hwui/ProgramCache.cpp193
-rw-r--r--libs/hwui/RecordedOp.h10
-rw-r--r--libs/hwui/RecordingCanvas.cpp5
-rw-r--r--libs/hwui/RenderNode.cpp92
-rw-r--r--libs/hwui/RenderNode.h57
-rw-r--r--libs/hwui/SkiaCanvas.cpp2
-rw-r--r--libs/hwui/Texture.cpp6
-rw-r--r--libs/hwui/Texture.h5
-rw-r--r--libs/hwui/TextureCache.cpp49
-rw-r--r--libs/hwui/TextureCache.h2
-rw-r--r--libs/hwui/TreeInfo.h8
-rw-r--r--libs/hwui/VkLayer.h8
-rw-r--r--libs/hwui/debug/nullegl.cpp13
-rw-r--r--libs/hwui/hwui/Bitmap.cpp24
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp25
-rw-r--r--libs/hwui/hwui/MinikinSkia.h2
-rw-r--r--libs/hwui/hwui/Typeface.cpp28
-rw-r--r--libs/hwui/hwui/Typeface.h3
-rw-r--r--libs/hwui/hwui_static_deps.mk2
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp3
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.h8
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp524
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp7
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp12
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp8
-rw-r--r--libs/hwui/renderstate/RenderState.cpp10
-rw-r--r--libs/hwui/renderstate/RenderState.h11
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp42
-rw-r--r--libs/hwui/renderthread/CanvasContext.h19
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp4
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h3
-rw-r--r--libs/hwui/renderthread/OpenGLPipeline.cpp13
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp25
-rw-r--r--libs/hwui/renderthread/RenderProxy.h9
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp5
-rw-r--r--libs/hwui/tests/common/TestContext.cpp7
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.cpp2
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp5
-rw-r--r--libs/hwui/tests/common/TestUtils.h21
-rw-r--r--libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp72
-rw-r--r--libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp83
-rw-r--r--libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp65
-rw-r--r--libs/hwui/tests/macrobench/TestSceneRunner.cpp4
-rw-r--r--libs/hwui/tests/unit/CanvasContextTests.cpp2
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp8
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp4
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp176
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp14
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp4
-rw-r--r--libs/hwui/tests/unit/TextureCacheTests.cpp39
-rw-r--r--libs/hwui/utils/Color.h8
-rw-r--r--libs/hwui/utils/TestWindowContext.cpp4
-rw-r--r--location/java/android/location/BatchedLocationCallback.java44
-rw-r--r--location/java/android/location/BatchedLocationCallbackTransport.java66
-rw-r--r--location/java/android/location/GnssNavigationMessage.java2
-rw-r--r--location/java/android/location/IBatchedLocationCallback.aidl29
-rw-r--r--location/java/android/location/ILocationManager.aidl11
-rw-r--r--location/java/android/location/LocationManager.java104
-rw-r--r--media/java/android/media/AudioAttributes.java37
-rw-r--r--media/java/android/media/AudioFocusInfo.java20
-rw-r--r--media/java/android/media/AudioManager.java82
-rw-r--r--media/java/android/media/AudioTrack.java218
-rw-r--r--media/java/android/media/BufferingParams.aidl19
-rw-r--r--media/java/android/media/BufferingParams.java459
-rw-r--r--media/java/android/media/ExifInterface.java12
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/IPlayer.aidl2
-rw-r--r--media/java/android/media/MediaCodec.java9
-rw-r--r--media/java/android/media/MediaDrm.java6
-rw-r--r--media/java/android/media/MediaMuxer.java41
-rw-r--r--media/java/android/media/MediaPlayer.java1125
-rw-r--r--media/java/android/media/MediaRecorder.java20
-rw-r--r--media/java/android/media/MediaSyncEvent.java2
-rw-r--r--media/java/android/media/PlayerBase.java103
-rw-r--r--media/java/android/media/PlayerProxy.java42
-rw-r--r--media/java/android/media/audiopolicy/AudioMixingRule.java6
-rw-r--r--media/java/android/media/session/IOnMediaKeyListener.aidl28
-rw-r--r--media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl27
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl5
-rw-r--r--media/java/android/media/session/ISessionController.aidl6
-rw-r--r--media/java/android/media/session/ISessionManager.aidl9
-rw-r--r--media/java/android/media/session/MediaController.java176
-rw-r--r--media/java/android/media/session/MediaSession.java130
-rw-r--r--media/java/android/media/session/MediaSessionLegacyHelper.java46
-rw-r--r--media/java/android/media/session/MediaSessionManager.java181
-rw-r--r--media/java/android/media/tv/TvContract.java1322
-rw-r--r--media/java/android/media/tv/TvInputManager.java18
-rw-r--r--media/jni/Android.mk1
-rw-r--r--media/jni/android_media_BufferingParams.h111
-rw-r--r--media/jni/android_media_MediaCodec.cpp41
-rw-r--r--media/jni/android_media_MediaCodec.h2
-rw-r--r--media/jni/android_media_MediaDrm.cpp23
-rw-r--r--media/jni/android_media_MediaDrm.h4
-rw-r--r--media/jni/android_media_MediaMetricsJNI.cpp93
-rw-r--r--media/jni/android_media_MediaMetricsJNI.h34
-rw-r--r--media/jni/android_media_MediaMuxer.cpp25
-rw-r--r--media/jni/android_media_MediaPlayer.cpp674
-rw-r--r--media/mca/effect/java/android/media/effect/package.html2
-rw-r--r--native/android/Android.mk21
-rw-r--r--native/android/hardware_buffer.cpp35
-rw-r--r--opengl/java/android/opengl/GLU.java4
-rw-r--r--packages/CarrierDefaultApp/res/values-af/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-am/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ar/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-az/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-be/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-bg/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-bn/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-bs/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ca/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-cs/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-da/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-de/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-el/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-en-rAU/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-en-rGB/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-en-rIN/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-es-rUS/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-es/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-et/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-eu/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-fa/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-fi/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-fr/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-gl/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-gu/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-hi/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-hr/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-hu/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-hy/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-in/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-is/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-it/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-iw/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ja/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ka/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-kk/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-km/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-kn/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ko/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ky/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-lo/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-lt/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-lv/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-mk/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ml/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-mn/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-mr/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ms/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-my/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-nb/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ne/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-nl/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-pa/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-pl/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-pt/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ro/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ru/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-si/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sk/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sl/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sq/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sr/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sv/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-sw/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ta/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-te/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-th/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-tl/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-tr/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-uk/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-ur/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-uz/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-vi/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml14
-rw-r--r--packages/CarrierDefaultApp/res/values-zu/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/Android.mk27
-rw-r--r--packages/CompanionDeviceManager/AndroidManifest.xml55
-rw-r--r--packages/CompanionDeviceManager/MODULE_LICENSE_APACHE20
-rw-r--r--packages/CompanionDeviceManager/NOTICE190
-rw-r--r--packages/CompanionDeviceManager/res/layout/device_chooser.xml67
-rw-r--r--packages/CompanionDeviceManager/res/values/dimens.xml7
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml25
-rw-r--r--packages/CompanionDeviceManager/res/values/themes.xml25
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java133
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java273
-rw-r--r--packages/Keyguard/res/values-bn/strings.xml16
-rw-r--r--packages/Keyguard/res/values-da/strings.xml6
-rw-r--r--packages/MtpDocumentsProvider/res/values-ml/strings.xml2
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java4
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java75
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java19
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java4
-rw-r--r--packages/SettingsLib/res/color/batterymeter_bolt_color.xml18
-rw-r--r--packages/SettingsLib/res/color/batterymeter_charge_color.xml18
-rw-r--r--packages/SettingsLib/res/color/batterymeter_frame_color.xml18
-rw-r--r--packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml18
-rw-r--r--packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml18
-rw-r--r--packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml18
-rw-r--r--packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml18
-rw-r--r--packages/SettingsLib/res/values-af/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-am/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ar/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-az/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-be/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-bg/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-bn/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml28
-rw-r--r--packages/SettingsLib/res/values-bs/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ca/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-cs/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-da/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml26
-rw-r--r--packages/SettingsLib/res/values-de/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-el/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rAU/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rGB/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rIN/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-es-rUS/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-es/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-et/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-eu/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-fa/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-fi/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-fr/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-gl/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-gu/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-hi/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-hr/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-hu/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-hy/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml30
-rw-r--r--packages/SettingsLib/res/values-is/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-it/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-iw/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ja/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ka/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-kk/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-km/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-kn/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ko/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ky/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-lo/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-lt/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-lv/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-mk/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ml/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-mn/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-mr/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ms/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-my/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-nb/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ne/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-nl/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-pa/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-pl/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-pt/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ro/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ru/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-si/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sk/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sl/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sq/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sr/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sv/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-sw/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ta/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-te/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-th/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-tl/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-tr/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-uk/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-ur/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-uz/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-vi/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml24
-rw-r--r--packages/SettingsLib/res/values-zu/arrays.xml78
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml24
-rw-r--r--packages/SettingsLib/res/values/arrays.xml60
-rw-r--r--packages/SettingsLib/res/values/dimens.xml11
-rw-r--r--packages/SettingsLib/res/values/strings.xml10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/HelpUtils.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java192
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TronUtils.java63
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java235
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java32
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java1
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java468
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java66
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java63
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java36
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java36
-rw-r--r--packages/SettingsLib/tests/integ/Android.mk3
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java89
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java51
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java74
-rw-r--r--packages/SettingsLib/tests/robotests/Android.mk6
-rw-r--r--packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml27
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java48
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java132
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java49
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java5
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java179
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java32
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java21
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java11
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java146
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java16
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java31
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java90
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java2
-rw-r--r--packages/SystemUI/proguard.flags4
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.pngbin0 -> 232 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.pngbin0 -> 234 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.pngbin0 -> 166 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.pngbin0 -> 165 bytes
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon.xml28
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.pngbin0 -> 282 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.pngbin0 -> 283 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.pngbin0 -> 383 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.pngbin0 -> 384 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.pngbin0 -> 498 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.pngbin0 -> 504 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_left.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_menu.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_data_disabled.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_signal_r.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_remove.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_right.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_snooze.xml12
-rw-r--r--packages/SystemUI/res/drawable/pip_dismiss_background.xml30
-rw-r--r--packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_data_disabled.xml5
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_roaming.xml (renamed from packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml)4
-rw-r--r--packages/SystemUI/res/layout-land/nav_bar_tuner.xml56
-rw-r--r--packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml57
-rw-r--r--packages/SystemUI/res/layout/data_usage.xml12
-rw-r--r--packages/SystemUI/res/layout/divider.xml20
-rw-r--r--packages/SystemUI/res/layout/menu_ime.xml9
-rw-r--r--packages/SystemUI/res/layout/mobile_signal_group.xml11
-rw-r--r--packages/SystemUI/res/layout/nav_bar_tuner.xml57
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml123
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml146
-rw-r--r--packages/SystemUI/res/layout/notification_menu_row.xml (renamed from packages/SystemUI/res/layout/notification_settings_icon_row.xml)20
-rw-r--r--packages/SystemUI/res/layout/notification_snooze.xml65
-rw-r--r--packages/SystemUI/res/layout/pip_dismiss_view.xml47
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml28
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml27
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_row.xml8
-rw-r--r--packages/SystemUI/res/layout/super_status_bar.xml3
-rw-r--r--packages/SystemUI/res/layout/tuner_shortcut_item.xml47
-rw-r--r--packages/SystemUI/res/layout/tuner_shortcut_list.xml22
-rw-r--r--packages/SystemUI/res/values-af/strings.xml86
-rw-r--r--packages/SystemUI/res/values-am/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml86
-rw-r--r--packages/SystemUI/res/values-az/strings.xml86
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml86
-rw-r--r--packages/SystemUI/res/values-be/strings.xml86
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml86
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml88
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml88
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml86
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml86
-rw-r--r--packages/SystemUI/res/values-da/strings.xml86
-rw-r--r--packages/SystemUI/res/values-de/strings.xml86
-rw-r--r--packages/SystemUI/res/values-el/strings.xml86
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml86
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml86
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml86
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml86
-rw-r--r--packages/SystemUI/res/values-es/strings.xml94
-rw-r--r--packages/SystemUI/res/values-et/strings.xml86
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml86
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml86
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml86
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml87
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml86
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml86
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml86
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml86
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml86
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml86
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml86
-rw-r--r--packages/SystemUI/res/values-in/strings.xml86
-rw-r--r--packages/SystemUI/res/values-is/strings.xml86
-rw-r--r--packages/SystemUI/res/values-it/strings.xml86
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml86
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml86
-rw-r--r--packages/SystemUI/res/values-km/strings.xml86
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml86
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml86
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml86
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml86
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml95
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml86
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml87
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml86
-rw-r--r--packages/SystemUI/res/values-my/strings.xml86
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml87
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml86
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml86
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml86
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml86
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml86
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml86
-rw-r--r--packages/SystemUI/res/values-si/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml86
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml96
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml2
-rw-r--r--packages/SystemUI/res/values-sw900dp/config.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml86
-rw-r--r--packages/SystemUI/res/values-te/strings.xml86
-rw-r--r--packages/SystemUI/res/values-th/strings.xml86
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml86
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml86
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml86
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml87
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml86
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml86
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml87
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml86
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml86
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml86
-rw-r--r--packages/SystemUI/res/values/arrays.xml54
-rw-r--r--packages/SystemUI/res/values/attrs.xml4
-rw-r--r--packages/SystemUI/res/values/colors.xml8
-rw-r--r--packages/SystemUI/res/values/config.xml38
-rw-r--r--packages/SystemUI/res/values/dimens.xml33
-rw-r--r--packages/SystemUI/res/values/dimens_grid.xml3
-rw-r--r--packages/SystemUI/res/values/ids.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml145
-rw-r--r--packages/SystemUI/res/values/styles.xml14
-rw-r--r--packages/SystemUI/res/xml/lockscreen_settings.xml59
-rw-r--r--packages/SystemUI/res/xml/nav_bar_tuner.xml79
-rw-r--r--packages/SystemUI/res/xml/other_settings.xml5
-rw-r--r--packages/SystemUI/res/xml/tuner_prefs.xml13
-rw-r--r--packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java2
-rw-r--r--[-rwxr-xr-x]packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java469
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/EventLogConstants.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/LatencyTester.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/RecentsComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemBars.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java)22
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java378
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java643
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java168
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java2552
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java145
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java259
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java320
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java404
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java300
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java211
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java261
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/CustomInterpolatorTransformation.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java175
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java126
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java)2589
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java88
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java239
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java196
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/BetterListPreference.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java405
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java724
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ShortcutParser.java162
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerService.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java119
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java3
-rw-r--r--packages/SystemUI/tests/Android.mk1
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/tests/res/layout/custom_view_dark.xml20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java95
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java223
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java46
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java25
-rw-r--r--preloaded-classes901
-rw-r--r--proto/src/metrics_constants.proto63
-rw-r--r--rs/java/android/renderscript/ScriptIntrinsicBLAS.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java255
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java363
-rw-r--r--services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java212
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java101
-rw-r--r--services/autofill/java/com/android/server/autofill/AnchoredWindow.java292
-rw-r--r--services/autofill/java/com/android/server/autofill/AutoFillManagerService.java292
-rw-r--r--services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java1115
-rw-r--r--services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java14
-rw-r--r--services/autofill/java/com/android/server/autofill/AutoFillUI.java624
-rw-r--r--services/autofill/java/com/android/server/autofill/DatasetPicker.java116
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java105
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java521
-rw-r--r--services/autofill/java/com/android/server/autofill/SavePrompt.java60
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java548
-rw-r--r--services/backup/java/com/android/server/backup/Trampoline.java17
-rw-r--r--services/backup/java/com/android/server/backup/TransportManager.java410
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java2
-rw-r--r--services/core/java/com/android/server/AppOpsService.java20
-rw-r--r--services/core/java/com/android/server/BackgroundDexOptJobService.java306
-rw-r--r--services/core/java/com/android/server/BatteryService.java37
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java66
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java41
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java137
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java317
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java164
-rw-r--r--services/core/java/com/android/server/LockSettingsShellCommand.java3
-rw-r--r--services/core/java/com/android/server/LockSettingsStorage.java19
-rw-r--r--services/core/java/com/android/server/LockSettingsStrongAuth.java49
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java346
-rw-r--r--services/core/java/com/android/server/PruneInstantAppsJobService.java61
-rw-r--r--services/core/java/com/android/server/RescueParty.java28
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java3
-rw-r--r--services/core/java/com/android/server/SystemServerInitThreadPool.java2
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java22
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java138
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java938
-rw-r--r--services/core/java/com/android/server/accounts/AccountsDb.java66
-rw-r--r--services/core/java/com/android/server/am/ActiveInstrumentation.java122
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java157
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java509
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java184
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java330
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java184
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java151
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java7
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java22
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java23
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java31
-rw-r--r--services/core/java/com/android/server/am/ResizeDockedStackTimeout.java63
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java118
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java30
-rw-r--r--services/core/java/com/android/server/audio/FocusRequester.java50
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java65
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java87
-rw-r--r--services/core/java/com/android/server/audio/PlayerFocusEnforcer.java31
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java116
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java21
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java191
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java47
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java26
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java2
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java3
-rw-r--r--services/core/java/com/android/server/display/NightDisplayService.java2
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java23
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java122
-rw-r--r--services/core/java/com/android/server/firewall/IntentFirewall.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java40
-rw-r--r--services/core/java/com/android/server/input/InputWindowHandle.java7
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java18
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java143
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java56
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java395
-rw-r--r--services/core/java/com/android/server/notification/NotificationComparator.java95
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java464
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java193
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java9
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java104
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java21
-rw-r--r--services/core/java/com/android/server/notification/ValidateNotificationPeople.java7
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java117
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java850
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java405
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java630
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerShellCommand.java187
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java162
-rw-r--r--services/core/java/com/android/server/pm/BasePermission.java2
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java17
-rw-r--r--services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java851
-rw-r--r--services/core/java/com/android/server/pm/EphemeralResolver.java2
-rw-r--r--services/core/java/com/android/server/pm/Installer.java31
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java959
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java61
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java129
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java479
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java37
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java8
-rw-r--r--services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java28
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java25
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java332
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java137
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java11
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java188
-rw-r--r--services/core/java/com/android/server/pm/dex/PackageDexUsage.java76
-rw-r--r--services/core/java/com/android/server/policy/BarController.java34
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java372
-rw-r--r--services/core/java/com/android/server/power/Notifier.java11
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java78
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java34
-rw-r--r--services/core/java/com/android/server/storage/DeviceStorageMonitorService.java27
-rw-r--r--services/core/java/com/android/server/storage/DiskStatsFileLogger.java14
-rw-r--r--services/core/java/com/android/server/storage/DiskStatsLoggingService.java10
-rw-r--r--services/core/java/com/android/server/text/TextClassificationService.java71
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java44
-rw-r--r--services/core/java/com/android/server/vr/VrManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java85
-rw-r--r--services/core/java/com/android/server/webkit/SystemImpl.java5
-rw-r--r--services/core/java/com/android/server/webkit/SystemInterface.java1
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java27
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java3
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java26
-rw-r--r--services/core/java/com/android/server/wm/AppWindowContainerController.java34
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java31
-rw-r--r--services/core/java/com/android/server/wm/DimLayerController.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java162
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java132
-rw-r--r--services/core/java/com/android/server/wm/DragState.java4
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java5
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java17
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java165
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java53
-rw-r--r--services/core/java/com/android/server/wm/StackWindowController.java327
-rw-r--r--services/core/java/com/android/server/wm/StackWindowListener.java29
-rw-r--r--services/core/java/com/android/server/wm/Task.java33
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java90
-rw-r--r--services/core/java/com/android/server/wm/TaskWindowContainerController.java166
-rw-r--r--services/core/java/com/android/server/wm/TaskWindowContainerListener.java11
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowLayersController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java312
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java40
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java35
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java6
-rw-r--r--services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp2
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp9
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp32
-rw-r--r--services/core/jni/com_android_server_location_ContextHubService.cpp4
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp180
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java1056
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java37
-rw-r--r--services/java/com/android/server/SystemServer.java90
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java17
-rw-r--r--services/net/java/android/net/ip/IpManager.java14
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java10
-rw-r--r--services/net/java/android/net/util/MultinetworkPolicyTracker.java (renamed from services/net/java/android/net/util/AvoidBadWifiTracker.java)73
-rw-r--r--services/print/java/com/android/server/print/CompanionDeviceManagerService.java147
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java222
-rw-r--r--services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java45
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java14
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java104
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java156
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java245
-rw-r--r--services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java138
-rw-r--r--services/tests/servicestests/src/com/android/server/LockSettingsServiceTestable.java116
-rw-r--r--services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java228
-rw-r--r--services/tests/servicestests/src/com/android/server/LockSettingsStorageTestable.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/MockGateKeeperService.java185
-rw-r--r--services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/MockStorageManager.java493
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java228
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java206
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java164
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java158
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java1293
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java48
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java183
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java651
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java273
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java137
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DimLayerControllerTests.java65
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java93
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestIWindow.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java165
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java128
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--services/usb/Android.mk2
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java41
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java551
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java61
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java4
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl3
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java12
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java23
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java172
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceBase.java35
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java33
-rw-r--r--telephony/java/com/android/ims/ImsReasonInfo.java5
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceController.aidl25
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl25
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl16
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java2
-rw-r--r--test-runner/src/android/test/mock/MockContext.java7
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java35
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java6
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java11
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java5
-rw-r--r--tests/UiBench/AndroidManifest.xml25
-rw-r--r--tests/UiBench/res/layout/app_bar_navigation_drawer.xml1
-rw-r--r--tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java66
-rw-r--r--tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java37
-rw-r--r--tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java89
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TextUtils.java6
-rw-r--r--tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java6
-rw-r--r--tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java (renamed from core/java/com/android/internal/logging/legacy/HistogramParser.java)24
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java176
-rw-r--r--tests/net/java/android/net/apf/ApfTest.java87
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java195
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java60
-rw-r--r--tools/aapt/AaptConfig.cpp28
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Main.cpp4
-rw-r--r--tools/aapt/ResourceTable.cpp31
-rw-r--r--tools/aapt/tests/AaptConfig_test.cpp8
-rw-r--r--tools/aapt2/Android.bp2
-rw-r--r--tools/aapt2/ConfigDescription.cpp42
-rw-r--r--tools/aapt2/ConfigDescription_test.cpp8
-rw-r--r--tools/aapt2/LoadedApk.cpp124
-rw-r--r--tools/aapt2/LoadedApk.h63
-rw-r--r--tools/aapt2/Main.cpp7
-rw-r--r--tools/aapt2/Resource.cpp3
-rw-r--r--tools/aapt2/Resource.h5
-rw-r--r--tools/aapt2/ResourceParser.cpp199
-rw-r--r--tools/aapt2/ResourceParser.h3
-rw-r--r--tools/aapt2/ResourceParser_test.cpp19
-rw-r--r--tools/aapt2/Resource_test.cpp4
-rw-r--r--tools/aapt2/diff/Diff.cpp63
-rw-r--r--tools/aapt2/integration-tests/AppOne/Android.mk2
-rw-r--r--tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml22
-rw-r--r--tools/aapt2/io/File.h5
-rw-r--r--tools/aapt2/io/ZipArchive.cpp18
-rw-r--r--tools/aapt2/io/ZipArchive.h6
-rw-r--r--tools/aapt2/link/Link.cpp37
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp83
-rw-r--r--tools/aapt2/link/ManifestFixer_test.cpp60
-rw-r--r--tools/aapt2/readme.md12
-rw-r--r--tools/aapt2/strip/Strip.cpp177
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.cpp3
-rw-r--r--tools/incident_report/Android.mk3
-rw-r--r--tools/incident_section_gen/Android.mk2
-rw-r--r--tools/layoutlib/.idea/libraries/mockito.xml9
-rw-r--r--tools/layoutlib/.idea/libraries/objenesis.xml9
-rw-r--r--tools/layoutlib/bridge/bridge.iml2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java14
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java10
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java29
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java19
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java3
-rw-r--r--tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java92
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java16
-rw-r--r--tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java290
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java8
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java24
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java4
-rw-r--r--tools/layoutlib/bridge/tests/Android.mk3
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.pngbin6066 -> 35872 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.pngbin10837 -> 67226 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.pngbin7363 -> 52245 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.pngbin3343 -> 15656 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.pngbin2846 -> 13335 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.pngbin5186 -> 27015 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.pngbin566 -> 2876 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.pngbin578 -> 3693 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.pngbin4600 -> 19503 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.pngbin4565 -> 19391 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.pngbin4634 -> 20951 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.pngbin714 -> 4474 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.pngbin1749 -> 9015 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.pngbin1590 -> 8202 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.pngbin1592 -> 8220 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.pngbin5881 -> 26162 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.pngbin2449 -> 11320 bytes
-rw-r--r--tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java110
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java2
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java10
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java15
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java5
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteClassClassAdapter.java64
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java4
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java20
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java170
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java9
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java91
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java134
-rwxr-xr-xwifi/java/android/net/wifi/WifiNetworkScoreCache.java12
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java6
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ConfigParser.java (renamed from wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java)28
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java401
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java786
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java1652
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java6
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Credential.java484
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java137
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl (renamed from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl)2
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java338
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl19
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Policy.java539
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl19
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java357
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base642
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf2
-rw-r--r--wifi/tests/assets/pps/PerProviderSubscription.xml321
-rw-r--r--wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java46
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java (renamed from wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java)64
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java288
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java173
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java261
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java260
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java148
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java221
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java312
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java348
1797 files changed, 87511 insertions, 38679 deletions
diff --git a/Android.mk b/Android.mk
index 2539c3dfbda6..2c85d4d96603 100644
--- a/Android.mk
+++ b/Android.mk
@@ -107,6 +107,7 @@ LOCAL_SRC_FILES += \
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
+ core/java/android/app/backup/ISelectBackupTransportCallback.aidl \
core/java/android/app/usage/IStorageStatsManager.aidl \
core/java/android/app/usage/IUsageStatsManager.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
@@ -147,6 +148,7 @@ LOCAL_SRC_FILES += \
core/java/android/content/ISyncContext.aidl \
core/java/android/content/ISyncServiceAdapter.aidl \
core/java/android/content/ISyncStatusObserver.aidl \
+ core/java/android/content/om/IOverlayManager.aidl \
core/java/android/content/pm/ILauncherApps.aidl \
core/java/android/content/pm/IOnAppsChangedListener.aidl \
core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
@@ -180,6 +182,7 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintService.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
+ core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
@@ -262,8 +265,9 @@ LOCAL_SRC_FILES += \
core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
core/java/android/service/autofill/IAutoFillAppCallback.aidl \
core/java/android/service/autofill/IAutoFillManagerService.aidl \
- core/java/android/service/autofill/IAutoFillServerCallback.aidl \
core/java/android/service/autofill/IAutoFillService.aidl \
+ core/java/android/service/autofill/IFillCallback.aidl \
+ core/java/android/service/autofill/ISaveCallback.aidl \
core/java/android/service/carrier/ICarrierService.aidl \
core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
core/java/android/service/carrier/ICarrierMessagingService.aidl \
@@ -291,6 +295,10 @@ LOCAL_SRC_FILES += \
core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
+ core/java/android/companion/ICompanionDeviceManager.aidl \
+ core/java/android/companion/ICompanionDeviceManagerService.aidl \
+ core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl \
+ core/java/android/companion/IOnAssociateCallback.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
@@ -304,6 +312,7 @@ LOCAL_SRC_FILES += \
core/java/android/service/wallpaper/IWallpaperService.aidl \
core/java/android/service/chooser/IChooserTargetService.aidl \
core/java/android/service/chooser/IChooserTargetResult.aidl \
+ core/java/android/text/ITextClassificationService.aidl \
core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
core/java/android/view/accessibility/IAccessibilityManager.aidl \
@@ -379,6 +388,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
keystore/java/android/security/IKeyChainAliasCallback.aidl \
keystore/java/android/security/IKeyChainService.aidl \
+ location/java/android/location/IBatchedLocationCallback.aidl \
location/java/android/location/ICountryDetector.aidl \
location/java/android/location/ICountryListener.aidl \
location/java/android/location/IFusedProvider.aidl \
@@ -424,10 +434,12 @@ LOCAL_SRC_FILES += \
media/java/android/media/projection/IMediaProjectionManager.aidl \
media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
media/java/android/media/session/IActiveSessionsListener.aidl \
- media/java/android/media/session/ISessionController.aidl \
- media/java/android/media/session/ISessionControllerCallback.aidl \
+ media/java/android/media/session/IOnMediaKeyListener.aidl \
+ media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl \
media/java/android/media/session/ISession.aidl \
media/java/android/media/session/ISessionCallback.aidl \
+ media/java/android/media/session/ISessionController.aidl \
+ media/java/android/media/session/ISessionControllerCallback.aidl \
media/java/android/media/session/ISessionManager.aidl \
media/java/android/media/tv/ITvInputClient.aidl \
media/java/android/media/tv/ITvInputHardware.aidl \
@@ -461,6 +473,8 @@ LOCAL_SRC_FILES += \
telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
+ telephony/java/com/android/ims/internal/IImsServiceController.aidl \
+ telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl \
telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
telephony/java/com/android/ims/internal/IImsUt.aidl \
telephony/java/com/android/ims/internal/IImsUtListener.aidl \
@@ -536,6 +550,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
android.hardware.thermal@1.0-java-constants \
android.hardware.health@1.0-java-constants \
+ android.hardware.usb@1.0-java-constants \
LOCAL_PROTOC_OPTIMIZE_TYPE := stream
LOCAL_PROTOC_FLAGS := \
@@ -1403,6 +1418,8 @@ include $(BUILD_JAVA_LIBRARY)
# ==== c++ proto host library ==============================
include $(CLEAR_VARS)
LOCAL_MODULE := libplatformprotos
+# b/34740546, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -modernize*
LOCAL_PROTOC_OPTIMIZE_TYPE := full
LOCAL_PROTOC_FLAGS := \
--include_source_info \
diff --git a/api/current.txt b/api/current.txt
index b964a60beead..5c1bff80b655 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -118,6 +118,7 @@ package android {
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -203,7 +204,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed0 = 16844097; // 0x1010541
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -349,6 +349,7 @@ package android {
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
+ field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
@@ -408,6 +409,7 @@ package android {
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
+ field public static final int colorMode = 16844108; // 0x101054c
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -738,6 +740,7 @@ package android {
field public static final int isScrollContainer = 16843342; // 0x101024e
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
+ field public static final int isolatedSplits = 16844109; // 0x101054d
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
@@ -1117,6 +1120,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
+ field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1266,6 +1270,8 @@ package android {
field public static final int targetId = 16843740; // 0x10103dc
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
+ field public static final int targetProcess = 16844097; // 0x1010541
+ field public static final int targetSandboxVersion = 16844110; // 0x101054e
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -2683,11 +2689,26 @@ package android {
package android.accessibilityservice {
+ public final class AccessibilityButtonController {
+ method public boolean isAccessibilityButtonAvailable();
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+ method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ }
+
+ public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+ ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+ method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+ method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+ }
+
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public final void disableSelf();
method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+ method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
+ method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2779,6 +2800,7 @@ package android.accessibilityservice {
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2794,9 +2816,11 @@ package android.accessibilityservice {
field public static final int FEEDBACK_HAPTIC = 2; // 0x2
field public static final int FEEDBACK_SPOKEN = 1; // 0x1
field public static final int FEEDBACK_VISUAL = 8; // 0x8
+ field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -2808,6 +2832,22 @@ package android.accessibilityservice {
field public java.lang.String[] packageNames;
}
+ public final class FingerprintGestureController {
+ method public boolean isGestureDetectionAvailable();
+ method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+ method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+ field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+ field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+ field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+ field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+ }
+
+ public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+ ctor public FingerprintGestureController.FingerprintGestureCallback();
+ method public void onGesture(int);
+ method public void onGestureDetectionAvailabilityChanged(boolean);
+ }
+
public final class GestureDescription {
method public static long getMaxGestureDuration();
method public static int getMaxStrokeCount();
@@ -2885,7 +2925,7 @@ package android.accounts {
public class AccountManager {
method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
- method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+ method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -2894,7 +2934,7 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public static android.accounts.AccountManager get(android.content.Context);
- method public int getAccountVisibility(android.accounts.Account, int);
+ method public int getAccountVisibility(android.accounts.Account, java.lang.String);
method public android.accounts.Account[] getAccounts();
method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2905,9 +2945,9 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getPassword(android.accounts.Account);
method public java.lang.String getPreviousName(android.accounts.Account);
- method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -2921,7 +2961,7 @@ package android.accounts {
method public boolean removeAccountExplicitly(android.accounts.Account);
method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
- method public boolean setAccountVisibility(android.accounts.Account, int, int);
+ method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
method public void setPassword(android.accounts.Account, java.lang.String);
method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -2961,8 +3001,8 @@ package android.accounts {
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
- field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3066,8 +3106,10 @@ package android.animation {
public static abstract interface Animator.AnimatorListener {
method public abstract void onAnimationCancel(android.animation.Animator);
+ method public default void onAnimationEnd(android.animation.Animator, boolean);
method public abstract void onAnimationEnd(android.animation.Animator);
method public abstract void onAnimationRepeat(android.animation.Animator);
+ method public default void onAnimationStart(android.animation.Animator, boolean);
method public abstract void onAnimationStart(android.animation.Animator);
}
@@ -3103,6 +3145,8 @@ package android.animation {
method public void playSequentially(java.util.List<android.animation.Animator>);
method public void playTogether(android.animation.Animator...);
method public void playTogether(java.util.Collection<android.animation.Animator>);
+ method public void reverse();
+ method public void setCurrentPlayTime(long);
method public android.animation.AnimatorSet setDuration(long);
method public void setInterpolator(android.animation.TimeInterpolator);
method public void setStartDelay(long);
@@ -3546,6 +3590,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
+ method public boolean isActivityTransitionRunning();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
@@ -4507,6 +4552,7 @@ package android.app {
method public final boolean isInLayout();
method public final boolean isRemoving();
method public final boolean isResumed();
+ method public final boolean isStateSaved();
method public final boolean isVisible();
method public void onActivityCreated(android.os.Bundle);
method public void onActivityResult(int, int, android.content.Intent);
@@ -4678,6 +4724,7 @@ package android.app {
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+ method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
method public abstract void popBackStack();
@@ -4744,6 +4791,7 @@ package android.app {
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
+ method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -4754,6 +4802,7 @@ package android.app {
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
method public abstract android.app.FragmentTransaction setTransition(int);
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -4771,6 +4820,7 @@ package android.app {
method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+ method public void addResults(android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnDestroy(android.app.Activity);
@@ -4795,6 +4845,7 @@ package android.app {
method public android.os.Bundle getBinderCounts();
method public android.content.ComponentName getComponentName();
method public android.content.Context getContext();
+ method public java.lang.String getProcessName();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
method public android.app.UiAutomation getUiAutomation(int);
@@ -5011,13 +5062,19 @@ package android.app {
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public int getBadgeIcon();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
+ method public java.lang.String getShortcutId();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
+ method public long getTimeout();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
field public static final java.lang.String CATEGORY_ALARM = "alarm";
field public static final java.lang.String CATEGORY_CALL = "call";
field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5043,8 +5100,10 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -5076,26 +5135,26 @@ package android.app {
field public static final int FLAG_NO_CLEAR = 32; // 0x20
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
- field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
- field public static final int PRIORITY_DEFAULT = 0; // 0x0
- field public static final int PRIORITY_HIGH = 1; // 0x1
- field public static final int PRIORITY_LOW = -1; // 0xffffffff
- field public static final int PRIORITY_MAX = 2; // 0x2
- field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
+ field public static final deprecated int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final deprecated int PRIORITY_MAX = 2; // 0x2
+ field public static final deprecated int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
field public android.app.Notification.Action[] actions;
- field public android.media.AudioAttributes audioAttributes;
+ field public deprecated android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
field public deprecated android.widget.RemoteViews contentView;
- field public int defaults;
+ field public deprecated int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
@@ -5104,16 +5163,16 @@ package android.app {
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
- field public int ledARGB;
- field public int ledOffMS;
- field public int ledOnMS;
- field public deprecated int number;
- field public int priority;
+ field public deprecated int ledARGB;
+ field public deprecated int ledOffMS;
+ field public deprecated int ledOnMS;
+ field public int number;
+ field public deprecated int priority;
field public android.app.Notification publicVersion;
- field public android.net.Uri sound;
+ field public deprecated android.net.Uri sound;
field public java.lang.CharSequence tickerText;
field public deprecated android.widget.RemoteViews tickerView;
- field public long[] vibrate;
+ field public deprecated long[] vibrate;
field public int visibility;
field public long when;
}
@@ -5188,12 +5247,14 @@ package android.app {
}
public static class Notification.Builder {
- ctor public Notification.Builder(android.content.Context);
+ ctor public Notification.Builder(android.content.Context, java.lang.String);
+ ctor public deprecated Notification.Builder(android.content.Context);
method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
method public android.app.Notification build();
+ method public android.app.Notification.Builder chooseBadgeIcon(int);
method public android.widget.RemoteViews createBigContentView();
method public android.widget.RemoteViews createContentView();
method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5207,6 +5268,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
+ method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -5215,7 +5277,7 @@ package android.app {
method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
- method public android.app.Notification.Builder setDefaults(int);
+ method public deprecated android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
@@ -5223,29 +5285,31 @@ package android.app {
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
- method public android.app.Notification.Builder setLights(int, int, int);
+ method public deprecated android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public deprecated android.app.Notification.Builder setNumber(int);
+ method public android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
- method public android.app.Notification.Builder setPriority(int);
+ method public deprecated android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+ method public android.app.Notification.Builder setShortcutId(java.lang.String);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
method public android.app.Notification.Builder setSmallIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setSortKey(java.lang.String);
- method public android.app.Notification.Builder setSound(android.net.Uri);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri);
method public deprecated android.app.Notification.Builder setSound(android.net.Uri, int);
- method public android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
method public android.app.Notification.Builder setStyle(android.app.Notification.Style);
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+ method public android.app.Notification.Builder setTimeout(long);
method public android.app.Notification.Builder setUsesChronometer(boolean);
- method public android.app.Notification.Builder setVibrate(long[]);
+ method public deprecated android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
method public android.app.Notification.Builder setWhen(long);
}
@@ -5310,9 +5374,11 @@ package android.app {
public static class Notification.MessagingStyle extends android.app.Notification.Style {
ctor public Notification.MessagingStyle(java.lang.CharSequence);
+ method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message);
method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message);
method public java.lang.CharSequence getConversationTitle();
+ method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages();
method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages();
method public java.lang.CharSequence getUserDisplayName();
method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence);
@@ -5406,19 +5472,24 @@ package android.app {
method public boolean canBypassDnd();
method public boolean canShowBadge();
method public int describeContents();
+ method public void enableLights(boolean);
method public void enableVibration(boolean);
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public java.lang.String getGroup();
method public java.lang.String getId();
method public int getImportance();
+ method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
+ method public void setGroup(java.lang.String);
method public void setImportance(int);
- method public void setLights(boolean);
+ method public void setLightColor(int);
method public void setLockscreenVisibility(int);
method public void setShowBadge(boolean);
- method public void setSound(android.net.Uri);
+ method public void setSound(android.net.Uri, android.media.AudioAttributes);
method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
@@ -5427,6 +5498,17 @@ package android.app {
field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
}
+ public final class NotificationChannelGroup implements android.os.Parcelable {
+ ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor protected NotificationChannelGroup(android.os.Parcel);
+ method public int describeContents();
+ method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getId();
+ method public java.lang.CharSequence getName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
+ }
+
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
method public boolean areNotificationsEnabled();
@@ -5434,6 +5516,8 @@ package android.app {
method public void cancel(java.lang.String, int);
method public void cancelAll();
method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
@@ -5596,10 +5680,11 @@ package android.app {
}
public final class RemoteAction implements android.os.Parcelable {
- ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+ ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
method public int describeContents();
method public void dump(java.lang.String, java.io.PrintWriter);
+ method public android.app.PendingIntent getActionIntent();
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getTitle();
@@ -5607,10 +5692,6 @@ package android.app {
field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
}
- public static abstract interface RemoteAction.OnActionListener {
- method public abstract void onAction(android.app.RemoteAction);
- }
-
public final class RemoteInput implements android.os.Parcelable {
method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6112,6 +6193,7 @@ package android.app.admin {
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public android.content.Intent createAdminSupportIntent(java.lang.String);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
@@ -6120,19 +6202,22 @@ package android.app.admin {
method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
- method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
+ method public deprecated java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
- method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
+ method public deprecated java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
+ method public java.util.List<java.lang.String> getDelegatePackages(android.content.ComponentName, java.lang.String);
+ method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -6174,7 +6259,7 @@ package android.app.admin {
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isBackupServiceEnabled(android.content.ComponentName);
- method public boolean isCallerApplicationRestrictionsManagingPackage();
+ method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isManagedProfile(android.content.ComponentName);
@@ -6202,14 +6287,15 @@ package android.app.admin {
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
- method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public deprecated void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
- method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
+ method public deprecated void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
+ method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
@@ -6257,6 +6343,7 @@ package android.app.admin {
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+ field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6266,6 +6353,12 @@ package android.app.admin {
field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
+ field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+ field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
@@ -6273,6 +6366,7 @@ package android.app.admin {
field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+ field public static final java.lang.String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
@@ -6331,6 +6425,8 @@ package android.app.admin {
field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
+ field public static final java.lang.String POLICY_DISABLE_CAMERA = "policy_disable_camera";
+ field public static final java.lang.String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -6437,6 +6533,7 @@ package android.app.assist {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
method public android.view.autofill.AutoFillType getAutoFillType();
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -6868,6 +6965,7 @@ package android.appwidget {
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders();
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(android.os.UserHandle);
method public static android.appwidget.AppWidgetManager getInstance(android.content.Context);
+ method public boolean isRequestPinAppWidgetSupported();
method public void notifyAppWidgetViewDataChanged(int[], int);
method public void notifyAppWidgetViewDataChanged(int, int);
method public void partiallyUpdateAppWidget(int[], android.widget.RemoteViews);
@@ -7868,6 +7966,65 @@ package android.bluetooth.le {
}
+package android.companion {
+
+ public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+ }
+
+ public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+ method public android.companion.AssociationRequest<F> build();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+ method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+ method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+ }
+
+ public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothDeviceFilter.Builder {
+ ctor public BluetoothDeviceFilter.Builder();
+ method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+ method public android.companion.BluetoothDeviceFilter build();
+ method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+ method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ }
+
+ public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothLEDeviceFilter.Builder {
+ ctor public BluetoothLEDeviceFilter.Builder();
+ method public android.companion.BluetoothLEDeviceFilter build();
+ method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+ }
+
+ public final class CompanionDeviceManager {
+ method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+ field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+ }
+
+ public static abstract class CompanionDeviceManager.Callback {
+ ctor public CompanionDeviceManager.Callback();
+ method public abstract void onDeviceFound(android.content.IntentSender);
+ method public abstract void onFailure(java.lang.CharSequence);
+ }
+
+ public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+ }
+
+}
+
package android.content {
public abstract class AbstractThreadedSyncAdapter {
@@ -8009,6 +8166,7 @@ package android.content {
method public java.lang.CharSequence getLabel();
method public java.lang.String getMimeType(int);
method public int getMimeTypeCount();
+ method public long getTimestamp();
method public boolean hasMimeType(java.lang.String);
method public void setExtras(android.os.PersistableBundle);
method public void writeToParcel(android.os.Parcel, int);
@@ -8355,6 +8513,7 @@ package android.content {
method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public abstract deprecated void clearWallpaper() throws java.io.IOException;
method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public abstract android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Context createDeviceProtectedStorageContext();
method public abstract android.content.Context createDisplayContext(android.view.Display);
method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -8478,6 +8637,7 @@ package android.content {
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -8553,6 +8713,7 @@ package android.content {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public deprecated void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -8861,6 +9022,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
+ field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
@@ -9002,6 +9164,7 @@ package android.content {
field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
+ field public static final java.lang.String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -9012,6 +9175,10 @@ package android.content {
field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+ field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+ field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9048,6 +9215,7 @@ package android.content {
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
+ field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN";
field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -9575,7 +9743,10 @@ package android.content.pm {
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
method public final int getThemeResource();
- field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
+ field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
+ field public static final int COLOR_MODE_HDR = 2; // 0x2
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT = 1; // 0x1
+ field public static final int CONFIG_COLOR_MODE = 16384; // 0x4000
field public static final int CONFIG_DENSITY = 4096; // 0x1000
field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -9636,6 +9807,7 @@ package android.content.pm {
field public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11; // 0xb
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
+ field public int colorMode;
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
@@ -9732,6 +9904,7 @@ package android.content.pm {
field public int requiresSmallestWidthDp;
field public java.lang.String[] sharedLibraryFiles;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public int targetSdkVersion;
@@ -9739,6 +9912,7 @@ package android.content.pm {
field public int theme;
field public int uiOptions;
field public int uid;
+ field public java.lang.String volumeUuid;
}
public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator {
@@ -9814,9 +9988,11 @@ package android.content.pm {
field public boolean handleProfiling;
field public java.lang.String publicSourceDir;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public java.lang.String targetPackage;
+ field public java.lang.String targetProcess;
}
public class LabeledIntent extends android.content.Intent {
@@ -9866,7 +10042,8 @@ package android.content.pm {
method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
- field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
}
@@ -10064,6 +10241,7 @@ package android.content.pm {
method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public abstract boolean canRequestPackageInstalls();
method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
@@ -10094,6 +10272,8 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
+ method public abstract byte[] getInstantAppCookie();
+ method public abstract int getInstantAppCookieMaxSize();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -10127,6 +10307,7 @@ package android.content.pm {
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
+ method public abstract boolean isInstantApp();
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -10146,6 +10327,7 @@ package android.content.pm {
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public abstract boolean setInstantAppCookie(byte[]);
method public abstract void verifyPendingInstall(int, int);
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
@@ -10176,6 +10358,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
@@ -10231,6 +10414,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -10611,16 +10795,16 @@ package android.content.res {
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
method public void writeToParcel(android.os.Parcel, int);
- field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
- field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
- field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
- field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
- field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_MASK = 12; // 0xc
+ field public static final int COLOR_MODE_HDR_NO = 4; // 0x4
+ field public static final int COLOR_MODE_HDR_SHIFT = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_HDR_YES = 8; // 0x8
+ field public static final int COLOR_MODE_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 2; // 0x2
field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -10686,7 +10870,7 @@ package android.content.res {
field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
- field public int colorimetry;
+ field public int colorMode;
field public int densityDpi;
field public float fontScale;
field public int hardKeyboardHidden;
@@ -10806,6 +10990,7 @@ package android.content.res {
method public int getDimensionPixelSize(int, int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public float getFloat(int, float);
+ method public android.graphics.Typeface getFont(int);
method public float getFraction(int, int, int, float);
method public int getIndex(int);
method public int getIndexCount();
@@ -12673,6 +12858,7 @@ package android.graphics {
method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
method public float getFontSpacing();
+ method public java.lang.String getFontVariationSettings();
method public int getHinting();
method public float getLetterSpacing();
method public android.graphics.MaskFilter getMaskFilter();
@@ -12730,6 +12916,7 @@ package android.graphics {
method public void setFilterBitmap(boolean);
method public void setFlags(int);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method public void setHinting(int);
method public void setLetterSpacing(float);
method public void setLinearText(boolean);
@@ -13662,6 +13849,23 @@ package android.graphics.drawable {
method public void addLevel(int, int, android.graphics.drawable.Drawable);
}
+ public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+ ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public void draw(android.graphics.Canvas);
+ method public android.graphics.drawable.Drawable getBackground();
+ method public android.graphics.drawable.Drawable getForeground();
+ method public android.graphics.Path getIconMask();
+ method public int getOpacity();
+ method public void invalidateDrawable(android.graphics.drawable.Drawable);
+ method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+ method public void setAlpha(int);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setOpacity(int);
+ method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+ field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
+ field public static final float MASK_SIZE = 100.0f;
+ }
+
public class NinePatchDrawable extends android.graphics.drawable.Drawable {
ctor public deprecated NinePatchDrawable(android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
@@ -14161,9 +14365,10 @@ package android.hardware {
method public int getWidth();
method public boolean isDestroyed();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BLOB = 33; // 0x21
field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
field public static final int RGBA_8888 = 1; // 0x1
- field public static final int RGBA_FP16 = 5; // 0x5
+ field public static final int RGBA_FP16 = 22; // 0x16
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
@@ -14184,6 +14389,7 @@ package android.hardware {
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getHighestDirectReportRateLevel();
method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
@@ -14197,6 +14403,7 @@ package android.hardware {
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isAdditionalInfoSupported();
+ method public boolean isDirectChannelTypeSupported(int);
method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
@@ -14274,6 +14481,17 @@ package android.hardware {
field public final int type;
}
+ public final class SensorDirectChannel implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean isValid();
+ field public static final int RATE_FAST = 2; // 0x2
+ field public static final int RATE_NORMAL = 1; // 0x1
+ field public static final int RATE_STOP = 0; // 0x0
+ field public static final int RATE_VERY_FAST = 3; // 0x3
+ field public static final int TYPE_ASHMEM = 1; // 0x1
+ field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -14305,6 +14523,9 @@ package android.hardware {
public abstract class SensorManager {
method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer);
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
@@ -14434,7 +14655,7 @@ package android.hardware.camera2 {
method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void close();
- method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void finalizeOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isReprocessable();
@@ -14849,6 +15070,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -14928,6 +15150,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -15075,10 +15298,12 @@ package android.hardware.camera2.params {
ctor public OutputConfiguration(android.view.Surface);
ctor public OutputConfiguration(int, android.view.Surface);
ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
+ method public void addSurface(android.view.Surface);
method public int describeContents();
+ method public void enableSurfaceSharing();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
- method public void setDeferredSurface(android.view.Surface);
+ method public java.util.List<android.view.Surface> getSurfaces();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -15147,6 +15372,7 @@ package android.hardware.display {
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
+ field public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
@@ -20305,6 +20531,7 @@ package android.media {
method public int getContentType();
method public int getFlags();
method public int getUsage();
+ method public static int getVolumeControlStream(android.media.AudioAttributes);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -20314,7 +20541,7 @@ package android.media {
field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
- field public static final int FLAG_LOW_LATENCY = 256; // 0x100
+ field public static final deprecated int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20755,6 +20982,7 @@ package android.media {
method protected deprecated int getNativeFrameCount();
method public static int getNativeOutputSampleRate(int);
method public int getNotificationMarkerPosition();
+ method public int getPerformanceMode();
method public int getPlayState();
method public int getPlaybackHeadPosition();
method public android.media.PlaybackParams getPlaybackParams();
@@ -20801,6 +21029,9 @@ package android.media {
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
field public static final int MODE_STATIC = 0; // 0x0
field public static final int MODE_STREAM = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_LOW_LATENCY = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_NONE = 0; // 0x0
+ field public static final int PERFORMANCE_MODE_POWER_SAVING = 2; // 0x2
field public static final int PLAYSTATE_PAUSED = 2; // 0x2
field public static final int PLAYSTATE_PLAYING = 3; // 0x3
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
@@ -20818,6 +21049,7 @@ package android.media {
method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioTrack.Builder setPerformanceMode(int);
method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
}
@@ -20832,6 +21064,40 @@ package android.media {
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -21184,6 +21450,7 @@ package android.media {
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -21976,6 +22243,7 @@ package android.media {
public final class MediaMuxer {
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
+ ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
method public int addTrack(android.media.MediaFormat);
method public void release();
method public void setLocation(float, float);
@@ -21986,6 +22254,7 @@ package android.media {
}
public static final class MediaMuxer.OutputFormat {
+ field public static final int MUXER_OUTPUT_3GPP = 2; // 0x2
field public static final int MUXER_OUTPUT_MPEG_4 = 0; // 0x0
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
@@ -22004,8 +22273,14 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
+ method public android.media.MediaPlayer.DrmInfo getDrmInfo();
+ method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
+ method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
@@ -22018,8 +22293,12 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
+ method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
+ method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
+ method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
method public void reset();
+ method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
@@ -22027,6 +22306,7 @@ package android.media {
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -22035,10 +22315,15 @@ package android.media {
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
+ method public void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void setLooping(boolean);
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
@@ -22081,6 +22366,16 @@ package android.media {
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
+ public static final class MediaPlayer.DrmInfo {
+ method public java.lang.String[] getMimes();
+ method public java.util.Map<java.util.UUID, byte[]> getPssh();
+ method public java.util.UUID[] getSupportedSchemes();
+ }
+
+ public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.NoDrmSchemeException(java.lang.String);
+ }
+
public static abstract interface MediaPlayer.OnBufferingUpdateListener {
method public abstract void onBufferingUpdate(android.media.MediaPlayer, int);
}
@@ -22089,6 +22384,19 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
+ public static abstract class MediaPlayer.OnDrmConfigCallback {
+ ctor public MediaPlayer.OnDrmConfigCallback();
+ method public void onDrmConfig(android.media.MediaPlayer);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmInfoListener {
+ method public abstract void onDrmInfo(android.media.MediaPlayer, android.media.MediaPlayer.DrmInfo);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmPreparedListener {
+ method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
+ }
+
public static abstract interface MediaPlayer.OnErrorListener {
method public abstract boolean onError(android.media.MediaPlayer, int, int);
}
@@ -22117,6 +22425,10 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
+ public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
+ }
+
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {
method public int describeContents();
method public android.media.MediaFormat getFormat();
@@ -23363,6 +23675,8 @@ package android.media.session {
public final class MediaController {
ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+ method public void addQueueItem(android.media.MediaDescription);
+ method public void addQueueItem(android.media.MediaDescription, int);
method public void adjustVolume(int, int);
method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
method public android.os.Bundle getExtras();
@@ -23381,6 +23695,8 @@ package android.media.session {
method public boolean isShuffleModeEnabled();
method public void registerCallback(android.media.session.MediaController.Callback);
method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+ method public void removeQueueItem(android.media.MediaDescription);
+ method public void removeQueueItemAt(int);
method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void setVolumeTo(int, int);
method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -23458,11 +23774,14 @@ package android.media.session {
method public void setSessionActivity(android.app.PendingIntent);
method public void setShuffleModeEnabled(boolean);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class MediaSession.Callback {
ctor public MediaSession.Callback();
+ method public void onAddQueueItem(android.media.MediaDescription);
+ method public void onAddQueueItem(android.media.MediaDescription, int);
method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void onCustomAction(java.lang.String, android.os.Bundle);
method public void onFastForward();
@@ -23476,6 +23795,8 @@ package android.media.session {
method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+ method public void onRemoveQueueItem(android.media.MediaDescription);
+ method public void onRemoveQueueItemAt(int);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -23633,6 +23954,31 @@ package android.media.tv {
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
+ public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+ field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+ field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+ field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+ field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+ field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+ field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+ field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ }
+
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
}
@@ -23715,44 +24061,70 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
- field public static final java.lang.String COLUMN_PREVIEW_DURATION = "preview_duration";
- field public static final java.lang.String COLUMN_PREVIEW_INTENT_URI = "preview_intent_uri";
- field public static final java.lang.String COLUMN_PREVIEW_LAST_PLAYBACK_POSITION = "preview_last_playback_position";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_PREVIEW_WEIGHT = "preview_weight";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs.Genres {
@@ -23778,37 +24150,15 @@ package android.media.tv {
field public static final java.lang.String TRAVEL = "TRAVEL";
}
- public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
field public static final android.net.Uri CONTENT_URI;
@@ -23863,10 +24213,13 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24336,6 +24689,7 @@ package android.net {
method public android.net.Network getBoundNetworkForProcess();
method public android.net.ProxyInfo getDefaultProxy();
method public android.net.LinkProperties getLinkProperties(android.net.Network);
+ method public int getMultipathPreference(android.net.Network);
method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
method public deprecated android.net.NetworkInfo getNetworkInfo(int);
method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -24375,6 +24729,9 @@ package android.net {
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final java.lang.String EXTRA_REASON = "reason";
+ field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+ field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+ field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -25328,6 +25685,7 @@ package android.net.wifi {
field public java.util.BitSet allowedProtocols;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public int networkId;
field public java.lang.String preSharedKey;
field public int priority;
@@ -25395,6 +25753,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -25408,6 +25767,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -25460,6 +25820,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -25472,6 +25833,7 @@ package android.net.wifi {
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -25483,9 +25845,11 @@ package android.net.wifi {
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
+ method public boolean removePasspointConfiguration(java.lang.String);
method public boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
@@ -25493,6 +25857,10 @@ package android.net.wifi {
method public boolean startScan();
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int ERROR_AUTHENTICATING = 1; // 0x1
@@ -25500,6 +25868,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
@@ -25684,6 +26064,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentififer();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnysOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -29225,6 +29840,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+ field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -29926,6 +30542,7 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
+ method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -29970,6 +30587,7 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
+ method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -30726,6 +31344,7 @@ package android.preference {
method public android.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
method public android.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
method public int getOrder();
+ method public android.preference.PreferenceGroup getParent();
method protected boolean getPersistedBoolean(boolean);
method protected float getPersistedFloat(float);
method protected int getPersistedInt(int);
@@ -32696,7 +33315,7 @@ package android.provider {
ctor public ContactsContract.Intents();
field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
- field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+ field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32809,7 +33428,6 @@ package android.provider {
field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
field public static final java.lang.String STATUS = "status";
field public static final int STATUS_BUSY = 1; // 0x1
- field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
field public static final int STATUS_EMPTY = 2; // 0x2
field public static final int STATUS_NORMAL = 0; // 0x0
}
@@ -33054,7 +33672,6 @@ package android.provider {
method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public android.content.res.AssetFileDescriptor openTypedDocument(java.lang.String, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
- method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
method public android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], android.os.Bundle) throws java.io.FileNotFoundException;
@@ -33443,6 +34060,7 @@ package android.provider {
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
@@ -33460,6 +34078,7 @@ package android.provider {
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_EXTERNAL_SOURCES = "android.settings.action.MANAGE_EXTERNAL_SOURCES";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -33495,8 +34114,10 @@ package android.provider {
field public static final java.lang.String AUTHORITY = "settings";
field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+ field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -33605,7 +34226,7 @@ package android.provider {
field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
- field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+ field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
field public static final java.lang.String LOCATION_MODE = "location_mode";
field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
@@ -34160,6 +34781,8 @@ package android.provider {
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DELETED = "deleted";
@@ -34167,6 +34790,7 @@ package android.provider {
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -34174,6 +34798,7 @@ package android.provider {
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+ field public static final java.lang.String RESTORED = "restored";
field public static final java.lang.String SOURCE_DATA = "source_data";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -35553,21 +36178,22 @@ package android.service.autofill {
method public void onConnected();
method public void onDisconnected();
method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
- field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
- field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
+ method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class FillCallback {
+ public final class FillCallback implements android.os.Parcelable {
+ method public int describeContents();
method public void onFailure(java.lang.CharSequence);
method public void onSuccess(android.view.autofill.FillResponse);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
}
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
- method public void onSuccess(android.view.autofill.AutoFillId[]);
+ method public void onSuccess();
}
}
@@ -35844,8 +36470,9 @@ package android.service.notification {
method public void deleteNotificationChannel(java.lang.String, java.lang.String);
method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+ method public final void unsnoozeNotification(java.lang.String);
method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -35861,6 +36488,7 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+ method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
@@ -35879,8 +36507,6 @@ package android.service.notification {
method public final void setNotificationsShown(java.lang.String[]);
method public final void snoozeNotification(java.lang.String, java.lang.String);
method public final void snoozeNotification(java.lang.String, long);
- method public final void snoozeNotification(java.lang.String);
- method public final void unsnoozeNotification(java.lang.String);
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -35905,9 +36531,9 @@ package android.service.notification {
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_TIMEOUT = 19; // 0x13
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -37991,6 +38617,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
@@ -38606,6 +39233,7 @@ package android.telephony {
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
+ method public java.lang.String getVisualVoicemailPackageName(android.telecom.PhoneAccountHandle);
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -38626,6 +39254,7 @@ package android.telephony {
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
+ method public boolean sendDialerCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
@@ -38658,6 +39287,7 @@ package android.telephony {
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+ field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
@@ -38666,6 +39296,7 @@ package android.telephony {
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
+ field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -39211,6 +39842,7 @@ package android.test.mock {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public void clearWallpaper();
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -39358,6 +39990,7 @@ package android.test.mock {
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public boolean canRequestPackageInstalls();
method public java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
@@ -39389,6 +40022,8 @@ package android.test.mock {
method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
+ method public byte[] getInstantAppCookie();
+ method public int getInstantAppCookieMaxSize();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -39421,6 +40056,7 @@ package android.test.mock {
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
+ method public boolean isInstantApp();
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -39440,6 +40076,7 @@ package android.test.mock {
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public boolean setInstantAppCookie(byte[]);
method public void verifyPendingInstall(int, int);
}
@@ -41388,6 +42025,15 @@ package android.transition {
method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
}
+ public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+ ctor public TransitionListenerAdapter();
+ method public void onTransitionCancel(android.transition.Transition);
+ method public void onTransitionEnd(android.transition.Transition);
+ method public void onTransitionPause(android.transition.Transition);
+ method public void onTransitionResume(android.transition.Transition);
+ method public void onTransitionStart(android.transition.Transition);
+ }
+
public class TransitionManager {
ctor public TransitionManager();
method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -42339,6 +42985,7 @@ package android.view {
method public boolean isValid();
method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
+ field public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
field public static final int FLAG_ROUND = 16; // 0x10
@@ -42589,6 +43236,7 @@ package android.view {
field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
field public static final int SOURCE_KEYBOARD = 257; // 0x101
field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_MOUSE_RELATIVE = 131076; // 0x20004
field public static final int SOURCE_STYLUS = 16386; // 0x4002
field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
@@ -43702,6 +44350,7 @@ package android.view {
ctor public View(android.content.Context, android.util.AttributeSet, int);
ctor public View(android.content.Context, android.util.AttributeSet, int, int);
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -43743,6 +44392,7 @@ package android.view {
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
+ method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -43761,6 +44411,7 @@ package android.view {
method public boolean dispatchNestedPrePerformAccessibilityAction(int, android.os.Bundle);
method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+ method public void dispatchPointerCaptureChanged(boolean);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
method public void dispatchProvideStructure(android.view.ViewStructure);
@@ -43799,7 +44450,8 @@ package android.view {
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public android.view.autofill.AutoFillType getAutoFillType();
- method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
+ method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate();
method public android.graphics.drawable.Drawable getBackground();
method public android.content.res.ColorStateList getBackgroundTintList();
method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -43826,6 +44478,7 @@ package android.view {
method public float getElevation();
method public boolean getFilterTouchesWhenObscured();
method public boolean getFitsSystemWindows();
+ method public int getFocusable();
method public java.util.ArrayList<android.view.View> getFocusables(int);
method public void getFocusedRect(android.graphics.Rect);
method public android.graphics.drawable.Drawable getForeground();
@@ -43941,6 +44594,7 @@ package android.view {
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -44005,6 +44659,7 @@ package android.view {
method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
+ method public boolean onCapturedPointerEvent(android.view.MotionEvent);
method public boolean onCheckIsTextEditor();
method protected void onConfigurationChanged(android.content.res.Configuration);
method protected void onCreateContextMenu(android.view.ContextMenu);
@@ -44034,6 +44689,7 @@ package android.view {
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
method protected void onOverScrolled(int, int, boolean, boolean);
+ method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
@@ -44076,6 +44732,7 @@ package android.view {
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -44086,6 +44743,7 @@ package android.view {
method public boolean requestFocus(int, android.graphics.Rect);
method public final boolean requestFocusFromTouch();
method public void requestLayout();
+ method public void requestPointerCapture();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
method public final void requestUnbufferedDispatch(android.view.MotionEvent);
@@ -44129,6 +44787,7 @@ package android.view {
method public void setFilterTouchesWhenObscured(boolean);
method public void setFitsSystemWindows(boolean);
method public void setFocusable(boolean);
+ method public void setFocusable(int);
method public void setFocusableInTouchMode(boolean);
method public void setFocusedByDefault(boolean);
method public void setForeground(android.graphics.drawable.Drawable);
@@ -44162,6 +44821,7 @@ package android.view {
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
+ method public void setOnCapturedPointerListener(android.view.View.OnCapturedPointerListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
@@ -44244,8 +44904,6 @@ package android.view {
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
- field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
- field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44266,8 +44924,10 @@ package android.view {
field protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET;
field public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 2; // 0x2
field public static final int FIND_VIEWS_WITH_TEXT = 1; // 0x1
+ field public static final int FOCUSABLE = 1; // 0x1
field public static final int FOCUSABLES_ALL = 0; // 0x0
field public static final int FOCUSABLES_TOUCH_MODE = 1; // 0x1
+ field public static final int FOCUSABLE_AUTO = 16; // 0x10
field protected static final int[] FOCUSED_SELECTED_STATE_SET;
field protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
field protected static final int[] FOCUSED_STATE_SET;
@@ -44297,6 +44957,7 @@ package android.view {
field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field public static final int NOT_FOCUSABLE = 0; // 0x0
field public static final int NO_ID = -1; // 0xffffffff
field public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
field public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
@@ -44385,6 +45046,7 @@ package android.view {
public static class View.AccessibilityDelegate {
ctor public View.AccessibilityDelegate();
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -44431,6 +45093,10 @@ package android.view {
method public abstract void onViewDetachedFromWindow(android.view.View);
}
+ public static abstract interface View.OnCapturedPointerListener {
+ method public abstract boolean onCapturedPointer(android.view.View, android.view.MotionEvent);
+ }
+
public static abstract interface View.OnClickListener {
method public abstract void onClick(android.view.View);
}
@@ -44634,8 +45300,8 @@ package android.view {
method public int getPersistentDrawingCache();
method public boolean getTouchscreenBlocksFocus();
method public int indexOfChild(android.view.View);
- method public final void invalidateChild(android.view.View, android.graphics.Rect);
- method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
method public deprecated boolean isAnimationCacheEnabled();
method protected boolean isChildrenDrawingOrderEnabled();
@@ -44798,14 +45464,15 @@ package android.view {
method public abstract android.view.ViewParent getParentForAccessibility();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
- method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
- method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public abstract boolean isLayoutDirectionResolved();
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
+ method public default void onDescendantInvalidated(android.view.View, android.view.View);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
@@ -44873,7 +45540,7 @@ package android.view {
method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewStructure asyncNewChild(int);
- method public abstract android.view.ViewStructure asyncNewChild(int, int);
+ method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
method public abstract int getChildCount();
method public abstract android.os.Bundle getExtras();
method public abstract java.lang.CharSequence getHint();
@@ -44882,11 +45549,12 @@ package android.view {
method public abstract int getTextSelectionStart();
method public abstract boolean hasExtras();
method public abstract android.view.ViewStructure newChild(int);
- method public abstract android.view.ViewStructure newChild(int, int);
+ method public abstract android.view.ViewStructure newChild(int, int, int);
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
+ method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
method public abstract void setChecked(boolean);
method public abstract void setChildCount(int);
@@ -44909,6 +45577,7 @@ package android.view {
method public abstract void setTextStyle(float, int, int, int);
method public abstract void setTransformation(android.graphics.Matrix);
method public abstract void setVisibility(int);
+ field public static final int AUTO_FILL_FLAG_SANITIZED = 1; // 0x1
}
public final class ViewStub extends android.view.View {
@@ -45001,6 +45670,7 @@ package android.view {
method public boolean getAllowReturnTransitionOverlap();
method public final android.view.WindowManager.LayoutParams getAttributes();
method public final android.view.Window.Callback getCallback();
+ method public int getColorMode();
method public final android.view.Window getContainer();
method public android.transition.Scene getContentScene();
method public final android.content.Context getContext();
@@ -45057,6 +45727,7 @@ package android.view {
method public abstract void setChildDrawable(int, android.graphics.drawable.Drawable);
method public abstract void setChildInt(int, int);
method public void setClipToOutline(boolean);
+ method public void setColorMode(int);
method public void setContainer(android.view.Window);
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
@@ -45161,6 +45832,7 @@ package android.view {
method public abstract boolean onMenuItemSelected(int, android.view.MenuItem);
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
+ method public default void onPointerCaptureChanged(boolean);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
@@ -45255,8 +45927,10 @@ package android.view {
method public final int copyFrom(android.view.WindowManager.LayoutParams);
method public java.lang.String debug(java.lang.String);
method public int describeContents();
+ method public int getColorMode();
method public final java.lang.CharSequence getTitle();
method public static boolean mayUseInputMethod(int);
+ method public void setColorMode(int);
method public final void setTitle(java.lang.CharSequence);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALPHA_CHANGED = 128; // 0x80
@@ -45337,6 +46011,7 @@ package android.view {
field public static final int TYPE_APPLICATION = 2; // 0x2
field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
+ field public static final int TYPE_APPLICATION_OVERLAY = 2038; // 0x7f6
field public static final int TYPE_APPLICATION_PANEL = 1000; // 0x3e8
field public static final int TYPE_APPLICATION_STARTING = 3; // 0x3
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
@@ -45346,17 +46021,17 @@ package android.view {
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
- field public static final int TYPE_PHONE = 2002; // 0x7d2
- field public static final int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
+ field public static final deprecated int TYPE_PHONE = 2002; // 0x7d2
+ field public static final deprecated int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
field public static final int TYPE_PRIVATE_PRESENTATION = 2030; // 0x7ee
field public static final int TYPE_SEARCH_BAR = 2001; // 0x7d1
field public static final int TYPE_STATUS_BAR = 2000; // 0x7d0
field public static final int TYPE_STATUS_BAR_PANEL = 2014; // 0x7de
- field public static final int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
+ field public static final deprecated int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
field public static final int TYPE_SYSTEM_DIALOG = 2008; // 0x7d8
- field public static final int TYPE_SYSTEM_ERROR = 2010; // 0x7da
- field public static final int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
- field public static final int TYPE_TOAST = 2005; // 0x7d5
+ field public static final deprecated int TYPE_SYSTEM_ERROR = 2010; // 0x7da
+ field public static final deprecated int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
+ field public static final deprecated int TYPE_TOAST = 2005; // 0x7d5
field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
field public float alpha;
field public float buttonBrightness;
@@ -45492,6 +46167,7 @@ package android.view.accessibility {
method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
method public deprecated int getActions();
+ method public java.util.List<java.lang.String> getAvailableExtraData();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -45548,11 +46224,13 @@ package android.view.accessibility {
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
method public boolean refresh();
+ method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
method public deprecated void removeAction(int);
method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method public boolean removeChild(android.view.View);
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String>);
method public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
method public void setCanOpenPopup(boolean);
@@ -45635,6 +46313,9 @@ package android.view.accessibility {
field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
field public static final int FOCUS_INPUT = 1; // 0x1
field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -45716,6 +46397,7 @@ package android.view.accessibility {
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
+ method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -46125,6 +46807,14 @@ package android.view.autofill {
field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
}
+ public final class AutoFillManager {
+ method public void focusChanged(android.view.View, boolean);
+ method public void reset();
+ method public void valueChanged(android.view.View);
+ method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+ method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
+ }
+
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
method public static android.view.autofill.AutoFillType forList();
@@ -46157,8 +46847,9 @@ package android.view.autofill {
}
public static final class Dataset.Builder {
- ctor public Dataset.Builder(java.lang.CharSequence);
+ ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
method public android.view.autofill.Dataset build();
+ method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
}
@@ -46170,10 +46861,11 @@ package android.view.autofill {
}
public static final class FillResponse.Builder {
- ctor public FillResponse.Builder();
+ ctor public FillResponse.Builder(java.lang.String);
method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.view.autofill.FillResponse build();
+ method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
}
@@ -46182,13 +46874,6 @@ package android.view.autofill {
method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
}
- public static abstract class VirtualViewDelegate.Callback {
- ctor public VirtualViewDelegate.Callback();
- method public void onFocusChanged(int, boolean);
- method public void onNodeRemoved(int...);
- method public void onValueChanged(int);
- }
-
}
package android.view.inputmethod {
@@ -48695,8 +49380,6 @@ package android.widget {
method public void addHeaderView(android.view.View);
method public boolean areFooterDividersEnabled();
method public boolean areHeaderDividersEnabled();
- method protected android.view.View findViewTraversal(int);
- method protected android.view.View findViewWithTagTraversal(java.lang.Object);
method public android.widget.ListAdapter getAdapter();
method public deprecated long[] getCheckItemIds();
method public android.graphics.drawable.Drawable getDivider();
@@ -48962,6 +49645,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
+ method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();
@@ -49711,6 +50395,7 @@ package android.widget {
method public int getExtendedPaddingTop();
method public android.text.InputFilter[] getFilters();
method public java.lang.String getFontFeatureSettings();
+ method public java.lang.String getFontVariationSettings();
method public boolean getFreezesText();
method public int getGravity();
method public int getHighlightColor();
@@ -49820,6 +50505,7 @@ package android.widget {
method public void setExtractedText(android.view.inputmethod.ExtractedText);
method public void setFilters(android.text.InputFilter[]);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method protected boolean setFrame(int, int, int, int);
method public void setFreezesText(boolean);
method public void setGravity(int);
@@ -49929,6 +50615,7 @@ package android.widget {
method public void setIs24HourView(java.lang.Boolean);
method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+ method public boolean validateInput();
}
public static abstract interface TimePicker.OnTimeChangedListener {
@@ -50327,6 +51014,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -53621,12 +54310,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -53660,17 +54352,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -53687,6 +54385,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
@@ -62016,6 +62715,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -62026,7 +62728,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -62055,12 +62761,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/system-current.txt b/api/system-current.txt
index d7c8f5aee4e4..a29c7f8a71e4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37,6 +37,7 @@ package android {
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
+ field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
@@ -205,6 +206,7 @@ package android {
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
@@ -217,6 +219,7 @@ package android {
field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
+ field public static final java.lang.String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
@@ -224,6 +227,7 @@ package android {
field public static final java.lang.String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY";
field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
field public static final java.lang.String SET_TIME_ZONE = "android.permission.SET_TIME_ZONE";
+ field public static final java.lang.String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
field public static final java.lang.String SET_WALLPAPER = "android.permission.SET_WALLPAPER";
field public static final java.lang.String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final java.lang.String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
@@ -312,7 +316,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed0 = 16844097; // 0x1010541
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -458,6 +461,7 @@ package android {
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
+ field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
@@ -517,6 +521,7 @@ package android {
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
+ field public static final int colorMode = 16844108; // 0x101054c
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -847,6 +852,7 @@ package android {
field public static final int isScrollContainer = 16843342; // 0x101024e
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
+ field public static final int isolatedSplits = 16844109; // 0x101054d
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
@@ -1230,6 +1236,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
+ field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1379,6 +1386,8 @@ package android {
field public static final int targetId = 16843740; // 0x10103dc
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
+ field public static final int targetProcess = 16844097; // 0x1010541
+ field public static final int targetSandboxVersion = 16844110; // 0x101054e
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -2799,11 +2808,26 @@ package android {
package android.accessibilityservice {
+ public final class AccessibilityButtonController {
+ method public boolean isAccessibilityButtonAvailable();
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+ method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ }
+
+ public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+ ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+ method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+ method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+ }
+
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public final void disableSelf();
method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+ method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
+ method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2895,6 +2919,7 @@ package android.accessibilityservice {
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2910,9 +2935,11 @@ package android.accessibilityservice {
field public static final int FEEDBACK_HAPTIC = 2; // 0x2
field public static final int FEEDBACK_SPOKEN = 1; // 0x1
field public static final int FEEDBACK_VISUAL = 8; // 0x8
+ field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -2924,6 +2951,22 @@ package android.accessibilityservice {
field public java.lang.String[] packageNames;
}
+ public final class FingerprintGestureController {
+ method public boolean isGestureDetectionAvailable();
+ method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+ method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+ field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+ field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+ field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+ field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+ }
+
+ public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+ ctor public FingerprintGestureController.FingerprintGestureCallback();
+ method public void onGesture(int);
+ method public void onGestureDetectionAvailabilityChanged(boolean);
+ }
+
public final class GestureDescription {
method public static long getMaxGestureDuration();
method public static int getMaxStrokeCount();
@@ -3001,7 +3044,7 @@ package android.accounts {
public class AccountManager {
method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
- method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+ method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -3011,7 +3054,7 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method 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);
method public static android.accounts.AccountManager get(android.content.Context);
- method public int getAccountVisibility(android.accounts.Account, int);
+ method public int getAccountVisibility(android.accounts.Account, java.lang.String);
method public android.accounts.Account[] getAccounts();
method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -3022,9 +3065,9 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getPassword(android.accounts.Account);
method public java.lang.String getPreviousName(android.accounts.Account);
- method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -3038,7 +3081,7 @@ package android.accounts {
method public boolean removeAccountExplicitly(android.accounts.Account);
method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
- method public boolean setAccountVisibility(android.accounts.Account, int, int);
+ method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
method public void setPassword(android.accounts.Account, java.lang.String);
method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -3078,8 +3121,8 @@ package android.accounts {
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
- field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3183,8 +3226,10 @@ package android.animation {
public static abstract interface Animator.AnimatorListener {
method public abstract void onAnimationCancel(android.animation.Animator);
+ method public default void onAnimationEnd(android.animation.Animator, boolean);
method public abstract void onAnimationEnd(android.animation.Animator);
method public abstract void onAnimationRepeat(android.animation.Animator);
+ method public default void onAnimationStart(android.animation.Animator, boolean);
method public abstract void onAnimationStart(android.animation.Animator);
}
@@ -3220,6 +3265,8 @@ package android.animation {
method public void playSequentially(java.util.List<android.animation.Animator>);
method public void playTogether(android.animation.Animator...);
method public void playTogether(java.util.Collection<android.animation.Animator>);
+ method public void reverse();
+ method public void setCurrentPlayTime(long);
method public android.animation.AnimatorSet setDuration(long);
method public void setInterpolator(android.animation.TimeInterpolator);
method public void setStartDelay(long);
@@ -3665,6 +3712,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
+ method public boolean isActivityTransitionRunning();
method public boolean isBackgroundVisibleBehind();
method public boolean isChangingConfigurations();
method public final boolean isChild();
@@ -4664,6 +4712,7 @@ package android.app {
method public final boolean isInLayout();
method public final boolean isRemoving();
method public final boolean isResumed();
+ method public final boolean isStateSaved();
method public final boolean isVisible();
method public void onActivityCreated(android.os.Bundle);
method public void onActivityResult(int, int, android.content.Intent);
@@ -4835,6 +4884,7 @@ package android.app {
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+ method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
method public abstract void popBackStack();
@@ -4901,6 +4951,7 @@ package android.app {
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
+ method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -4911,6 +4962,7 @@ package android.app {
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
method public abstract android.app.FragmentTransaction setTransition(int);
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -4928,6 +4980,7 @@ package android.app {
method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+ method public void addResults(android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnDestroy(android.app.Activity);
@@ -4952,6 +5005,7 @@ package android.app {
method public android.os.Bundle getBinderCounts();
method public android.content.ComponentName getComponentName();
method public android.content.Context getContext();
+ method public java.lang.String getProcessName();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
method public android.app.UiAutomation getUiAutomation(int);
@@ -5168,14 +5222,20 @@ package android.app {
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public int getBadgeIcon();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
+ method public java.lang.String getShortcutId();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
+ method public long getTimeout();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
field public static final java.lang.String CATEGORY_ALARM = "alarm";
field public static final java.lang.String CATEGORY_CALL = "call";
field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5201,8 +5261,10 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -5236,26 +5298,26 @@ package android.app {
field public static final int FLAG_NO_CLEAR = 32; // 0x20
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
- field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
- field public static final int PRIORITY_DEFAULT = 0; // 0x0
- field public static final int PRIORITY_HIGH = 1; // 0x1
- field public static final int PRIORITY_LOW = -1; // 0xffffffff
- field public static final int PRIORITY_MAX = 2; // 0x2
- field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
+ field public static final deprecated int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final deprecated int PRIORITY_MAX = 2; // 0x2
+ field public static final deprecated int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
field public android.app.Notification.Action[] actions;
- field public android.media.AudioAttributes audioAttributes;
+ field public deprecated android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
field public deprecated android.widget.RemoteViews contentView;
- field public int defaults;
+ field public deprecated int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
@@ -5264,16 +5326,16 @@ package android.app {
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
- field public int ledARGB;
- field public int ledOffMS;
- field public int ledOnMS;
- field public deprecated int number;
- field public int priority;
+ field public deprecated int ledARGB;
+ field public deprecated int ledOffMS;
+ field public deprecated int ledOnMS;
+ field public int number;
+ field public deprecated int priority;
field public android.app.Notification publicVersion;
- field public android.net.Uri sound;
+ field public deprecated android.net.Uri sound;
field public java.lang.CharSequence tickerText;
field public deprecated android.widget.RemoteViews tickerView;
- field public long[] vibrate;
+ field public deprecated long[] vibrate;
field public int visibility;
field public long when;
}
@@ -5348,12 +5410,14 @@ package android.app {
}
public static class Notification.Builder {
- ctor public Notification.Builder(android.content.Context);
+ ctor public Notification.Builder(android.content.Context, java.lang.String);
+ ctor public deprecated Notification.Builder(android.content.Context);
method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
method public android.app.Notification build();
+ method public android.app.Notification.Builder chooseBadgeIcon(int);
method public android.widget.RemoteViews createBigContentView();
method public android.widget.RemoteViews createContentView();
method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5367,6 +5431,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
+ method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -5375,7 +5440,7 @@ package android.app {
method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
- method public android.app.Notification.Builder setDefaults(int);
+ method public deprecated android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
@@ -5383,29 +5448,31 @@ package android.app {
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
- method public android.app.Notification.Builder setLights(int, int, int);
+ method public deprecated android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public deprecated android.app.Notification.Builder setNumber(int);
+ method public android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
- method public android.app.Notification.Builder setPriority(int);
+ method public deprecated android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+ method public android.app.Notification.Builder setShortcutId(java.lang.String);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
method public android.app.Notification.Builder setSmallIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setSortKey(java.lang.String);
- method public android.app.Notification.Builder setSound(android.net.Uri);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri);
method public deprecated android.app.Notification.Builder setSound(android.net.Uri, int);
- method public android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
method public android.app.Notification.Builder setStyle(android.app.Notification.Style);
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+ method public android.app.Notification.Builder setTimeout(long);
method public android.app.Notification.Builder setUsesChronometer(boolean);
- method public android.app.Notification.Builder setVibrate(long[]);
+ method public deprecated android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
method public android.app.Notification.Builder setWhen(long);
}
@@ -5470,9 +5537,11 @@ package android.app {
public static class Notification.MessagingStyle extends android.app.Notification.Style {
ctor public Notification.MessagingStyle(java.lang.CharSequence);
+ method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message);
method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message);
method public java.lang.CharSequence getConversationTitle();
+ method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages();
method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages();
method public java.lang.CharSequence getUserDisplayName();
method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence);
@@ -5579,9 +5648,13 @@ package android.app {
method public boolean canBypassDnd();
method public boolean canShowBadge();
method public int describeContents();
+ method public void enableLights(boolean);
method public void enableVibration(boolean);
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public java.lang.String getGroup();
method public java.lang.String getId();
method public int getImportance();
+ method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
@@ -5592,11 +5665,12 @@ package android.app {
method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
method public void setBypassDnd(boolean);
method public void setDeleted(boolean);
+ method public void setGroup(java.lang.String);
method public void setImportance(int);
- method public void setLights(boolean);
+ method public void setLightColor(int);
method public void setLockscreenVisibility(int);
method public void setShowBadge(boolean);
- method public void setSound(android.net.Uri);
+ method public void setSound(android.net.Uri, android.media.AudioAttributes);
method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
@@ -5607,6 +5681,7 @@ package android.app {
field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
field public static final int[] LOCKABLE_FIELDS;
field public static final int USER_LOCKED_ALLOWED = 64; // 0x40
+ field public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 256; // 0x100
field public static final int USER_LOCKED_IMPORTANCE = 4; // 0x4
field public static final int USER_LOCKED_LIGHTS = 8; // 0x8
field public static final int USER_LOCKED_PRIORITY = 1; // 0x1
@@ -5616,6 +5691,20 @@ package android.app {
field public static final int USER_LOCKED_VISIBILITY = 2; // 0x2
}
+ public final class NotificationChannelGroup implements android.os.Parcelable {
+ ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor protected NotificationChannelGroup(android.os.Parcel);
+ method public void addChannel(android.app.NotificationChannel);
+ method public int describeContents();
+ method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getId();
+ method public java.lang.CharSequence getName();
+ method public org.json.JSONObject toJson() throws org.json.JSONException;
+ method public void writeToParcel(android.os.Parcel, int);
+ method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+ field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
+ }
+
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
method public boolean areNotificationsEnabled();
@@ -5623,6 +5712,8 @@ package android.app {
method public void cancel(java.lang.String, int);
method public void cancelAll();
method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
@@ -5785,10 +5876,11 @@ package android.app {
}
public final class RemoteAction implements android.os.Parcelable {
- ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+ ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
method public int describeContents();
method public void dump(java.lang.String, java.io.PrintWriter);
+ method public android.app.PendingIntent getActionIntent();
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getTitle();
@@ -5796,10 +5888,6 @@ package android.app {
field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
}
- public static abstract interface RemoteAction.OnActionListener {
- method public abstract void onAction(android.app.RemoteAction);
- }
-
public final class RemoteInput implements android.os.Parcelable {
method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6138,6 +6226,10 @@ package android.app {
method public void onDetached();
}
+ public class VrManager {
+ method public void setPersistentVrModeEnabled(boolean);
+ }
+
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -6306,6 +6398,7 @@ package android.app.admin {
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public android.content.Intent createAdminSupportIntent(java.lang.String);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
@@ -6314,16 +6407,18 @@ package android.app.admin {
method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
- method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
+ method public deprecated java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
- method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
+ method public deprecated java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
+ method public java.util.List<java.lang.String> getDelegatePackages(android.content.ComponentName, java.lang.String);
+ method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public java.lang.String getDeviceOwner();
@@ -6333,6 +6428,7 @@ package android.app.admin {
method public java.lang.CharSequence getDeviceOwnerOrganizationName();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -6379,7 +6475,7 @@ package android.app.admin {
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isBackupServiceEnabled(android.content.ComponentName);
- method public boolean isCallerApplicationRestrictionsManagingPackage();
+ method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceManaged();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isDeviceProvisioned();
@@ -6414,14 +6510,15 @@ package android.app.admin {
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
- method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public deprecated void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
- method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
+ method public deprecated void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
+ method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setDeviceProvisioningConfigApplied();
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
@@ -6470,6 +6567,7 @@ package android.app.admin {
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+ field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6482,6 +6580,12 @@ package android.app.admin {
field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
+ field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+ field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
@@ -6489,6 +6593,7 @@ package android.app.admin {
field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+ field public static final java.lang.String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
@@ -6552,6 +6657,8 @@ package android.app.admin {
field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
+ field public static final java.lang.String POLICY_DISABLE_CAMERA = "policy_disable_camera";
+ field public static final java.lang.String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -6663,6 +6770,7 @@ package android.app.assist {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
method public android.view.autofill.AutoFillType getAutoFillType();
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -6787,15 +6895,18 @@ package android.app.backup {
method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, int);
method public int requestRestore(android.app.backup.RestoreObserver);
- method public java.lang.String selectBackupTransport(java.lang.String);
+ method public deprecated java.lang.String selectBackupTransport(java.lang.String);
+ method public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
method public void setAutoRestore(boolean);
method public void setBackupEnabled(boolean);
field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
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 java.lang.String PACKAGE_MANAGER_SENTINEL = "@pm@";
field public static final int SUCCESS = 0; // 0x0
@@ -6910,6 +7021,12 @@ package android.app.backup {
field public long token;
}
+ public abstract class SelectBackupTransportCallback {
+ ctor public SelectBackupTransportCallback();
+ method public void onFailure(int);
+ method public void onSuccess(java.lang.String);
+ }
+
public class SharedPreferencesBackupHelper extends android.app.backup.FileBackupHelperBase implements android.app.backup.BackupHelper {
ctor public SharedPreferencesBackupHelper(android.content.Context, java.lang.String...);
method public void performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor);
@@ -7208,6 +7325,7 @@ package android.appwidget {
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders();
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(android.os.UserHandle);
method public static android.appwidget.AppWidgetManager getInstance(android.content.Context);
+ method public boolean isRequestPinAppWidgetSupported();
method public void notifyAppWidgetViewDataChanged(int[], int);
method public void notifyAppWidgetViewDataChanged(int, int);
method public void partiallyUpdateAppWidget(int[], android.widget.RemoteViews);
@@ -8238,6 +8356,65 @@ package android.bluetooth.le {
}
+package android.companion {
+
+ public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+ }
+
+ public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+ method public android.companion.AssociationRequest<F> build();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+ method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+ method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+ }
+
+ public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothDeviceFilter.Builder {
+ ctor public BluetoothDeviceFilter.Builder();
+ method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+ method public android.companion.BluetoothDeviceFilter build();
+ method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+ method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ }
+
+ public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothLEDeviceFilter.Builder {
+ ctor public BluetoothLEDeviceFilter.Builder();
+ method public android.companion.BluetoothLEDeviceFilter build();
+ method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+ }
+
+ public final class CompanionDeviceManager {
+ method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+ field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+ }
+
+ public static abstract class CompanionDeviceManager.Callback {
+ ctor public CompanionDeviceManager.Callback();
+ method public abstract void onDeviceFound(android.content.IntentSender);
+ method public abstract void onFailure(java.lang.CharSequence);
+ }
+
+ public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+ }
+
+}
+
package android.content {
public abstract class AbstractThreadedSyncAdapter {
@@ -8379,6 +8556,7 @@ package android.content {
method public java.lang.CharSequence getLabel();
method public java.lang.String getMimeType(int);
method public int getMimeTypeCount();
+ method public long getTimestamp();
method public boolean hasMimeType(java.lang.String);
method public void setExtras(android.os.PersistableBundle);
method public void writeToParcel(android.os.Parcel, int);
@@ -8726,6 +8904,7 @@ package android.content {
method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public abstract deprecated void clearWallpaper() throws java.io.IOException;
method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public abstract android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Context createCredentialProtectedStorageContext();
method public abstract android.content.Context createDeviceProtectedStorageContext();
method public abstract android.content.Context createDisplayContext(android.view.Display);
@@ -8855,6 +9034,7 @@ package android.content {
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
@@ -8913,6 +9093,7 @@ package android.content {
field public static final java.lang.String USB_SERVICE = "usb";
field public static final java.lang.String USER_SERVICE = "user";
field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
+ field public static final java.lang.String VR_SERVICE = "vrmanager";
field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
@@ -8936,6 +9117,7 @@ package android.content {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public deprecated void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createCredentialProtectedStorageContext();
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
@@ -9249,6 +9431,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
+ field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
@@ -9398,6 +9581,7 @@ package android.content {
field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
+ field public static final java.lang.String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -9408,6 +9592,10 @@ package android.content {
field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+ field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+ field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9448,6 +9636,7 @@ package android.content {
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
+ field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN";
field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -9978,7 +10167,10 @@ package android.content.pm {
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
method public final int getThemeResource();
- field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
+ field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
+ field public static final int COLOR_MODE_HDR = 2; // 0x2
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT = 1; // 0x1
+ field public static final int CONFIG_COLOR_MODE = 16384; // 0x4000
field public static final int CONFIG_DENSITY = 4096; // 0x1000
field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -10039,6 +10231,7 @@ package android.content.pm {
field public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11; // 0xb
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
+ field public int colorMode;
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
@@ -10136,6 +10329,7 @@ package android.content.pm {
field public int requiresSmallestWidthDp;
field public java.lang.String[] sharedLibraryFiles;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public int targetSdkVersion;
@@ -10143,6 +10337,7 @@ package android.content.pm {
field public int theme;
field public int uiOptions;
field public int uid;
+ field public java.lang.String volumeUuid;
}
public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator {
@@ -10253,9 +10448,11 @@ package android.content.pm {
field public boolean handleProfiling;
field public java.lang.String publicSourceDir;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public java.lang.String targetPackage;
+ field public java.lang.String targetProcess;
}
public final class IntentFilterVerificationInfo implements android.os.Parcelable {
@@ -10314,7 +10511,8 @@ package android.content.pm {
method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
- field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
}
@@ -10518,6 +10716,7 @@ package android.content.pm {
method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public abstract boolean canRequestPackageInstalls();
method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
@@ -10551,6 +10750,8 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
+ method public abstract byte[] getInstantAppCookie();
+ method public abstract int getInstantAppCookieMaxSize();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
@@ -10588,6 +10789,7 @@ package android.content.pm {
method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
+ method public abstract boolean isInstantApp();
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -10611,6 +10813,7 @@ package android.content.pm {
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public abstract boolean setInstantAppCookie(byte[]);
method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
@@ -10647,6 +10850,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
@@ -10703,6 +10907,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -11158,16 +11363,16 @@ package android.content.res {
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
method public void writeToParcel(android.os.Parcel, int);
- field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
- field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
- field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
- field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
- field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_MASK = 12; // 0xc
+ field public static final int COLOR_MODE_HDR_NO = 4; // 0x4
+ field public static final int COLOR_MODE_HDR_SHIFT = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_HDR_YES = 8; // 0x8
+ field public static final int COLOR_MODE_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 2; // 0x2
field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -11233,7 +11438,7 @@ package android.content.res {
field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
- field public int colorimetry;
+ field public int colorMode;
field public int densityDpi;
field public float fontScale;
field public int hardKeyboardHidden;
@@ -11353,6 +11558,7 @@ package android.content.res {
method public int getDimensionPixelSize(int, int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public float getFloat(int, float);
+ method public android.graphics.Typeface getFont(int);
method public float getFraction(int, int, int, float);
method public int getIndex(int);
method public int getIndexCount();
@@ -13220,6 +13426,7 @@ package android.graphics {
method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
method public float getFontSpacing();
+ method public java.lang.String getFontVariationSettings();
method public int getHinting();
method public float getLetterSpacing();
method public android.graphics.MaskFilter getMaskFilter();
@@ -13277,6 +13484,7 @@ package android.graphics {
method public void setFilterBitmap(boolean);
method public void setFlags(int);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method public void setHinting(int);
method public void setLetterSpacing(float);
method public void setLinearText(boolean);
@@ -14209,6 +14417,23 @@ package android.graphics.drawable {
method public void addLevel(int, int, android.graphics.drawable.Drawable);
}
+ public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+ ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public void draw(android.graphics.Canvas);
+ method public android.graphics.drawable.Drawable getBackground();
+ method public android.graphics.drawable.Drawable getForeground();
+ method public android.graphics.Path getIconMask();
+ method public int getOpacity();
+ method public void invalidateDrawable(android.graphics.drawable.Drawable);
+ method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+ method public void setAlpha(int);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setOpacity(int);
+ method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+ field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
+ field public static final float MASK_SIZE = 100.0f;
+ }
+
public class NinePatchDrawable extends android.graphics.drawable.Drawable {
ctor public deprecated NinePatchDrawable(android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
@@ -14708,9 +14933,10 @@ package android.hardware {
method public int getWidth();
method public boolean isDestroyed();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BLOB = 33; // 0x21
field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
field public static final int RGBA_8888 = 1; // 0x1
- field public static final int RGBA_FP16 = 5; // 0x5
+ field public static final int RGBA_FP16 = 22; // 0x16
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
@@ -14731,6 +14957,7 @@ package android.hardware {
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getHighestDirectReportRateLevel();
method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
@@ -14746,6 +14973,7 @@ package android.hardware {
method public int getVersion();
method public boolean isAdditionalInfoSupported();
method public boolean isDataInjectionSupported();
+ method public boolean isDirectChannelTypeSupported(int);
method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
@@ -14827,6 +15055,17 @@ package android.hardware {
field public final int type;
}
+ public final class SensorDirectChannel implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean isValid();
+ field public static final int RATE_FAST = 2; // 0x2
+ field public static final int RATE_NORMAL = 1; // 0x1
+ field public static final int RATE_STOP = 0; // 0x0
+ field public static final int RATE_VERY_FAST = 3; // 0x3
+ field public static final int TYPE_ASHMEM = 1; // 0x1
+ field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -14858,6 +15097,9 @@ package android.hardware {
public abstract class SensorManager {
method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer);
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
@@ -14989,7 +15231,7 @@ package android.hardware.camera2 {
method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void close();
- method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void finalizeOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isReprocessable();
@@ -15404,6 +15646,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -15483,6 +15726,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -15632,11 +15876,13 @@ package android.hardware.camera2.params {
ctor public OutputConfiguration(android.view.Surface, int);
ctor public OutputConfiguration(int, android.view.Surface, int);
ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
+ method public void addSurface(android.view.Surface);
method public int describeContents();
+ method public void enableSurfaceSharing();
method public int getRotation();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
- method public void setDeferredSurface(android.view.Surface);
+ method public java.util.List<android.view.Surface> getSurfaces();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int ROTATION_0 = 0; // 0x0
@@ -15709,6 +15955,7 @@ package android.hardware.display {
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
+ field public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
@@ -21168,6 +21415,11 @@ package android.location {
field public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
}
+ public abstract class BatchedLocationCallback {
+ ctor public BatchedLocationCallback();
+ method public void onLocationBatch(java.util.List<android.location.Location>);
+ }
+
public class Criteria implements android.os.Parcelable {
ctor public Criteria();
ctor public Criteria(android.location.Criteria);
@@ -21706,14 +21958,17 @@ package android.location {
method public void clearTestProviderEnabled(java.lang.String);
method public void clearTestProviderLocation(java.lang.String);
method public void clearTestProviderStatus(java.lang.String);
+ method public void flushGnssBatch();
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
+ method public int getGnssBatchSize();
method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
method public android.location.Location getLastKnownLocation(java.lang.String);
method public android.location.LocationProvider getProvider(java.lang.String);
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
+ method public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
@@ -21744,6 +21999,7 @@ package android.location {
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+ method public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback);
@@ -21845,6 +22101,7 @@ package android.media {
method public int getContentType();
method public int getFlags();
method public int getUsage();
+ method public static int getVolumeControlStream(android.media.AudioAttributes);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -21858,7 +22115,7 @@ package android.media {
field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
field public static final int FLAG_HW_HOTWORD = 32; // 0x20
- field public static final int FLAG_LOW_LATENCY = 256; // 0x100
+ field public static final deprecated int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -21935,6 +22192,7 @@ package android.media {
method public int describeContents();
method public android.media.AudioAttributes getAttributes();
method public java.lang.String getClientId();
+ method public int getClientUid();
method public int getFlags();
method public int getGainRequest();
method public int getLossReceived();
@@ -22344,6 +22602,7 @@ package android.media {
method protected deprecated int getNativeFrameCount();
method public static int getNativeOutputSampleRate(int);
method public int getNotificationMarkerPosition();
+ method public int getPerformanceMode();
method public int getPlayState();
method public int getPlaybackHeadPosition();
method public android.media.PlaybackParams getPlaybackParams();
@@ -22390,6 +22649,9 @@ package android.media {
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
field public static final int MODE_STATIC = 0; // 0x0
field public static final int MODE_STREAM = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_LOW_LATENCY = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_NONE = 0; // 0x0
+ field public static final int PERFORMANCE_MODE_POWER_SAVING = 2; // 0x2
field public static final int PLAYSTATE_PAUSED = 2; // 0x2
field public static final int PLAYSTATE_PLAYING = 3; // 0x3
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
@@ -22407,6 +22669,7 @@ package android.media {
method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioTrack.Builder setPerformanceMode(int);
method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
}
@@ -22421,6 +22684,40 @@ package android.media {
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -22773,6 +23070,7 @@ package android.media {
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -23565,6 +23863,7 @@ package android.media {
public final class MediaMuxer {
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
+ ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
method public int addTrack(android.media.MediaFormat);
method public void release();
method public void setLocation(float, float);
@@ -23575,6 +23874,7 @@ package android.media {
}
public static final class MediaMuxer.OutputFormat {
+ field public static final int MUXER_OUTPUT_3GPP = 2; // 0x2
field public static final int MUXER_OUTPUT_MPEG_4 = 0; // 0x0
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
@@ -23593,8 +23893,14 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
+ method public android.media.MediaPlayer.DrmInfo getDrmInfo();
+ method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
+ method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
@@ -23607,8 +23913,12 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
+ method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
+ method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
+ method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
method public void reset();
+ method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
@@ -23616,6 +23926,7 @@ package android.media {
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -23624,10 +23935,15 @@ package android.media {
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
+ method public void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void setLooping(boolean);
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
@@ -23670,6 +23986,16 @@ package android.media {
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
+ public static final class MediaPlayer.DrmInfo {
+ method public java.lang.String[] getMimes();
+ method public java.util.Map<java.util.UUID, byte[]> getPssh();
+ method public java.util.UUID[] getSupportedSchemes();
+ }
+
+ public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.NoDrmSchemeException(java.lang.String);
+ }
+
public static abstract interface MediaPlayer.OnBufferingUpdateListener {
method public abstract void onBufferingUpdate(android.media.MediaPlayer, int);
}
@@ -23678,6 +24004,19 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
+ public static abstract class MediaPlayer.OnDrmConfigCallback {
+ ctor public MediaPlayer.OnDrmConfigCallback();
+ method public void onDrmConfig(android.media.MediaPlayer);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmInfoListener {
+ method public abstract void onDrmInfo(android.media.MediaPlayer, android.media.MediaPlayer.DrmInfo);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmPreparedListener {
+ method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
+ }
+
public static abstract interface MediaPlayer.OnErrorListener {
method public abstract boolean onError(android.media.MediaPlayer, int, int);
}
@@ -23706,6 +24045,10 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
+ public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
+ }
+
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {
method public int describeContents();
method public android.media.MediaFormat getFormat();
@@ -24035,10 +24378,12 @@ package android.media {
}
public class PlayerProxy {
- method public void pause() throws java.lang.IllegalStateException;
- method public void setVolume(float) throws java.lang.IllegalStateException;
- method public void start() throws java.lang.IllegalStateException;
- method public void stop() throws java.lang.IllegalStateException;
+ 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 final class Rating implements android.os.Parcelable {
@@ -25033,6 +25378,8 @@ package android.media.session {
public final class MediaController {
ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+ method public void addQueueItem(android.media.MediaDescription);
+ method public void addQueueItem(android.media.MediaDescription, int);
method public void adjustVolume(int, int);
method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
method public android.os.Bundle getExtras();
@@ -25051,6 +25398,8 @@ package android.media.session {
method public boolean isShuffleModeEnabled();
method public void registerCallback(android.media.session.MediaController.Callback);
method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+ method public void removeQueueItem(android.media.MediaDescription);
+ method public void removeQueueItemAt(int);
method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void setVolumeTo(int, int);
method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -25128,11 +25477,14 @@ package android.media.session {
method public void setSessionActivity(android.app.PendingIntent);
method public void setShuffleModeEnabled(boolean);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class MediaSession.Callback {
ctor public MediaSession.Callback();
+ method public void onAddQueueItem(android.media.MediaDescription);
+ method public void onAddQueueItem(android.media.MediaDescription, int);
method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void onCustomAction(java.lang.String, android.os.Bundle);
method public void onFastForward();
@@ -25146,6 +25498,8 @@ package android.media.session {
method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+ method public void onRemoveQueueItem(android.media.MediaDescription);
+ method public void onRemoveQueueItemAt(int);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -25178,12 +25532,22 @@ package android.media.session {
method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler);
method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
+ method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
+ method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
}
public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
}
+ public static abstract interface MediaSessionManager.OnMediaKeyListener {
+ method public abstract boolean onMediaKey(android.view.KeyEvent);
+ }
+
+ public static abstract interface MediaSessionManager.OnVolumeKeyLongPressListener {
+ method public abstract void onVolumeKeyLongPress(android.view.KeyEvent);
+ }
+
public final class PlaybackState implements android.os.Parcelable {
method public int describeContents();
method public long getActions();
@@ -25352,6 +25716,31 @@ package android.media.tv {
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
+ public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+ field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+ field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+ field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+ field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+ field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+ field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+ field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ }
+
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
}
@@ -25379,6 +25768,7 @@ package android.media.tv {
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+ field public static final java.lang.String COLUMN_SYSTEM_APPROVED = "system_approved";
field public static final java.lang.String COLUMN_TRANSIENT = "transient";
field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
field public static final java.lang.String COLUMN_TYPE = "type";
@@ -25437,45 +25827,71 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
- field public static final java.lang.String COLUMN_PREVIEW_DURATION = "preview_duration";
- field public static final java.lang.String COLUMN_PREVIEW_INTENT_URI = "preview_intent_uri";
- field public static final java.lang.String COLUMN_PREVIEW_LAST_PLAYBACK_POSITION = "preview_last_playback_position";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_PREVIEW_WEIGHT = "preview_weight";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
field public static final java.lang.String COLUMN_TRANSIENT = "transient";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs.Genres {
@@ -25501,37 +25917,15 @@ package android.media.tv {
field public static final java.lang.String TRAVEL = "TRAVEL";
}
- public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
field public static final android.net.Uri CONTENT_URI;
@@ -25666,10 +26060,13 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -25931,6 +26328,7 @@ package android.metrics {
ctor public LogMaker(int);
ctor public LogMaker(java.lang.Object[]);
method public android.metrics.LogMaker addTaggedData(int, java.lang.Object);
+ method public android.metrics.LogMaker clearTaggedData(int);
method public void deserialize(java.lang.Object[]);
method public int getCategory();
method public long getCounterBucket();
@@ -25942,6 +26340,7 @@ package android.metrics {
method public long getTimestamp();
method public int getType();
method public boolean isLongCounterBucket();
+ method public boolean isSubsetOf(android.metrics.LogMaker);
method public boolean isValidValue(java.lang.Object);
method public java.lang.Object[] serialize();
method public android.metrics.LogMaker setCategory(int);
@@ -26228,6 +26627,7 @@ package android.net {
method public java.lang.String getCaptivePortalServerUrl();
method public android.net.ProxyInfo getDefaultProxy();
method public android.net.LinkProperties getLinkProperties(android.net.Network);
+ method public int getMultipathPreference(android.net.Network);
method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
method public deprecated android.net.NetworkInfo getNetworkInfo(int);
method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -26271,6 +26671,9 @@ package android.net {
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final java.lang.String EXTRA_REASON = "reason";
+ field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+ field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+ field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -26482,6 +26885,10 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
}
+ public class NetworkBadging {
+ method public static android.graphics.drawable.Drawable getWifiIcon(int, int, android.content.res.Resources.Theme);
+ }
+
public final class NetworkCapabilities implements android.os.Parcelable {
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
method public int describeContents();
@@ -27785,6 +28192,7 @@ package android.net.wifi {
field public int creatorUid;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public java.lang.String lastUpdateName;
field public int lastUpdateUid;
field public boolean meteredHint;
@@ -27875,6 +28283,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -27888,6 +28297,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -27940,6 +28350,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -27955,6 +28366,7 @@ package android.net.wifi {
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
@@ -27974,9 +28386,11 @@ package android.net.wifi {
method public boolean isWifiEnabled();
method public boolean isWifiScannerSupported();
method public boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
+ method public boolean removePasspointConfiguration(java.lang.String);
method public boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
@@ -27988,6 +28402,10 @@ package android.net.wifi {
method public boolean startScan(android.os.WorkSource);
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
@@ -28001,6 +28419,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
@@ -28344,6 +28774,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentififer();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnysOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -31898,6 +32563,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+ field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -32621,6 +33287,7 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
+ method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -32665,6 +33332,7 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
+ method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -33425,7 +34093,6 @@ package android.permissionpresenterservice {
method public final void attachBaseContext(android.content.Context);
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
- method public abstract java.util.List<android.content.pm.ApplicationInfo> onGetAppsUsingPermissions(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
}
@@ -33538,6 +34205,7 @@ package android.preference {
method public android.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
method public android.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
method public int getOrder();
+ method public android.preference.PreferenceGroup getParent();
method protected boolean getPersistedBoolean(boolean);
method protected float getPersistedFloat(float);
method protected int getPersistedInt(int);
@@ -35534,7 +36202,7 @@ package android.provider {
ctor public ContactsContract.Intents();
field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
- field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+ field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -35677,7 +36345,6 @@ package android.provider {
field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
field public static final java.lang.String STATUS = "status";
field public static final int STATUS_BUSY = 1; // 0x1
- field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
field public static final int STATUS_EMPTY = 2; // 0x2
field public static final int STATUS_NORMAL = 0; // 0x0
}
@@ -35922,7 +36589,6 @@ package android.provider {
method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public android.content.res.AssetFileDescriptor openTypedDocument(java.lang.String, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
- method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
method public android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], android.os.Bundle) throws java.io.FileNotFoundException;
@@ -36409,10 +37075,12 @@ package android.provider {
field public static final java.lang.String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
field public static final java.lang.String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
+ field public static final java.lang.String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_CONFIGURE_WIFI_SETTINGS = "android.settings.CONFIGURE_WIFI_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
@@ -36432,6 +37100,7 @@ package android.provider {
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_EXTERNAL_SOURCES = "android.settings.action.MANAGE_EXTERNAL_SOURCES";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -36468,8 +37137,10 @@ package android.provider {
field public static final java.lang.String AUTHORITY = "settings";
field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+ field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -36528,6 +37199,7 @@ package android.provider {
field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+ field public static final java.lang.String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
field public static final java.lang.String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
@@ -36588,7 +37260,7 @@ package android.provider {
field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
- field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+ field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
field public static final java.lang.String LOCATION_MODE = "location_mode";
field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
@@ -37143,6 +37815,8 @@ package android.provider {
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DELETED = "deleted";
@@ -37150,6 +37824,7 @@ package android.provider {
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -37157,6 +37832,7 @@ package android.provider {
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+ field public static final java.lang.String RESTORED = "restored";
field public static final java.lang.String SOURCE_DATA = "source_data";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -38361,6 +39037,18 @@ package android.security {
package android.security.keystore {
+ public abstract class AttestationUtils {
+ method public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, int[], 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
+ }
+
+ public class DeviceIdAttestationException extends java.lang.Exception {
+ ctor public DeviceIdAttestationException(java.lang.String);
+ ctor public DeviceIdAttestationException(java.lang.String, java.lang.Throwable);
+ }
+
public class KeyExpiredException extends java.security.InvalidKeyException {
ctor public KeyExpiredException();
ctor public KeyExpiredException(java.lang.String);
@@ -38536,21 +39224,22 @@ package android.service.autofill {
method public void onConnected();
method public void onDisconnected();
method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
- field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
- field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
+ method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class FillCallback {
+ public final class FillCallback implements android.os.Parcelable {
+ method public int describeContents();
method public void onFailure(java.lang.CharSequence);
method public void onSuccess(android.view.autofill.FillResponse);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
}
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
- method public void onSuccess(android.view.autofill.AutoFillId[]);
+ method public void onSuccess();
}
}
@@ -38827,8 +39516,9 @@ package android.service.notification {
method public void deleteNotificationChannel(java.lang.String, java.lang.String);
method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+ method public final void unsnoozeNotification(java.lang.String);
method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -38846,6 +39536,7 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+ method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
@@ -38866,9 +39557,7 @@ package android.service.notification {
method public final void setOnNotificationPostedTrim(int);
method public final void snoozeNotification(java.lang.String, java.lang.String);
method public final void snoozeNotification(java.lang.String, long);
- method public final void snoozeNotification(java.lang.String);
method public void unregisterAsSystemService() throws android.os.RemoteException;
- method public final void unsnoozeNotification(java.lang.String);
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -38893,9 +39582,9 @@ package android.service.notification {
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_TIMEOUT = 19; // 0x13
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -41248,6 +41937,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
@@ -41905,6 +42595,7 @@ package android.telephony {
method public int getSimState(int);
method public java.lang.String getSubscriberId();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+ method public java.lang.String getVisualVoicemailPackageName(android.telecom.PhoneAccountHandle);
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -41935,6 +42626,7 @@ package android.telephony {
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public boolean needsOtaServiceProvisioning();
+ method public boolean sendDialerCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
@@ -41983,6 +42675,7 @@ package android.telephony {
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+ field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
@@ -41991,6 +42684,7 @@ package android.telephony {
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
+ field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -42014,11 +42708,6 @@ package android.telephony {
field public static final int PHONE_TYPE_GSM = 1; // 0x1
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
- field public static final int SIM_ACTIVATION_RESULT_CANCELED = 4; // 0x4
- field public static final int SIM_ACTIVATION_RESULT_COMPLETE = 0; // 0x0
- field public static final int SIM_ACTIVATION_RESULT_FAILED = 3; // 0x3
- field public static final int SIM_ACTIVATION_RESULT_IN_PROGRESS = 2; // 0x2
- field public static final int SIM_ACTIVATION_RESULT_NOT_SUPPORTED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
@@ -42197,6 +42886,15 @@ package android.telephony.gsm {
}
+package android.telephony.ims {
+
+ public class ImsServiceBase extends android.app.Service {
+ ctor public ImsServiceBase();
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+}
+
package android.test {
public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
@@ -42541,6 +43239,7 @@ package android.test.mock {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public void clearWallpaper();
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createCredentialProtectedStorageContext();
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
@@ -42694,6 +43393,7 @@ package android.test.mock {
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public boolean canRequestPackageInstalls();
method public java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
@@ -42727,6 +43427,8 @@ package android.test.mock {
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public java.lang.String getInstallerPackageName(java.lang.String);
+ method public byte[] getInstantAppCookie();
+ method public int getInstantAppCookieMaxSize();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public int getIntentVerificationStatusAsUser(java.lang.String, int);
@@ -42763,6 +43465,7 @@ package android.test.mock {
method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
+ method public boolean isInstantApp();
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -42785,6 +43488,7 @@ package android.test.mock {
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public boolean setInstantAppCookie(byte[]);
method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
@@ -44736,6 +45440,15 @@ package android.transition {
method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
}
+ public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+ ctor public TransitionListenerAdapter();
+ method public void onTransitionCancel(android.transition.Transition);
+ method public void onTransitionEnd(android.transition.Transition);
+ method public void onTransitionPause(android.transition.Transition);
+ method public void onTransitionResume(android.transition.Transition);
+ method public void onTransitionStart(android.transition.Transition);
+ }
+
public class TransitionManager {
ctor public TransitionManager();
method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -45688,6 +46401,7 @@ package android.view {
method public boolean isValid();
method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
+ field public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
field public static final int FLAG_ROUND = 16; // 0x10
@@ -45938,6 +46652,7 @@ package android.view {
field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
field public static final int SOURCE_KEYBOARD = 257; // 0x101
field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_MOUSE_RELATIVE = 131076; // 0x20004
field public static final int SOURCE_STYLUS = 16386; // 0x4002
field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
@@ -47051,6 +47766,7 @@ package android.view {
ctor public View(android.content.Context, android.util.AttributeSet, int);
ctor public View(android.content.Context, android.util.AttributeSet, int, int);
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -47092,6 +47808,7 @@ package android.view {
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
+ method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -47110,6 +47827,7 @@ package android.view {
method public boolean dispatchNestedPrePerformAccessibilityAction(int, android.os.Bundle);
method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+ method public void dispatchPointerCaptureChanged(boolean);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
method public void dispatchProvideStructure(android.view.ViewStructure);
@@ -47148,7 +47866,8 @@ package android.view {
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public android.view.autofill.AutoFillType getAutoFillType();
- method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
+ method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate();
method public android.graphics.drawable.Drawable getBackground();
method public android.content.res.ColorStateList getBackgroundTintList();
method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -47175,6 +47894,7 @@ package android.view {
method public float getElevation();
method public boolean getFilterTouchesWhenObscured();
method public boolean getFitsSystemWindows();
+ method public int getFocusable();
method public java.util.ArrayList<android.view.View> getFocusables(int);
method public void getFocusedRect(android.graphics.Rect);
method public android.graphics.drawable.Drawable getForeground();
@@ -47290,6 +48010,7 @@ package android.view {
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -47354,6 +48075,7 @@ package android.view {
method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
+ method public boolean onCapturedPointerEvent(android.view.MotionEvent);
method public boolean onCheckIsTextEditor();
method protected void onConfigurationChanged(android.content.res.Configuration);
method protected void onCreateContextMenu(android.view.ContextMenu);
@@ -47383,6 +48105,7 @@ package android.view {
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
method protected void onOverScrolled(int, int, boolean, boolean);
+ method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
@@ -47425,6 +48148,7 @@ package android.view {
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -47435,6 +48159,7 @@ package android.view {
method public boolean requestFocus(int, android.graphics.Rect);
method public final boolean requestFocusFromTouch();
method public void requestLayout();
+ method public void requestPointerCapture();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
method public final void requestUnbufferedDispatch(android.view.MotionEvent);
@@ -47478,6 +48203,7 @@ package android.view {
method public void setFilterTouchesWhenObscured(boolean);
method public void setFitsSystemWindows(boolean);
method public void setFocusable(boolean);
+ method public void setFocusable(int);
method public void setFocusableInTouchMode(boolean);
method public void setFocusedByDefault(boolean);
method public void setForeground(android.graphics.drawable.Drawable);
@@ -47511,6 +48237,7 @@ package android.view {
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
+ method public void setOnCapturedPointerListener(android.view.View.OnCapturedPointerListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
@@ -47593,8 +48320,6 @@ package android.view {
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
- field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
- field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -47615,8 +48340,10 @@ package android.view {
field protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET;
field public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 2; // 0x2
field public static final int FIND_VIEWS_WITH_TEXT = 1; // 0x1
+ field public static final int FOCUSABLE = 1; // 0x1
field public static final int FOCUSABLES_ALL = 0; // 0x0
field public static final int FOCUSABLES_TOUCH_MODE = 1; // 0x1
+ field public static final int FOCUSABLE_AUTO = 16; // 0x10
field protected static final int[] FOCUSED_SELECTED_STATE_SET;
field protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
field protected static final int[] FOCUSED_STATE_SET;
@@ -47646,6 +48373,7 @@ package android.view {
field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field public static final int NOT_FOCUSABLE = 0; // 0x0
field public static final int NO_ID = -1; // 0xffffffff
field public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
field public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
@@ -47734,6 +48462,7 @@ package android.view {
public static class View.AccessibilityDelegate {
ctor public View.AccessibilityDelegate();
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -47780,6 +48509,10 @@ package android.view {
method public abstract void onViewDetachedFromWindow(android.view.View);
}
+ public static abstract interface View.OnCapturedPointerListener {
+ method public abstract boolean onCapturedPointer(android.view.View, android.view.MotionEvent);
+ }
+
public static abstract interface View.OnClickListener {
method public abstract void onClick(android.view.View);
}
@@ -47983,8 +48716,8 @@ package android.view {
method public int getPersistentDrawingCache();
method public boolean getTouchscreenBlocksFocus();
method public int indexOfChild(android.view.View);
- method public final void invalidateChild(android.view.View, android.graphics.Rect);
- method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
method public deprecated boolean isAnimationCacheEnabled();
method protected boolean isChildrenDrawingOrderEnabled();
@@ -48147,14 +48880,15 @@ package android.view {
method public abstract android.view.ViewParent getParentForAccessibility();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
- method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
- method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public abstract boolean isLayoutDirectionResolved();
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
+ method public default void onDescendantInvalidated(android.view.View, android.view.View);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
@@ -48222,7 +48956,7 @@ package android.view {
method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewStructure asyncNewChild(int);
- method public abstract android.view.ViewStructure asyncNewChild(int, int);
+ method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
method public abstract int getChildCount();
method public abstract android.os.Bundle getExtras();
method public abstract java.lang.CharSequence getHint();
@@ -48231,11 +48965,12 @@ package android.view {
method public abstract int getTextSelectionStart();
method public abstract boolean hasExtras();
method public abstract android.view.ViewStructure newChild(int);
- method public abstract android.view.ViewStructure newChild(int, int);
+ method public abstract android.view.ViewStructure newChild(int, int, int);
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
+ method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
method public abstract void setChecked(boolean);
method public abstract void setChildCount(int);
@@ -48258,6 +48993,7 @@ package android.view {
method public abstract void setTextStyle(float, int, int, int);
method public abstract void setTransformation(android.graphics.Matrix);
method public abstract void setVisibility(int);
+ field public static final int AUTO_FILL_FLAG_SANITIZED = 1; // 0x1
}
public final class ViewStub extends android.view.View {
@@ -48350,6 +49086,7 @@ package android.view {
method public boolean getAllowReturnTransitionOverlap();
method public final android.view.WindowManager.LayoutParams getAttributes();
method public final android.view.Window.Callback getCallback();
+ method public int getColorMode();
method public final android.view.Window getContainer();
method public android.transition.Scene getContentScene();
method public final android.content.Context getContext();
@@ -48406,6 +49143,7 @@ package android.view {
method public abstract void setChildDrawable(int, android.graphics.drawable.Drawable);
method public abstract void setChildInt(int, int);
method public void setClipToOutline(boolean);
+ method public void setColorMode(int);
method public void setContainer(android.view.Window);
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
@@ -48511,6 +49249,7 @@ package android.view {
method public abstract boolean onMenuItemSelected(int, android.view.MenuItem);
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
+ method public default void onPointerCaptureChanged(boolean);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
@@ -48605,9 +49344,11 @@ package android.view {
method public final int copyFrom(android.view.WindowManager.LayoutParams);
method public java.lang.String debug(java.lang.String);
method public int describeContents();
+ method public int getColorMode();
method public final java.lang.CharSequence getTitle();
method public final long getUserActivityTimeout();
method public static boolean mayUseInputMethod(int);
+ method public void setColorMode(int);
method public final void setTitle(java.lang.CharSequence);
method public final void setUserActivityTimeout(long);
method public void writeToParcel(android.os.Parcel, int);
@@ -48689,6 +49430,7 @@ package android.view {
field public static final int TYPE_APPLICATION = 2; // 0x2
field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
+ field public static final int TYPE_APPLICATION_OVERLAY = 2038; // 0x7f6
field public static final int TYPE_APPLICATION_PANEL = 1000; // 0x3e8
field public static final int TYPE_APPLICATION_STARTING = 3; // 0x3
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
@@ -48698,17 +49440,17 @@ package android.view {
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
- field public static final int TYPE_PHONE = 2002; // 0x7d2
- field public static final int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
+ field public static final deprecated int TYPE_PHONE = 2002; // 0x7d2
+ field public static final deprecated int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
field public static final int TYPE_PRIVATE_PRESENTATION = 2030; // 0x7ee
field public static final int TYPE_SEARCH_BAR = 2001; // 0x7d1
field public static final int TYPE_STATUS_BAR = 2000; // 0x7d0
field public static final int TYPE_STATUS_BAR_PANEL = 2014; // 0x7de
- field public static final int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
+ field public static final deprecated int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
field public static final int TYPE_SYSTEM_DIALOG = 2008; // 0x7d8
- field public static final int TYPE_SYSTEM_ERROR = 2010; // 0x7da
- field public static final int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
- field public static final int TYPE_TOAST = 2005; // 0x7d5
+ field public static final deprecated int TYPE_SYSTEM_ERROR = 2010; // 0x7da
+ field public static final deprecated int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
+ field public static final deprecated int TYPE_TOAST = 2005; // 0x7d5
field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
field public float alpha;
field public float buttonBrightness;
@@ -48844,6 +49586,7 @@ package android.view.accessibility {
method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
method public deprecated int getActions();
+ method public java.util.List<java.lang.String> getAvailableExtraData();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -48900,11 +49643,13 @@ package android.view.accessibility {
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
method public boolean refresh();
+ method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
method public deprecated void removeAction(int);
method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method public boolean removeChild(android.view.View);
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String>);
method public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
method public void setCanOpenPopup(boolean);
@@ -48987,6 +49732,9 @@ package android.view.accessibility {
field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
field public static final int FOCUS_INPUT = 1; // 0x1
field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -49068,6 +49816,7 @@ package android.view.accessibility {
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
+ method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -49477,6 +50226,14 @@ package android.view.autofill {
field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
}
+ public final class AutoFillManager {
+ method public void focusChanged(android.view.View, boolean);
+ method public void reset();
+ method public void valueChanged(android.view.View);
+ method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+ method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
+ }
+
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
method public static android.view.autofill.AutoFillType forList();
@@ -49509,8 +50266,9 @@ package android.view.autofill {
}
public static final class Dataset.Builder {
- ctor public Dataset.Builder(java.lang.CharSequence);
+ ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
method public android.view.autofill.Dataset build();
+ method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
}
@@ -49522,10 +50280,11 @@ package android.view.autofill {
}
public static final class FillResponse.Builder {
- ctor public FillResponse.Builder();
+ ctor public FillResponse.Builder(java.lang.String);
method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.view.autofill.FillResponse build();
+ method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
}
@@ -49534,13 +50293,6 @@ package android.view.autofill {
method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
}
- public static abstract class VirtualViewDelegate.Callback {
- ctor public VirtualViewDelegate.Callback();
- method public void onFocusChanged(int, boolean);
- method public void onNodeRemoved(int...);
- method public void onValueChanged(int);
- }
-
}
package android.view.inputmethod {
@@ -52408,8 +53160,6 @@ package android.widget {
method public void addHeaderView(android.view.View);
method public boolean areFooterDividersEnabled();
method public boolean areHeaderDividersEnabled();
- method protected android.view.View findViewTraversal(int);
- method protected android.view.View findViewWithTagTraversal(java.lang.Object);
method public android.widget.ListAdapter getAdapter();
method public deprecated long[] getCheckItemIds();
method public android.graphics.drawable.Drawable getDivider();
@@ -52675,6 +53425,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
+ method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();
@@ -53424,6 +54175,7 @@ package android.widget {
method public int getExtendedPaddingTop();
method public android.text.InputFilter[] getFilters();
method public java.lang.String getFontFeatureSettings();
+ method public java.lang.String getFontVariationSettings();
method public boolean getFreezesText();
method public int getGravity();
method public int getHighlightColor();
@@ -53533,6 +54285,7 @@ package android.widget {
method public void setExtractedText(android.view.inputmethod.ExtractedText);
method public void setFilters(android.text.InputFilter[]);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method protected boolean setFrame(int, int, int, int);
method public void setFreezesText(boolean);
method public void setGravity(int);
@@ -53642,6 +54395,7 @@ package android.widget {
method public void setIs24HourView(java.lang.Boolean);
method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+ method public boolean validateInput();
}
public static abstract interface TimePicker.OnTimeChangedListener {
@@ -54040,6 +54794,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -57334,12 +58090,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -57373,17 +58132,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -57400,6 +58165,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
@@ -65729,6 +66495,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -65739,7 +66508,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -65768,12 +66541,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/test-current.txt b/api/test-current.txt
index c2ae08194263..5d6f5d08646d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -118,6 +118,7 @@ package android {
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -203,7 +204,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed0 = 16844097; // 0x1010541
field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -349,6 +349,7 @@ package android {
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
+ field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
@@ -408,6 +409,7 @@ package android {
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
+ field public static final int colorMode = 16844108; // 0x101054c
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -738,6 +740,7 @@ package android {
field public static final int isScrollContainer = 16843342; // 0x101024e
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
+ field public static final int isolatedSplits = 16844109; // 0x101054d
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
@@ -1117,6 +1120,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
+ field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1266,6 +1270,8 @@ package android {
field public static final int targetId = 16843740; // 0x10103dc
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
+ field public static final int targetProcess = 16844097; // 0x1010541
+ field public static final int targetSandboxVersion = 16844110; // 0x101054e
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -2683,11 +2689,26 @@ package android {
package android.accessibilityservice {
+ public final class AccessibilityButtonController {
+ method public boolean isAccessibilityButtonAvailable();
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+ method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+ }
+
+ public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+ ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+ method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+ method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+ }
+
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public final void disableSelf();
method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+ method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
+ method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2779,6 +2800,7 @@ package android.accessibilityservice {
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2794,9 +2816,11 @@ package android.accessibilityservice {
field public static final int FEEDBACK_HAPTIC = 2; // 0x2
field public static final int FEEDBACK_SPOKEN = 1; // 0x1
field public static final int FEEDBACK_VISUAL = 8; // 0x8
+ field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -2808,6 +2832,22 @@ package android.accessibilityservice {
field public java.lang.String[] packageNames;
}
+ public final class FingerprintGestureController {
+ method public boolean isGestureDetectionAvailable();
+ method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+ method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+ field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+ field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+ field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+ field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+ }
+
+ public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+ ctor public FingerprintGestureController.FingerprintGestureCallback();
+ method public void onGesture(int);
+ method public void onGestureDetectionAvailabilityChanged(boolean);
+ }
+
public final class GestureDescription {
method public static long getMaxGestureDuration();
method public static int getMaxStrokeCount();
@@ -2885,7 +2925,7 @@ package android.accounts {
public class AccountManager {
method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
- method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+ method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -2894,7 +2934,7 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public static android.accounts.AccountManager get(android.content.Context);
- method public int getAccountVisibility(android.accounts.Account, int);
+ method public int getAccountVisibility(android.accounts.Account, java.lang.String);
method public android.accounts.Account[] getAccounts();
method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2905,9 +2945,9 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getPassword(android.accounts.Account);
method public java.lang.String getPreviousName(android.accounts.Account);
- method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -2921,7 +2961,7 @@ package android.accounts {
method public boolean removeAccountExplicitly(android.accounts.Account);
method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
- method public boolean setAccountVisibility(android.accounts.Account, int, int);
+ method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
method public void setPassword(android.accounts.Account, java.lang.String);
method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -2961,8 +3001,8 @@ package android.accounts {
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
- field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
- field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+ field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3066,8 +3106,10 @@ package android.animation {
public static abstract interface Animator.AnimatorListener {
method public abstract void onAnimationCancel(android.animation.Animator);
+ method public default void onAnimationEnd(android.animation.Animator, boolean);
method public abstract void onAnimationEnd(android.animation.Animator);
method public abstract void onAnimationRepeat(android.animation.Animator);
+ method public default void onAnimationStart(android.animation.Animator, boolean);
method public abstract void onAnimationStart(android.animation.Animator);
}
@@ -3103,6 +3145,8 @@ package android.animation {
method public void playSequentially(java.util.List<android.animation.Animator>);
method public void playTogether(android.animation.Animator...);
method public void playTogether(java.util.Collection<android.animation.Animator>);
+ method public void reverse();
+ method public void setCurrentPlayTime(long);
method public android.animation.AnimatorSet setDuration(long);
method public void setInterpolator(android.animation.TimeInterpolator);
method public void setStartDelay(long);
@@ -3548,6 +3592,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
+ method public boolean isActivityTransitionRunning();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
@@ -4517,6 +4562,7 @@ package android.app {
method public final boolean isInLayout();
method public final boolean isRemoving();
method public final boolean isResumed();
+ method public final boolean isStateSaved();
method public final boolean isVisible();
method public void onActivityCreated(android.os.Bundle);
method public void onActivityResult(int, int, android.content.Intent);
@@ -4688,6 +4734,7 @@ package android.app {
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+ method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
method public abstract void popBackStack();
@@ -4754,6 +4801,7 @@ package android.app {
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
method public abstract boolean isEmpty();
+ method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -4764,6 +4812,7 @@ package android.app {
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
method public abstract android.app.FragmentTransaction setTransition(int);
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -4781,6 +4830,7 @@ package android.app {
method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+ method public void addResults(android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnDestroy(android.app.Activity);
@@ -4805,6 +4855,7 @@ package android.app {
method public android.os.Bundle getBinderCounts();
method public android.content.ComponentName getComponentName();
method public android.content.Context getContext();
+ method public java.lang.String getProcessName();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
method public android.app.UiAutomation getUiAutomation(int);
@@ -5021,13 +5072,19 @@ package android.app {
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public int getBadgeIcon();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
+ method public java.lang.String getShortcutId();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
+ method public long getTimeout();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
field public static final java.lang.String CATEGORY_ALARM = "alarm";
field public static final java.lang.String CATEGORY_CALL = "call";
field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5053,8 +5110,10 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -5086,26 +5145,26 @@ package android.app {
field public static final int FLAG_NO_CLEAR = 32; // 0x20
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
- field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
- field public static final int PRIORITY_DEFAULT = 0; // 0x0
- field public static final int PRIORITY_HIGH = 1; // 0x1
- field public static final int PRIORITY_LOW = -1; // 0xffffffff
- field public static final int PRIORITY_MAX = 2; // 0x2
- field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
+ field public static final deprecated int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final deprecated int PRIORITY_MAX = 2; // 0x2
+ field public static final deprecated int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
field public android.app.Notification.Action[] actions;
- field public android.media.AudioAttributes audioAttributes;
+ field public deprecated android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
field public deprecated android.widget.RemoteViews contentView;
- field public int defaults;
+ field public deprecated int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
@@ -5114,16 +5173,16 @@ package android.app {
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
- field public int ledARGB;
- field public int ledOffMS;
- field public int ledOnMS;
- field public deprecated int number;
- field public int priority;
+ field public deprecated int ledARGB;
+ field public deprecated int ledOffMS;
+ field public deprecated int ledOnMS;
+ field public int number;
+ field public deprecated int priority;
field public android.app.Notification publicVersion;
- field public android.net.Uri sound;
+ field public deprecated android.net.Uri sound;
field public java.lang.CharSequence tickerText;
field public deprecated android.widget.RemoteViews tickerView;
- field public long[] vibrate;
+ field public deprecated long[] vibrate;
field public int visibility;
field public long when;
}
@@ -5198,12 +5257,14 @@ package android.app {
}
public static class Notification.Builder {
- ctor public Notification.Builder(android.content.Context);
+ ctor public Notification.Builder(android.content.Context, java.lang.String);
+ ctor public deprecated Notification.Builder(android.content.Context);
method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
method public android.app.Notification build();
+ method public android.app.Notification.Builder chooseBadgeIcon(int);
method public android.widget.RemoteViews createBigContentView();
method public android.widget.RemoteViews createContentView();
method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5217,6 +5278,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
+ method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -5225,7 +5287,7 @@ package android.app {
method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
- method public android.app.Notification.Builder setDefaults(int);
+ method public deprecated android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
@@ -5233,29 +5295,31 @@ package android.app {
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
- method public android.app.Notification.Builder setLights(int, int, int);
+ method public deprecated android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public deprecated android.app.Notification.Builder setNumber(int);
+ method public android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
- method public android.app.Notification.Builder setPriority(int);
+ method public deprecated android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+ method public android.app.Notification.Builder setShortcutId(java.lang.String);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
method public android.app.Notification.Builder setSmallIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setSortKey(java.lang.String);
- method public android.app.Notification.Builder setSound(android.net.Uri);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri);
method public deprecated android.app.Notification.Builder setSound(android.net.Uri, int);
- method public android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
+ method public deprecated android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
method public android.app.Notification.Builder setStyle(android.app.Notification.Style);
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+ method public android.app.Notification.Builder setTimeout(long);
method public android.app.Notification.Builder setUsesChronometer(boolean);
- method public android.app.Notification.Builder setVibrate(long[]);
+ method public deprecated android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
method public android.app.Notification.Builder setWhen(long);
}
@@ -5320,9 +5384,11 @@ package android.app {
public static class Notification.MessagingStyle extends android.app.Notification.Style {
ctor public Notification.MessagingStyle(java.lang.CharSequence);
+ method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message);
method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message);
method public java.lang.CharSequence getConversationTitle();
+ method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages();
method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages();
method public java.lang.CharSequence getUserDisplayName();
method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence);
@@ -5416,19 +5482,24 @@ package android.app {
method public boolean canBypassDnd();
method public boolean canShowBadge();
method public int describeContents();
+ method public void enableLights(boolean);
method public void enableVibration(boolean);
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public java.lang.String getGroup();
method public java.lang.String getId();
method public int getImportance();
+ method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
+ method public void setGroup(java.lang.String);
method public void setImportance(int);
- method public void setLights(boolean);
+ method public void setLightColor(int);
method public void setLockscreenVisibility(int);
method public void setShowBadge(boolean);
- method public void setSound(android.net.Uri);
+ method public void setSound(android.net.Uri, android.media.AudioAttributes);
method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
@@ -5437,6 +5508,17 @@ package android.app {
field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
}
+ public final class NotificationChannelGroup implements android.os.Parcelable {
+ ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor protected NotificationChannelGroup(android.os.Parcel);
+ method public int describeContents();
+ method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getId();
+ method public java.lang.CharSequence getName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
+ }
+
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
method public boolean areNotificationsEnabled();
@@ -5444,6 +5526,8 @@ package android.app {
method public void cancel(java.lang.String, int);
method public void cancelAll();
method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
@@ -5607,10 +5691,11 @@ package android.app {
}
public final class RemoteAction implements android.os.Parcelable {
- ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+ ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.RemoteAction clone();
method public int describeContents();
method public void dump(java.lang.String, java.io.PrintWriter);
+ method public android.app.PendingIntent getActionIntent();
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getTitle();
@@ -5618,10 +5703,6 @@ package android.app {
field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
}
- public static abstract interface RemoteAction.OnActionListener {
- method public abstract void onAction(android.app.RemoteAction);
- }
-
public final class RemoteInput implements android.os.Parcelable {
method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6129,6 +6210,7 @@ package android.app.admin {
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public android.content.Intent createAdminSupportIntent(java.lang.String);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
@@ -6137,16 +6219,18 @@ package android.app.admin {
method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
- method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
+ method public deprecated java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
- method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
+ method public deprecated java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
+ method public java.util.List<java.lang.String> getDelegatePackages(android.content.ComponentName, java.lang.String);
+ method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.lang.CharSequence getDeviceOwnerOrganizationName();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
@@ -6154,6 +6238,7 @@ package android.app.admin {
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
+ method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -6195,7 +6280,7 @@ package android.app.admin {
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isBackupServiceEnabled(android.content.ComponentName);
- method public boolean isCallerApplicationRestrictionsManagingPackage();
+ method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceManaged();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
@@ -6224,14 +6309,15 @@ package android.app.admin {
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
- method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public deprecated void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
- method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
+ method public deprecated void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
+ method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
@@ -6279,6 +6365,7 @@ package android.app.admin {
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+ field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6288,6 +6375,12 @@ package android.app.admin {
field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
+ field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+ field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
@@ -6295,6 +6388,7 @@ package android.app.admin {
field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+ field public static final java.lang.String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
@@ -6326,6 +6420,7 @@ package android.app.admin {
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
+ field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
field public static final int FLAG_EVICT_CE_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
@@ -6353,6 +6448,8 @@ package android.app.admin {
field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
+ field public static final java.lang.String POLICY_DISABLE_CAMERA = "policy_disable_camera";
+ field public static final java.lang.String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -6459,6 +6556,7 @@ package android.app.assist {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
method public android.view.autofill.AutoFillType getAutoFillType();
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -6890,6 +6988,7 @@ package android.appwidget {
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders();
method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(android.os.UserHandle);
method public static android.appwidget.AppWidgetManager getInstance(android.content.Context);
+ method public boolean isRequestPinAppWidgetSupported();
method public void notifyAppWidgetViewDataChanged(int[], int);
method public void notifyAppWidgetViewDataChanged(int, int);
method public void partiallyUpdateAppWidget(int[], android.widget.RemoteViews);
@@ -7890,6 +7989,65 @@ package android.bluetooth.le {
}
+package android.companion {
+
+ public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+ }
+
+ public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+ method public android.companion.AssociationRequest<F> build();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+ method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+ method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+ method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+ }
+
+ public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothDeviceFilter.Builder {
+ ctor public BluetoothDeviceFilter.Builder();
+ method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+ method public android.companion.BluetoothDeviceFilter build();
+ method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+ method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ }
+
+ public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+ }
+
+ public static final class BluetoothLEDeviceFilter.Builder {
+ ctor public BluetoothLEDeviceFilter.Builder();
+ method public android.companion.BluetoothLEDeviceFilter build();
+ method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+ method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+ }
+
+ public final class CompanionDeviceManager {
+ method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+ field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+ }
+
+ public static abstract class CompanionDeviceManager.Callback {
+ ctor public CompanionDeviceManager.Callback();
+ method public abstract void onDeviceFound(android.content.IntentSender);
+ method public abstract void onFailure(java.lang.CharSequence);
+ }
+
+ public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+ }
+
+}
+
package android.content {
public abstract class AbstractThreadedSyncAdapter {
@@ -8031,6 +8189,7 @@ package android.content {
method public java.lang.CharSequence getLabel();
method public java.lang.String getMimeType(int);
method public int getMimeTypeCount();
+ method public long getTimestamp();
method public boolean hasMimeType(java.lang.String);
method public void setExtras(android.os.PersistableBundle);
method public void writeToParcel(android.os.Parcel, int);
@@ -8378,6 +8537,7 @@ package android.content {
method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public abstract deprecated void clearWallpaper() throws java.io.IOException;
method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public abstract android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Context createDeviceProtectedStorageContext();
method public abstract android.content.Context createDisplayContext(android.view.Display);
method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -8502,6 +8662,7 @@ package android.content {
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -8577,6 +8738,7 @@ package android.content {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public deprecated void clearWallpaper() throws java.io.IOException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -8886,6 +9048,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
+ field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
@@ -9027,6 +9190,7 @@ package android.content {
field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
+ field public static final java.lang.String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -9037,6 +9201,10 @@ package android.content {
field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+ field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+ field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+ field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9073,6 +9241,7 @@ package android.content {
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
+ field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN";
field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -9600,7 +9769,10 @@ package android.content.pm {
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
method public final int getThemeResource();
- field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
+ field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
+ field public static final int COLOR_MODE_HDR = 2; // 0x2
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT = 1; // 0x1
+ field public static final int CONFIG_COLOR_MODE = 16384; // 0x4000
field public static final int CONFIG_DENSITY = 4096; // 0x1000
field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -9661,6 +9833,7 @@ package android.content.pm {
field public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11; // 0xb
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
+ field public int colorMode;
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
@@ -9759,6 +9932,7 @@ package android.content.pm {
field public int requiresSmallestWidthDp;
field public java.lang.String[] sharedLibraryFiles;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public int targetSdkVersion;
@@ -9766,6 +9940,7 @@ package android.content.pm {
field public int theme;
field public int uiOptions;
field public int uid;
+ field public java.lang.String volumeUuid;
}
public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator {
@@ -9841,9 +10016,11 @@ package android.content.pm {
field public boolean handleProfiling;
field public java.lang.String publicSourceDir;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitNames;
field public java.lang.String[] splitPublicSourceDirs;
field public java.lang.String[] splitSourceDirs;
field public java.lang.String targetPackage;
+ field public java.lang.String targetProcess;
}
public class LabeledIntent extends android.content.Intent {
@@ -9894,7 +10071,8 @@ package android.content.pm {
method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
- field public static final java.lang.String ACTION_CONFIRM_PIN_ITEM = "android.content.pm.action.CONFIRM_PIN_ITEM";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
+ field public static final java.lang.String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
}
@@ -10092,6 +10270,7 @@ package android.content.pm {
method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public abstract boolean canRequestPackageInstalls();
method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
@@ -10124,6 +10303,8 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
+ method public abstract byte[] getInstantAppCookie();
+ method public abstract int getInstantAppCookieMaxSize();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -10157,6 +10338,8 @@ package android.content.pm {
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
+ method public abstract boolean isInstantApp();
+ method public abstract boolean isPermissionReviewModeEnabled();
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -10176,6 +10359,7 @@ package android.content.pm {
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public abstract boolean setInstantAppCookie(byte[]);
method public abstract void verifyPendingInstall(int, int);
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
@@ -10206,6 +10390,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
@@ -10261,6 +10446,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -10643,16 +10829,16 @@ package android.content.res {
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
method public void writeToParcel(android.os.Parcel, int);
- field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
- field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
- field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
- field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
- field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
- field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_MASK = 12; // 0xc
+ field public static final int COLOR_MODE_HDR_NO = 4; // 0x4
+ field public static final int COLOR_MODE_HDR_SHIFT = 2; // 0x2
+ field public static final int COLOR_MODE_HDR_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_HDR_YES = 8; // 0x8
+ field public static final int COLOR_MODE_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+ field public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 2; // 0x2
field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -10718,7 +10904,7 @@ package android.content.res {
field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
- field public int colorimetry;
+ field public int colorMode;
field public int densityDpi;
field public float fontScale;
field public int hardKeyboardHidden;
@@ -10838,6 +11024,7 @@ package android.content.res {
method public int getDimensionPixelSize(int, int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public float getFloat(int, float);
+ method public android.graphics.Typeface getFont(int);
method public float getFraction(int, int, int, float);
method public int getIndex(int);
method public int getIndexCount();
@@ -12705,6 +12892,7 @@ package android.graphics {
method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
method public float getFontSpacing();
+ method public java.lang.String getFontVariationSettings();
method public int getHinting();
method public float getLetterSpacing();
method public android.graphics.MaskFilter getMaskFilter();
@@ -12762,6 +12950,7 @@ package android.graphics {
method public void setFilterBitmap(boolean);
method public void setFlags(int);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method public void setHinting(int);
method public void setLetterSpacing(float);
method public void setLinearText(boolean);
@@ -13694,6 +13883,23 @@ package android.graphics.drawable {
method public void addLevel(int, int, android.graphics.drawable.Drawable);
}
+ public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+ ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public void draw(android.graphics.Canvas);
+ method public android.graphics.drawable.Drawable getBackground();
+ method public android.graphics.drawable.Drawable getForeground();
+ method public android.graphics.Path getIconMask();
+ method public int getOpacity();
+ method public void invalidateDrawable(android.graphics.drawable.Drawable);
+ method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+ method public void setAlpha(int);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setOpacity(int);
+ method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+ field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
+ field public static final float MASK_SIZE = 100.0f;
+ }
+
public class NinePatchDrawable extends android.graphics.drawable.Drawable {
ctor public deprecated NinePatchDrawable(android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
@@ -14193,9 +14399,10 @@ package android.hardware {
method public int getWidth();
method public boolean isDestroyed();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BLOB = 33; // 0x21
field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
field public static final int RGBA_8888 = 1; // 0x1
- field public static final int RGBA_FP16 = 5; // 0x5
+ field public static final int RGBA_FP16 = 22; // 0x16
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
@@ -14216,6 +14423,7 @@ package android.hardware {
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getHighestDirectReportRateLevel();
method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
@@ -14229,6 +14437,7 @@ package android.hardware {
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isAdditionalInfoSupported();
+ method public boolean isDirectChannelTypeSupported(int);
method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
@@ -14306,6 +14515,17 @@ package android.hardware {
field public final int type;
}
+ public final class SensorDirectChannel implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean isValid();
+ field public static final int RATE_FAST = 2; // 0x2
+ field public static final int RATE_NORMAL = 1; // 0x1
+ field public static final int RATE_STOP = 0; // 0x0
+ field public static final int RATE_VERY_FAST = 3; // 0x3
+ field public static final int TYPE_ASHMEM = 1; // 0x1
+ field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -14337,6 +14557,9 @@ package android.hardware {
public abstract class SensorManager {
method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile);
+ method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer);
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
@@ -14466,7 +14689,7 @@ package android.hardware.camera2 {
method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void close();
- method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void finalizeOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isReprocessable();
@@ -14881,6 +15104,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -14960,6 +15184,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
+ field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
@@ -15107,10 +15332,12 @@ package android.hardware.camera2.params {
ctor public OutputConfiguration(android.view.Surface);
ctor public OutputConfiguration(int, android.view.Surface);
ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
+ method public void addSurface(android.view.Surface);
method public int describeContents();
+ method public void enableSurfaceSharing();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
- method public void setDeferredSurface(android.view.Surface);
+ method public java.util.List<android.view.Surface> getSurfaces();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -15179,6 +15406,7 @@ package android.hardware.display {
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
+ field public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
@@ -20395,6 +20623,7 @@ package android.media {
method public int getContentType();
method public int getFlags();
method public int getUsage();
+ method public static int getVolumeControlStream(android.media.AudioAttributes);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -20404,7 +20633,7 @@ package android.media {
field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
- field public static final int FLAG_LOW_LATENCY = 256; // 0x100
+ field public static final deprecated int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20845,6 +21074,7 @@ package android.media {
method protected deprecated int getNativeFrameCount();
method public static int getNativeOutputSampleRate(int);
method public int getNotificationMarkerPosition();
+ method public int getPerformanceMode();
method public int getPlayState();
method public int getPlaybackHeadPosition();
method public android.media.PlaybackParams getPlaybackParams();
@@ -20891,6 +21121,9 @@ package android.media {
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
field public static final int MODE_STATIC = 0; // 0x0
field public static final int MODE_STREAM = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_LOW_LATENCY = 1; // 0x1
+ field public static final int PERFORMANCE_MODE_NONE = 0; // 0x0
+ field public static final int PERFORMANCE_MODE_POWER_SAVING = 2; // 0x2
field public static final int PLAYSTATE_PAUSED = 2; // 0x2
field public static final int PLAYSTATE_PLAYING = 3; // 0x3
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
@@ -20908,6 +21141,7 @@ package android.media {
method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioTrack.Builder setPerformanceMode(int);
method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
}
@@ -20922,6 +21156,40 @@ package android.media {
method public default void onRoutingChanged(android.media.AudioRouting);
}
+ public final class BufferingParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getInitialBufferingMode();
+ method public int getInitialBufferingWatermarkKB();
+ method public int getInitialBufferingWatermarkMs();
+ method public int getRebufferingMode();
+ method public int getRebufferingWatermarkHighKB();
+ method public int getRebufferingWatermarkHighMs();
+ method public int getRebufferingWatermarkLowKB();
+ method public int getRebufferingWatermarkLowMs();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+ field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+ field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+ field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+ field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+ }
+
+ public static class BufferingParams.Builder {
+ ctor public BufferingParams.Builder();
+ ctor public BufferingParams.Builder(android.media.BufferingParams);
+ method public android.media.BufferingParams build();
+ method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+ method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingMode(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+ method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -21274,6 +21542,7 @@ package android.media {
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -22066,6 +22335,7 @@ package android.media {
public final class MediaMuxer {
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
+ ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
method public int addTrack(android.media.MediaFormat);
method public void release();
method public void setLocation(float, float);
@@ -22076,6 +22346,7 @@ package android.media {
}
public static final class MediaMuxer.OutputFormat {
+ field public static final int MUXER_OUTPUT_3GPP = 2; // 0x2
field public static final int MUXER_OUTPUT_MPEG_4 = 0; // 0x0
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
@@ -22094,8 +22365,14 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
+ method public android.media.BufferingParams getBufferingParams();
method public int getCurrentPosition();
+ method public android.media.BufferingParams getDefaultBufferingParams();
+ method public android.media.MediaPlayer.DrmInfo getDrmInfo();
+ method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
+ method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
@@ -22108,8 +22385,12 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
+ method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
+ method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
+ method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
method public void reset();
+ method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
@@ -22117,6 +22398,7 @@ package android.media {
method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public deprecated void setAudioStreamType(int);
method public void setAuxEffectSendLevel(float);
+ method public void setBufferingParams(android.media.BufferingParams);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -22125,10 +22407,15 @@ package android.media {
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
+ method public void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void setLooping(boolean);
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
+ method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
+ method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
@@ -22171,6 +22458,16 @@ package android.media {
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
+ public static final class MediaPlayer.DrmInfo {
+ method public java.lang.String[] getMimes();
+ method public java.util.Map<java.util.UUID, byte[]> getPssh();
+ method public java.util.UUID[] getSupportedSchemes();
+ }
+
+ public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.NoDrmSchemeException(java.lang.String);
+ }
+
public static abstract interface MediaPlayer.OnBufferingUpdateListener {
method public abstract void onBufferingUpdate(android.media.MediaPlayer, int);
}
@@ -22179,6 +22476,19 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
+ public static abstract class MediaPlayer.OnDrmConfigCallback {
+ ctor public MediaPlayer.OnDrmConfigCallback();
+ method public void onDrmConfig(android.media.MediaPlayer);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmInfoListener {
+ method public abstract void onDrmInfo(android.media.MediaPlayer, android.media.MediaPlayer.DrmInfo);
+ }
+
+ public static abstract interface MediaPlayer.OnDrmPreparedListener {
+ method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
+ }
+
public static abstract interface MediaPlayer.OnErrorListener {
method public abstract boolean onError(android.media.MediaPlayer, int, int);
}
@@ -22207,6 +22517,10 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
+ public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
+ ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
+ }
+
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {
method public int describeContents();
method public android.media.MediaFormat getFormat();
@@ -23453,6 +23767,8 @@ package android.media.session {
public final class MediaController {
ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+ method public void addQueueItem(android.media.MediaDescription);
+ method public void addQueueItem(android.media.MediaDescription, int);
method public void adjustVolume(int, int);
method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
method public android.os.Bundle getExtras();
@@ -23471,6 +23787,8 @@ package android.media.session {
method public boolean isShuffleModeEnabled();
method public void registerCallback(android.media.session.MediaController.Callback);
method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+ method public void removeQueueItem(android.media.MediaDescription);
+ method public void removeQueueItemAt(int);
method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void setVolumeTo(int, int);
method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -23548,11 +23866,14 @@ package android.media.session {
method public void setSessionActivity(android.app.PendingIntent);
method public void setShuffleModeEnabled(boolean);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class MediaSession.Callback {
ctor public MediaSession.Callback();
+ method public void onAddQueueItem(android.media.MediaDescription);
+ method public void onAddQueueItem(android.media.MediaDescription, int);
method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void onCustomAction(java.lang.String, android.os.Bundle);
method public void onFastForward();
@@ -23566,6 +23887,8 @@ package android.media.session {
method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+ method public void onRemoveQueueItem(android.media.MediaDescription);
+ method public void onRemoveQueueItemAt(int);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -23723,6 +24046,31 @@ package android.media.tv {
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
+ public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+ field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+ field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+ field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+ field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+ field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+ field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+ field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ }
+
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
}
@@ -23805,44 +24153,70 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
- field public static final java.lang.String COLUMN_PREVIEW_DURATION = "preview_duration";
- field public static final java.lang.String COLUMN_PREVIEW_INTENT_URI = "preview_intent_uri";
- field public static final java.lang.String COLUMN_PREVIEW_LAST_PLAYBACK_POSITION = "preview_last_playback_position";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_PREVIEW_WEIGHT = "preview_weight";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs.Genres {
@@ -23868,37 +24242,15 @@ package android.media.tv {
field public static final java.lang.String TRAVEL = "TRAVEL";
}
- public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
- field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
- field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
- field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
- field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
- field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
- field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
- field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
- field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
- field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
field public static final android.net.Uri CONTENT_URI;
@@ -23953,10 +24305,13 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24426,6 +24781,7 @@ package android.net {
method public android.net.Network getBoundNetworkForProcess();
method public android.net.ProxyInfo getDefaultProxy();
method public android.net.LinkProperties getLinkProperties(android.net.Network);
+ method public int getMultipathPreference(android.net.Network);
method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
method public deprecated android.net.NetworkInfo getNetworkInfo(int);
method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -24465,6 +24821,9 @@ package android.net {
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final java.lang.String EXTRA_REASON = "reason";
+ field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+ field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+ field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -25418,6 +25777,7 @@ package android.net.wifi {
field public java.util.BitSet allowedProtocols;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public int networkId;
field public java.lang.String preSharedKey;
field public int priority;
@@ -25485,6 +25845,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -25498,6 +25859,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -25550,6 +25912,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -25562,6 +25925,7 @@ package android.net.wifi {
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -25573,9 +25937,11 @@ package android.net.wifi {
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
+ method public boolean removePasspointConfiguration(java.lang.String);
method public boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
@@ -25583,6 +25949,10 @@ package android.net.wifi {
method public boolean startScan();
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int ERROR_AUTHENTICATING = 1; // 0x1
@@ -25590,6 +25960,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
@@ -25774,6 +26156,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentififer();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnysOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -29315,6 +29932,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+ field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -30037,6 +30655,7 @@ package android.os {
method public final android.util.SizeF readSizeF();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
+ method public final android.util.SparseIntArray readSparseIntArray();
method public final java.lang.String readString();
method public final void readStringArray(java.lang.String[]);
method public final void readStringList(java.util.List<java.lang.String>);
@@ -30081,6 +30700,7 @@ package android.os {
method public final void writeSizeF(android.util.SizeF);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
+ method public final void writeSparseIntArray(android.util.SparseIntArray);
method public final void writeString(java.lang.String);
method public final void writeStringArray(java.lang.String[]);
method public final void writeStringList(java.util.List<java.lang.String>);
@@ -30839,6 +31459,7 @@ package android.preference {
method public android.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
method public android.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
method public int getOrder();
+ method public android.preference.PreferenceGroup getParent();
method protected boolean getPersistedBoolean(boolean);
method protected float getPersistedFloat(float);
method protected int getPersistedInt(int);
@@ -32812,7 +33433,7 @@ package android.provider {
ctor public ContactsContract.Intents();
field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
- field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+ field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32925,7 +33546,6 @@ package android.provider {
field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
field public static final java.lang.String STATUS = "status";
field public static final int STATUS_BUSY = 1; // 0x1
- field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
field public static final int STATUS_EMPTY = 2; // 0x2
field public static final int STATUS_NORMAL = 0; // 0x0
}
@@ -33170,7 +33790,6 @@ package android.provider {
method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public android.content.res.AssetFileDescriptor openTypedDocument(java.lang.String, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
- method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
method public android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], android.os.Bundle) throws java.io.FileNotFoundException;
@@ -33559,6 +34178,7 @@ package android.provider {
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
@@ -33577,6 +34197,7 @@ package android.provider {
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_EXTERNAL_SOURCES = "android.settings.action.MANAGE_EXTERNAL_SOURCES";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -33612,8 +34233,10 @@ package android.provider {
field public static final java.lang.String AUTHORITY = "settings";
field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+ field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -33724,7 +34347,7 @@ package android.provider {
field public static final java.lang.String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
- field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+ field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
field public static final java.lang.String LOCATION_MODE = "location_mode";
field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
@@ -34281,6 +34904,8 @@ package android.provider {
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DELETED = "deleted";
@@ -34288,6 +34913,7 @@ package android.provider {
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -34295,6 +34921,7 @@ package android.provider {
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+ field public static final java.lang.String RESTORED = "restored";
field public static final java.lang.String SOURCE_DATA = "source_data";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -35499,6 +36126,18 @@ package android.security {
package android.security.keystore {
+ public abstract class AttestationUtils {
+ method public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, int[], 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
+ }
+
+ public class DeviceIdAttestationException extends java.lang.Exception {
+ ctor public DeviceIdAttestationException(java.lang.String);
+ ctor public DeviceIdAttestationException(java.lang.String, java.lang.Throwable);
+ }
+
public class KeyExpiredException extends java.security.InvalidKeyException {
ctor public KeyExpiredException();
ctor public KeyExpiredException(java.lang.String);
@@ -35674,21 +36313,22 @@ package android.service.autofill {
method public void onConnected();
method public void onDisconnected();
method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
- field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
- field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
+ method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class FillCallback {
+ public final class FillCallback implements android.os.Parcelable {
+ method public int describeContents();
method public void onFailure(java.lang.CharSequence);
method public void onSuccess(android.view.autofill.FillResponse);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
}
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
- method public void onSuccess(android.view.autofill.AutoFillId[]);
+ method public void onSuccess();
}
}
@@ -35965,8 +36605,9 @@ package android.service.notification {
method public void deleteNotificationChannel(java.lang.String, java.lang.String);
method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+ method public final void unsnoozeNotification(java.lang.String);
method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -35982,6 +36623,7 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+ method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
@@ -36000,8 +36642,6 @@ package android.service.notification {
method public final void setNotificationsShown(java.lang.String[]);
method public final void snoozeNotification(java.lang.String, java.lang.String);
method public final void snoozeNotification(java.lang.String, long);
- method public final void snoozeNotification(java.lang.String);
- method public final void unsnoozeNotification(java.lang.String);
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -36026,9 +36666,9 @@ package android.service.notification {
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_TIMEOUT = 19; // 0x13
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -38112,6 +38752,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
@@ -38727,6 +39368,7 @@ package android.telephony {
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
+ method public java.lang.String getVisualVoicemailPackageName(android.telecom.PhoneAccountHandle);
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -38747,6 +39389,7 @@ package android.telephony {
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
+ method public boolean sendDialerCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
@@ -38779,6 +39422,7 @@ package android.telephony {
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+ field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
@@ -38787,6 +39431,7 @@ package android.telephony {
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
+ field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -39332,6 +39977,7 @@ package android.test.mock {
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public void clearWallpaper();
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -39480,6 +40126,7 @@ package android.test.mock {
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public boolean canRequestPackageInstalls();
method public java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
@@ -39513,6 +40160,8 @@ package android.test.mock {
method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
+ method public byte[] getInstantAppCookie();
+ method public int getInstantAppCookieMaxSize();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -39545,6 +40194,8 @@ package android.test.mock {
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
+ method public boolean isInstantApp();
+ method public boolean isPermissionReviewModeEnabled();
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -39564,6 +40215,7 @@ package android.test.mock {
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public boolean setInstantAppCookie(byte[]);
method public void verifyPendingInstall(int, int);
}
@@ -41512,6 +42164,15 @@ package android.transition {
method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
}
+ public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+ ctor public TransitionListenerAdapter();
+ method public void onTransitionCancel(android.transition.Transition);
+ method public void onTransitionEnd(android.transition.Transition);
+ method public void onTransitionPause(android.transition.Transition);
+ method public void onTransitionResume(android.transition.Transition);
+ method public void onTransitionStart(android.transition.Transition);
+ }
+
public class TransitionManager {
ctor public TransitionManager();
method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -42628,6 +43289,7 @@ package android.view {
method public boolean isValid();
method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
+ field public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 32; // 0x20
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
field public static final int FLAG_ROUND = 16; // 0x10
@@ -42878,6 +43540,7 @@ package android.view {
field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
field public static final int SOURCE_KEYBOARD = 257; // 0x101
field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_MOUSE_RELATIVE = 131076; // 0x20004
field public static final int SOURCE_STYLUS = 16386; // 0x4002
field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
@@ -43993,6 +44656,7 @@ package android.view {
ctor public View(android.content.Context, android.util.AttributeSet, int);
ctor public View(android.content.Context, android.util.AttributeSet, int, int);
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -44034,6 +44698,7 @@ package android.view {
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
+ method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -44052,6 +44717,7 @@ package android.view {
method public boolean dispatchNestedPrePerformAccessibilityAction(int, android.os.Bundle);
method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+ method public void dispatchPointerCaptureChanged(boolean);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
method public void dispatchProvideStructure(android.view.ViewStructure);
@@ -44090,7 +44756,8 @@ package android.view {
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public android.view.autofill.AutoFillType getAutoFillType();
- method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+ method public android.view.autofill.AutoFillValue getAutoFillValue();
+ method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate();
method public android.graphics.drawable.Drawable getBackground();
method public android.content.res.ColorStateList getBackgroundTintList();
method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -44117,6 +44784,7 @@ package android.view {
method public float getElevation();
method public boolean getFilterTouchesWhenObscured();
method public boolean getFitsSystemWindows();
+ method public int getFocusable();
method public java.util.ArrayList<android.view.View> getFocusables(int);
method public void getFocusedRect(android.graphics.Rect);
method public android.graphics.drawable.Drawable getForeground();
@@ -44233,6 +44901,7 @@ package android.view {
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -44297,6 +44966,7 @@ package android.view {
method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
+ method public boolean onCapturedPointerEvent(android.view.MotionEvent);
method public boolean onCheckIsTextEditor();
method protected void onConfigurationChanged(android.content.res.Configuration);
method protected void onCreateContextMenu(android.view.ContextMenu);
@@ -44326,6 +44996,7 @@ package android.view {
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
method protected void onOverScrolled(int, int, boolean, boolean);
+ method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
@@ -44368,6 +45039,7 @@ package android.view {
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -44378,6 +45050,7 @@ package android.view {
method public boolean requestFocus(int, android.graphics.Rect);
method public final boolean requestFocusFromTouch();
method public void requestLayout();
+ method public void requestPointerCapture();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
method public final void requestUnbufferedDispatch(android.view.MotionEvent);
@@ -44421,6 +45094,7 @@ package android.view {
method public void setFilterTouchesWhenObscured(boolean);
method public void setFitsSystemWindows(boolean);
method public void setFocusable(boolean);
+ method public void setFocusable(int);
method public void setFocusableInTouchMode(boolean);
method public void setFocusedByDefault(boolean);
method public void setForeground(android.graphics.drawable.Drawable);
@@ -44454,6 +45128,7 @@ package android.view {
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
+ method public void setOnCapturedPointerListener(android.view.View.OnCapturedPointerListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
@@ -44536,8 +45211,6 @@ package android.view {
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
- field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
- field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44558,8 +45231,10 @@ package android.view {
field protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET;
field public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 2; // 0x2
field public static final int FIND_VIEWS_WITH_TEXT = 1; // 0x1
+ field public static final int FOCUSABLE = 1; // 0x1
field public static final int FOCUSABLES_ALL = 0; // 0x0
field public static final int FOCUSABLES_TOUCH_MODE = 1; // 0x1
+ field public static final int FOCUSABLE_AUTO = 16; // 0x10
field protected static final int[] FOCUSED_SELECTED_STATE_SET;
field protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
field protected static final int[] FOCUSED_STATE_SET;
@@ -44589,6 +45264,7 @@ package android.view {
field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field public static final int NOT_FOCUSABLE = 0; // 0x0
field public static final int NO_ID = -1; // 0xffffffff
field public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
field public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
@@ -44677,6 +45353,7 @@ package android.view {
public static class View.AccessibilityDelegate {
ctor public View.AccessibilityDelegate();
+ method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -44723,6 +45400,10 @@ package android.view {
method public abstract void onViewDetachedFromWindow(android.view.View);
}
+ public static abstract interface View.OnCapturedPointerListener {
+ method public abstract boolean onCapturedPointer(android.view.View, android.view.MotionEvent);
+ }
+
public static abstract interface View.OnClickListener {
method public abstract void onClick(android.view.View);
}
@@ -44930,8 +45611,8 @@ package android.view {
method public int getPersistentDrawingCache();
method public boolean getTouchscreenBlocksFocus();
method public int indexOfChild(android.view.View);
- method public final void invalidateChild(android.view.View, android.graphics.Rect);
- method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
method public deprecated boolean isAnimationCacheEnabled();
method protected boolean isChildrenDrawingOrderEnabled();
@@ -45094,14 +45775,15 @@ package android.view {
method public abstract android.view.ViewParent getParentForAccessibility();
method public abstract int getTextAlignment();
method public abstract int getTextDirection();
- method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
- method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+ method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
+ method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
method public abstract boolean isLayoutDirectionResolved();
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
+ method public default void onDescendantInvalidated(android.view.View, android.view.View);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
@@ -45169,7 +45851,7 @@ package android.view {
method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewStructure asyncNewChild(int);
- method public abstract android.view.ViewStructure asyncNewChild(int, int);
+ method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
method public abstract int getChildCount();
method public abstract android.os.Bundle getExtras();
method public abstract java.lang.CharSequence getHint();
@@ -45178,11 +45860,12 @@ package android.view {
method public abstract int getTextSelectionStart();
method public abstract boolean hasExtras();
method public abstract android.view.ViewStructure newChild(int);
- method public abstract android.view.ViewStructure newChild(int, int);
+ method public abstract android.view.ViewStructure newChild(int, int, int);
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
+ method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
method public abstract void setChecked(boolean);
method public abstract void setChildCount(int);
@@ -45205,6 +45888,7 @@ package android.view {
method public abstract void setTextStyle(float, int, int, int);
method public abstract void setTransformation(android.graphics.Matrix);
method public abstract void setVisibility(int);
+ field public static final int AUTO_FILL_FLAG_SANITIZED = 1; // 0x1
}
public final class ViewStub extends android.view.View {
@@ -45297,6 +45981,7 @@ package android.view {
method public boolean getAllowReturnTransitionOverlap();
method public final android.view.WindowManager.LayoutParams getAttributes();
method public final android.view.Window.Callback getCallback();
+ method public int getColorMode();
method public final android.view.Window getContainer();
method public android.transition.Scene getContentScene();
method public final android.content.Context getContext();
@@ -45353,6 +46038,7 @@ package android.view {
method public abstract void setChildDrawable(int, android.graphics.drawable.Drawable);
method public abstract void setChildInt(int, int);
method public void setClipToOutline(boolean);
+ method public void setColorMode(int);
method public void setContainer(android.view.Window);
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
@@ -45457,6 +46143,7 @@ package android.view {
method public abstract boolean onMenuItemSelected(int, android.view.MenuItem);
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
+ method public default void onPointerCaptureChanged(boolean);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
@@ -45551,8 +46238,10 @@ package android.view {
method public final int copyFrom(android.view.WindowManager.LayoutParams);
method public java.lang.String debug(java.lang.String);
method public int describeContents();
+ method public int getColorMode();
method public final java.lang.CharSequence getTitle();
method public static boolean mayUseInputMethod(int);
+ method public void setColorMode(int);
method public final void setTitle(java.lang.CharSequence);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALPHA_CHANGED = 128; // 0x80
@@ -45633,6 +46322,7 @@ package android.view {
field public static final int TYPE_APPLICATION = 2; // 0x2
field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
+ field public static final int TYPE_APPLICATION_OVERLAY = 2038; // 0x7f6
field public static final int TYPE_APPLICATION_PANEL = 1000; // 0x3e8
field public static final int TYPE_APPLICATION_STARTING = 3; // 0x3
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
@@ -45642,17 +46332,17 @@ package android.view {
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
- field public static final int TYPE_PHONE = 2002; // 0x7d2
- field public static final int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
+ field public static final deprecated int TYPE_PHONE = 2002; // 0x7d2
+ field public static final deprecated int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
field public static final int TYPE_PRIVATE_PRESENTATION = 2030; // 0x7ee
field public static final int TYPE_SEARCH_BAR = 2001; // 0x7d1
field public static final int TYPE_STATUS_BAR = 2000; // 0x7d0
field public static final int TYPE_STATUS_BAR_PANEL = 2014; // 0x7de
- field public static final int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
+ field public static final deprecated int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
field public static final int TYPE_SYSTEM_DIALOG = 2008; // 0x7d8
- field public static final int TYPE_SYSTEM_ERROR = 2010; // 0x7da
- field public static final int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
- field public static final int TYPE_TOAST = 2005; // 0x7d5
+ field public static final deprecated int TYPE_SYSTEM_ERROR = 2010; // 0x7da
+ field public static final deprecated int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
+ field public static final deprecated int TYPE_TOAST = 2005; // 0x7d5
field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
field public float alpha;
field public float buttonBrightness;
@@ -45788,6 +46478,7 @@ package android.view.accessibility {
method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
method public deprecated int getActions();
+ method public java.util.List<java.lang.String> getAvailableExtraData();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -45844,11 +46535,13 @@ package android.view.accessibility {
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
method public boolean refresh();
+ method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
method public deprecated void removeAction(int);
method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method public boolean removeChild(android.view.View);
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String>);
method public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
method public void setCanOpenPopup(boolean);
@@ -45932,6 +46625,9 @@ package android.view.accessibility {
field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
field public static final int FOCUS_INPUT = 1; // 0x1
field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -46013,6 +46709,7 @@ package android.view.accessibility {
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
+ method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -46423,6 +47120,14 @@ package android.view.autofill {
field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
}
+ public final class AutoFillManager {
+ method public void focusChanged(android.view.View, boolean);
+ method public void reset();
+ method public void valueChanged(android.view.View);
+ method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+ method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
+ }
+
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
method public static android.view.autofill.AutoFillType forList();
@@ -46455,8 +47160,9 @@ package android.view.autofill {
}
public static final class Dataset.Builder {
- ctor public Dataset.Builder(java.lang.CharSequence);
+ ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
method public android.view.autofill.Dataset build();
+ method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
}
@@ -46468,10 +47174,11 @@ package android.view.autofill {
}
public static final class FillResponse.Builder {
- ctor public FillResponse.Builder();
+ ctor public FillResponse.Builder(java.lang.String);
method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.view.autofill.FillResponse build();
+ method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
}
@@ -46480,13 +47187,6 @@ package android.view.autofill {
method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
}
- public static abstract class VirtualViewDelegate.Callback {
- ctor public VirtualViewDelegate.Callback();
- method public void onFocusChanged(int, boolean);
- method public void onNodeRemoved(int...);
- method public void onValueChanged(int);
- }
-
}
package android.view.inputmethod {
@@ -48997,8 +49697,6 @@ package android.widget {
method public void addHeaderView(android.view.View);
method public boolean areFooterDividersEnabled();
method public boolean areHeaderDividersEnabled();
- method protected android.view.View findViewTraversal(int);
- method protected android.view.View findViewWithTagTraversal(java.lang.Object);
method public android.widget.ListAdapter getAdapter();
method public deprecated long[] getCheckItemIds();
method public android.graphics.drawable.Drawable getDivider();
@@ -49266,6 +49964,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
+ method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();
@@ -50016,6 +50715,7 @@ package android.widget {
method public int getExtendedPaddingTop();
method public android.text.InputFilter[] getFilters();
method public java.lang.String getFontFeatureSettings();
+ method public java.lang.String getFontVariationSettings();
method public boolean getFreezesText();
method public int getGravity();
method public int getHighlightColor();
@@ -50125,6 +50825,7 @@ package android.widget {
method public void setExtractedText(android.view.inputmethod.ExtractedText);
method public void setFilters(android.text.InputFilter[]);
method public void setFontFeatureSettings(java.lang.String);
+ method public void setFontVariationSettings(java.lang.String);
method protected boolean setFrame(int, int, int, int);
method public void setFreezesText(boolean);
method public void setGravity(int);
@@ -50239,6 +50940,7 @@ package android.widget {
method public void setIs24HourView(java.lang.Boolean);
method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+ method public boolean validateInput();
field public static final int MODE_CLOCK = 2; // 0x2
field public static final int MODE_SPINNER = 1; // 0x1
}
@@ -50640,6 +51342,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -53934,12 +54638,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -53973,17 +54680,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -54000,6 +54713,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
@@ -62329,6 +63043,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -62339,7 +63056,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -62368,12 +63089,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 780db5e26c35..7e913913dfae 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -18,20 +18,24 @@ package com.android.commands.bmgr;
import android.app.backup.BackupManager;
import android.app.backup.BackupProgress;
-import android.app.backup.RestoreSet;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.app.backup.RestoreSet;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.content.ComponentName;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
public final class Bmgr {
IBackupManager mBmgr;
@@ -363,6 +367,11 @@ public final class Bmgr {
return;
}
+ if ("-c".equals(which)) {
+ doTransportByComponent();
+ return;
+ }
+
String old = mBmgr.selectBackupTransport(which);
if (old == null) {
System.out.println("Unknown transport '" + which
@@ -370,12 +379,50 @@ public final class Bmgr {
} else {
System.out.println("Selected transport " + which + " (formerly " + old + ")");
}
+
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
}
+ private void doTransportByComponent() {
+ String which = nextArg();
+ if (which == null) {
+ showUsage();
+ return;
+ }
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ try {
+ mBmgr.selectBackupTransportAsync(ComponentName.unflattenFromString(which),
+ new ISelectBackupTransportCallback.Stub() {
+ @Override
+ public void onSuccess(String transportName) {
+ System.out.println("Success. Selected transport: " + transportName);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ System.err.println("Failure. error=" + reason);
+ latch.countDown();
+ }
+ });
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ return;
+ }
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ System.err.println("Operation interrupted.");
+ }
+ }
+
private void doWipe() {
String transport = nextArg();
if (transport == null) {
@@ -427,7 +474,16 @@ public final class Bmgr {
}
private void doListTransports() {
+ String arg = nextArg();
+
try {
+ if ("-c".equals(arg)) {
+ for (ComponentName transport : mBmgr.listAllTransportComponents()) {
+ System.out.println(transport.flattenToShortString());
+ }
+ return;
+ }
+
String current = mBmgr.getCurrentTransport();
String[] transports = mBmgr.listAllTransports();
if (transports == null || transports.length == 0) {
@@ -649,9 +705,9 @@ public final class Bmgr {
System.err.println(" bmgr backup PACKAGE");
System.err.println(" bmgr enable BOOL");
System.err.println(" bmgr enabled");
- System.err.println(" bmgr list transports");
+ System.err.println(" bmgr list transports [-c]");
System.err.println(" bmgr list sets");
- System.err.println(" bmgr transport WHICH");
+ System.err.println(" bmgr transport WHICH|-c WHICH_COMPONENT");
System.err.println(" bmgr restore TOKEN");
System.err.println(" bmgr restore TOKEN PACKAGE...");
System.err.println(" bmgr restore PACKAGE");
@@ -673,15 +729,18 @@ public final class Bmgr {
System.err.println("the backup mechanism.");
System.err.println("");
System.err.println("The 'list transports' command reports the names of the backup transports");
- System.err.println("currently available on the device. These names can be passed as arguments");
+ System.err.println("BackupManager is currently bound to. These names can be passed as arguments");
System.err.println("to the 'transport' and 'wipe' commands. The currently active transport");
- System.err.println("is indicated with a '*' character.");
+ System.err.println("is indicated with a '*' character. If -c flag is used, all available");
+ System.err.println("transport components on the device are listed. These can be used with");
+ System.err.println("the component variant of 'transport' command.");
System.err.println("");
System.err.println("The 'list sets' command reports the token and name of each restore set");
System.err.println("available to the device via the currently active transport.");
System.err.println("");
System.err.println("The 'transport' command designates the named transport as the currently");
- System.err.println("active one. This setting is persistent across reboots.");
+ System.err.println("active one. This setting is persistent across reboots. If -c flag is");
+ System.err.println("specified, the following string is treated as a component name.");
System.err.println("");
System.err.println("The 'restore' command when given just a restore token initiates a full-system");
System.err.println("restore operation from the currently active transport. It will deliver");
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 9fad7bfd4038..a6d2986e185a 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "BootAnimation"
#include <stdint.h>
+#include <inttypes.h>
#include <sys/inotify.h>
#include <sys/poll.h>
#include <sys/stat.h>
@@ -35,6 +36,7 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
@@ -107,8 +109,6 @@ BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccu
mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
}
-BootAnimation::~BootAnimation() {}
-
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
@@ -352,6 +352,7 @@ bool BootAnimation::threadLoop()
bool BootAnimation::android()
{
+ ALOGD("BootAnimationShownTiming start time: %" PRId64 "ms", elapsedRealtime());
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
@@ -778,11 +779,12 @@ bool BootAnimation::preloadZip(Animation& animation)
}
// Create and initialize audioplay if there is a wav file in any of the animations.
+ // Do it on a separate thread so we don't hold up the animation intro.
if (partWithAudio != NULL) {
ALOGD("found audio.wav, creating playback engine");
- if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
- return false;
- }
+ mInitAudioThread = new InitAudioThread(partWithAudio->audioData,
+ partWithAudio->audioLength);
+ mInitAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
}
zip->endIteration(cookie);
@@ -850,9 +852,14 @@ bool BootAnimation::movie()
playAnimation(*animation);
- if (mTimeCheckThread != NULL) {
+ if (mTimeCheckThread != nullptr) {
mTimeCheckThread->requestExit();
- mTimeCheckThread = NULL;
+ mTimeCheckThread = nullptr;
+ }
+
+ // We should have joined mInitAudioThread thread in playAnimation
+ if (mInitAudioThread != nullptr) {
+ mInitAudioThread = nullptr;
}
releaseAnimation(animation);
@@ -871,6 +878,7 @@ bool BootAnimation::playAnimation(const Animation& animation)
const int animationX = (mWidth - animation.width) / 2;
const int animationY = (mHeight - animation.height) / 2;
+ ALOGD("BootAnimationShownTiming start time: %" PRId64 "ms", elapsedRealtime());
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
@@ -892,6 +900,10 @@ bool BootAnimation::playAnimation(const Animation& animation)
// only play audio file the first time we animate the part
if (r == 0 && part.audioData && playSoundsAllowed()) {
ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
+ // Block until the audio engine is finished initializing.
+ if (mInitAudioThread != nullptr) {
+ mInitAudioThread->join();
+ }
audioplay::playClip(part.audioData, part.audioLength);
}
@@ -1185,6 +1197,17 @@ status_t BootAnimation::TimeCheckThread::readyToRun() {
return NO_ERROR;
}
+BootAnimation::InitAudioThread::InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
+ : Thread(false),
+ mExampleAudioData(exampleAudioData),
+ mExampleAudioLength(exampleAudioLength) {}
+
+bool BootAnimation::InitAudioThread::threadLoop() {
+ audioplay::create(mExampleAudioData, mExampleAudioLength);
+ // Exit immediately
+ return false;
+}
+
// ---------------------------------------------------------------------------
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 7a2e4c28f767..f1fc98e10c1e 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -39,8 +39,7 @@ class SurfaceControl;
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
- BootAnimation();
- virtual ~BootAnimation();
+ BootAnimation();
sp<SurfaceComposerClient> session() const;
@@ -68,6 +67,16 @@ private:
BootAnimation* mBootAnimation;
};
+ class InitAudioThread : public Thread {
+ public:
+ InitAudioThread(uint8_t* exampleAudioData, int mExampleAudioLength);
+ private:
+ virtual bool threadLoop();
+
+ uint8_t* mExampleAudioData;
+ int mExampleAudioLength;
+ };
+
struct Texture {
GLint w;
GLint h;
@@ -156,7 +165,8 @@ private:
bool mSystemBoot;
String8 mZipFileName;
SortedVector<String8> mLoadedFiles;
- sp<TimeCheckThread> mTimeCheckThread;
+ sp<TimeCheckThread> mTimeCheckThread = nullptr;
+ sp<InitAudioThread> mInitAudioThread = nullptr;
};
// ---------------------------------------------------------------------------
diff --git a/cmds/media/src/com/android/commands/media/VolumeCtrl.java b/cmds/media/src/com/android/commands/media/VolumeCtrl.java
index a17193202bbd..1629c6f178f0 100755
--- a/cmds/media/src/com/android/commands/media/VolumeCtrl.java
+++ b/cmds/media/src/com/android/commands/media/VolumeCtrl.java
@@ -42,6 +42,7 @@ public class VolumeCtrl {
// --stream affects --set, --adj or --get options.
// --show affects --set and --adj options.
+ // --get can be used with --set, --adj or by itself.
public final static String USAGE = new String(
"the options are as follows: \n" +
"\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n" +
@@ -56,9 +57,8 @@ public class VolumeCtrl {
"\t\tadb shell media volume --stream 3 --get\n"
);
- private final static int VOLUME_CONTROL_MODE_SET = 0;
- private final static int VOLUME_CONTROL_MODE_ADJUST = 1;
- private final static int VOLUME_CONTROL_MODE_GET = 2;
+ private final static int VOLUME_CONTROL_MODE_SET = 1;
+ private final static int VOLUME_CONTROL_MODE_ADJUST = 2;
private final static String ADJUST_LOWER = "lower";
private final static String ADJUST_SAME = "same";
@@ -69,9 +69,10 @@ public class VolumeCtrl {
// Default parameters
int stream = AudioManager.STREAM_MUSIC;
int volIndex = 5;
- int mode = VOLUME_CONTROL_MODE_SET;
+ int mode = 0;
int adjDir = AudioManager.ADJUST_RAISE;
boolean showUi = false;
+ boolean doGet = false;
//----------------------------------------
// read options
@@ -83,7 +84,7 @@ public class VolumeCtrl {
showUi = true;
break;
case "--get":
- mode = VOLUME_CONTROL_MODE_GET;
+ doGet = true;
log(LOG_V, "will get volume");
break;
case "--stream":
@@ -150,15 +151,16 @@ public class VolumeCtrl {
// Non-interactive test
final int flag = showUi? AudioManager.FLAG_SHOW_UI : 0;
final String pack = cmd.getClass().getPackage().getName();
- if (mode == VOLUME_CONTROL_MODE_GET) {
- log(LOG_V, "volume is " + audioService.getStreamVolume(stream) +
- " in range [" + audioService.getStreamMinVolume(stream) +
- ".." + audioService.getStreamMaxVolume(stream) + "]");
- } else if (mode == VOLUME_CONTROL_MODE_SET) {
+ if (mode == VOLUME_CONTROL_MODE_SET) {
audioService.setStreamVolume(stream, volIndex, flag, pack/*callingPackage*/);
} else if (mode == VOLUME_CONTROL_MODE_ADJUST) {
audioService.adjustStreamVolume(stream, adjDir, flag, pack);
}
+ if (doGet) {
+ log(LOG_V, "volume is " + audioService.getStreamVolume(stream) +
+ " in range [" + audioService.getStreamMinVolume(stream) +
+ ".." + audioService.getStreamMaxVolume(stream) + "]");
+ }
}
//--------------------------------------------
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ac5fea36ad2b..7015381dc4fb 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -408,7 +408,7 @@ public final class Pm {
if (file.isFile()) {
try {
ApkLite baseApk = PackageParser.parseApkLite(file, 0);
- PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
+ PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null);
params.sessionParams.setSize(
PackageHelper.calculateInstalledSize(pkgLite, false,
params.sessionParams.abiOverride));
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 377e29d99576..000420f29c3b 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -162,7 +162,9 @@ int main(int argc, char** argv)
uint8_t displayOrientation = configs[activeConfig].orientation;
uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
- status_t result = screenshot.update(display, Rect(), 0, 0, 0, -1U,
+ status_t result = screenshot.update(display, Rect(),
+ 0 /* reqWidth */, 0 /* reqHeight */,
+ INT32_MIN, INT32_MAX, /* all layers */
false, captureOrientation);
if (result == NO_ERROR) {
base = screenshot.getPixels();
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
index 751bbe825bca..ef6d55ffb483 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
@@ -808,7 +808,7 @@ public class UiObject {
*
* @return Rect
* @throws UiObjectNotFoundException
- * @see {@link #getBounds()}
+ * @see #getBounds()
* @since API Level 17
*/
public Rect getVisibleBounds() throws UiObjectNotFoundException {
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index d98b4ff3e69a..71561c3c7023 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -40,7 +40,7 @@ public class UiAutomationShellWrapper {
* actions such as dialing 911 or posting messages to public forums, etc.
*
* @param isSet True to set as monkey test. False to set as regular functional test (default).
- * @see {@link ActivityManager#isUserAMonkey()}
+ * @see ActivityManager#isUserAMonkey()
*/
public void setRunAsMonkey(boolean isSet) {
IActivityManager am = ActivityManager.getService();
diff --git a/compiled-classes-phone b/compiled-classes-phone
index ed0a4a6a33cc..ea8f4a4d87fa 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2016 The Android Open Source Project
+# 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.
@@ -31,7 +31,6 @@
android.R$styleable
android.accessibilityservice.AccessibilityServiceInfo
android.accessibilityservice.AccessibilityServiceInfo$1
-android.accessibilityservice.AccessibilityServiceInfo$CapabilityInfo
android.accessibilityservice.IAccessibilityServiceClient
android.accessibilityservice.IAccessibilityServiceConnection
android.accessibilityservice.IAccessibilityServiceConnection$Stub
@@ -58,6 +57,8 @@ android.accounts.AccountManager$Future2Task
android.accounts.AccountManager$Future2Task$1
android.accounts.AccountManagerCallback
android.accounts.AccountManagerFuture
+android.accounts.AccountManagerInternal
+android.accounts.AccountManagerInternal$OnAppPermissionChangeListener
android.accounts.AccountsException
android.accounts.AuthenticatorDescription
android.accounts.AuthenticatorDescription$1
@@ -78,7 +79,6 @@ android.accounts.OnAccountsUpdateListener
android.accounts.OperationCanceledException
android.animation.AnimationHandler
android.animation.AnimationHandler$1
-android.animation.AnimationHandler$2
android.animation.AnimationHandler$AnimationFrameCallback
android.animation.AnimationHandler$AnimationFrameCallbackProvider
android.animation.AnimationHandler$MyFrameCallbackProvider
@@ -90,9 +90,13 @@ android.animation.AnimatorInflater
android.animation.AnimatorInflater$PathDataEvaluator
android.animation.AnimatorListenerAdapter
android.animation.AnimatorSet
-android.animation.AnimatorSet$AnimatorSetListener
+android.animation.AnimatorSet$1
+android.animation.AnimatorSet$2
+android.animation.AnimatorSet$3
+android.animation.AnimatorSet$AnimationEvent
android.animation.AnimatorSet$Builder
android.animation.AnimatorSet$Node
+android.animation.AnimatorSet$SeekState
android.animation.ArgbEvaluator
android.animation.FloatArrayEvaluator
android.animation.FloatEvaluator
@@ -119,14 +123,15 @@ android.animation.ObjectAnimator
android.animation.PathKeyframes
android.animation.PathKeyframes$1
android.animation.PathKeyframes$2
-android.animation.PathKeyframes$3
-android.animation.PathKeyframes$4
android.animation.PathKeyframes$FloatKeyframesBase
android.animation.PathKeyframes$IntKeyframesBase
android.animation.PathKeyframes$SimpleKeyframes
android.animation.PropertyValuesHolder
+android.animation.PropertyValuesHolder$1
android.animation.PropertyValuesHolder$FloatPropertyValuesHolder
android.animation.PropertyValuesHolder$IntPropertyValuesHolder
+android.animation.PropertyValuesHolder$PropertyValues
+android.animation.PropertyValuesHolder$PropertyValues$DataSource
android.animation.RectEvaluator
android.animation.RevealAnimator
android.animation.StateListAnimator
@@ -139,22 +144,25 @@ android.animation.TimeInterpolator
android.animation.TypeEvaluator
android.animation.ValueAnimator
android.animation.ValueAnimator$AnimatorUpdateListener
-android.annotation.TargetApi
+android.app.-$Lambda$36$c44uHH2WE4sJvw5tZZB6gRzEaHI
+android.app.-$Lambda$39$c44uHH2WE4sJvw5tZZB6gRzEaHI
+android.app.-$Lambda$57$vZ1qb742P9hE4drBY-TrOZB_qKo
+android.app.-$Lambda$7$u_rp3dnwvfyMTggc6hVftcuYJ3E
+android.app.-$Lambda$71$3eJ3p8XnIxdVOnT82Ns3R0V5ZQE
+android.app.-$Lambda$76$3eJ3p8XnIxdVOnT82Ns3R0V5ZQE
android.app.ActionBar
android.app.ActionBar$LayoutParams
android.app.ActionBar$OnMenuVisibilityListener
-android.app.ActionBar$OnNavigationListener
android.app.ActionBar$Tab
android.app.ActionBar$TabListener
android.app.Activity
android.app.Activity$HostCallbacks
-android.app.Activity$NonConfigurationInstances
android.app.ActivityManager
+android.app.ActivityManager$1
android.app.ActivityManager$AppTask
android.app.ActivityManager$MemoryInfo
android.app.ActivityManager$MemoryInfo$1
-android.app.ActivityManager$ProcessErrorStateInfo
-android.app.ActivityManager$ProcessErrorStateInfo$1
+android.app.ActivityManager$OnUidImportanceListener
android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RecentTaskInfo$1
android.app.ActivityManager$RunningAppProcessInfo
@@ -168,10 +176,12 @@ android.app.ActivityManager$StackInfo
android.app.ActivityManager$StackInfo$1
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
+android.app.ActivityManager$TaskSnapshot
+android.app.ActivityManager$TaskSnapshot$1
android.app.ActivityManager$TaskThumbnail
-android.app.ActivityManager$TaskThumbnail$1
android.app.ActivityManager$TaskThumbnailInfo
android.app.ActivityManager$TaskThumbnailInfo$1
+android.app.ActivityManager$UidObserver
android.app.ActivityManagerInternal
android.app.ActivityManagerInternal$SleepToken
android.app.ActivityOptions
@@ -189,6 +199,7 @@ android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
+android.app.ActivityThread$DumpComponentInfo
android.app.ActivityThread$EventLoggingReporter
android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
@@ -199,18 +210,13 @@ android.app.ActivityThread$ProviderClientRecord
android.app.ActivityThread$ProviderKey
android.app.ActivityThread$ProviderRefCount
android.app.ActivityThread$ReceiverData
+android.app.ActivityThread$RequestAssistContextExtras
android.app.ActivityThread$ResultData
android.app.ActivityThread$ServiceArgsData
android.app.ActivityThread$StopInfo
-android.app.ActivityTransitionCoordinator
-android.app.ActivityTransitionCoordinator$1
-android.app.ActivityTransitionCoordinator$2
-android.app.ActivityTransitionCoordinator$ContinueTransitionListener
-android.app.ActivityTransitionCoordinator$FixedEpicenterCallback
-android.app.ActivityTransitionCoordinator$SharedElementOriginalState
android.app.ActivityTransitionState
+android.app.AlarmManager
android.app.AlarmManager$AlarmClockInfo
-android.app.AlarmManager$AlarmClockInfo$1
android.app.AlarmManager$ListenerWrapper
android.app.AlarmManager$OnAlarmListener
android.app.AlertDialog
@@ -227,71 +233,59 @@ android.app.AppOpsManager$PackageOps$1
android.app.Application
android.app.Application$ActivityLifecycleCallbacks
android.app.ApplicationErrorReport
-android.app.ApplicationErrorReport$1
android.app.ApplicationErrorReport$CrashInfo
+android.app.ApplicationErrorReport$ParcelableCrashInfo
android.app.ApplicationLoaders
android.app.ApplicationPackageManager
android.app.ApplicationPackageManager$MoveCallbackDelegate
android.app.ApplicationPackageManager$OnPermissionsChangeListenerDelegate
android.app.ApplicationPackageManager$ResourceName
-android.app.ApplicationThreadProxy
android.app.AutomaticZenRule
android.app.BackStackRecord
android.app.BackStackRecord$Op
-android.app.BackStackRecord$TransitionState
-android.app.BackStackState
-android.app.BackStackState$1
android.app.BroadcastOptions
android.app.ContentProviderHolder
android.app.ContentProviderHolder$1
android.app.ContextImpl
-android.app.ContextImpl$1
android.app.ContextImpl$ApplicationContentResolver
android.app.DatePickerDialog
android.app.DatePickerDialog$OnDateSetListener
android.app.Dialog
-android.app.Dialog$-void__init__android_content_Context_context_int_themeResId_boolean_createContextThemeWrapper_LambdaImpl0
android.app.Dialog$ListenersHandler
android.app.DialogFragment
android.app.DownloadManager
android.app.DownloadManager$CursorTranslator
android.app.DownloadManager$Query
android.app.DownloadManager$Request
-android.app.EnterTransitionCoordinator
-android.app.EnterTransitionCoordinator$1
-android.app.EnterTransitionCoordinator$4
-android.app.EnterTransitionCoordinator$5
-android.app.EnterTransitionCoordinator$5$1
-android.app.EnterTransitionCoordinator$5$1$1
-android.app.EnterTransitionCoordinator$6
-android.app.EnterTransitionCoordinator$7
-android.app.EnterTransitionCoordinator$8
-android.app.ExitTransitionCoordinator
-android.app.ExitTransitionCoordinator$10
-android.app.ExitTransitionCoordinator$11
-android.app.ExitTransitionCoordinator$4
android.app.Fragment
android.app.Fragment$1
+android.app.Fragment$AnimationInfo
+android.app.Fragment$OnStartEnterTransitionListener
android.app.Fragment$SavedState
-android.app.FragmentBreadCrumbs
android.app.FragmentContainer
android.app.FragmentController
android.app.FragmentHostCallback
android.app.FragmentManager
android.app.FragmentManager$BackStackEntry
+android.app.FragmentManager$FragmentLifecycleCallbacks
android.app.FragmentManager$OnBackStackChangedListener
android.app.FragmentManagerImpl
android.app.FragmentManagerImpl$1
android.app.FragmentManagerImpl$2
-android.app.FragmentManagerImpl$3
-android.app.FragmentManagerImpl$4
-android.app.FragmentManagerImpl$5
android.app.FragmentManagerImpl$AnimateOnHWLayerIfNeededListener
+android.app.FragmentManagerImpl$OpGenerator
+android.app.FragmentManagerImpl$PopBackStackState
+android.app.FragmentManagerImpl$StartEnterTransitionListener
android.app.FragmentManagerState
android.app.FragmentManagerState$1
android.app.FragmentState
android.app.FragmentState$1
android.app.FragmentTransaction
+android.app.FragmentTransition
+android.app.FragmentTransition$3
+android.app.FragmentTransition$4
+android.app.FragmentTransition$5
+android.app.FragmentTransition$FragmentContainerTransition
android.app.IActivityContainer
android.app.IActivityContainer$Stub
android.app.IActivityContainerCallback
@@ -356,12 +350,11 @@ android.app.IntentService$ServiceHandler
android.app.JobSchedulerImpl
android.app.KeyguardManager
android.app.ListActivity
-android.app.ListActivity$1
-android.app.ListActivity$2
android.app.ListFragment
android.app.ListFragment$1
android.app.ListFragment$2
android.app.LoadedApk
+android.app.LoadedApk$DexLoadReporter
android.app.LoadedApk$ReceiverDispatcher
android.app.LoadedApk$ReceiverDispatcher$Args
android.app.LoadedApk$ReceiverDispatcher$InnerReceiver
@@ -391,26 +384,34 @@ android.app.Notification$Extender
android.app.Notification$InboxStyle
android.app.Notification$MediaStyle
android.app.Notification$MessagingStyle
+android.app.Notification$MessagingStyle$Message
+android.app.Notification$StandardTemplateParams
android.app.Notification$Style
android.app.Notification$WearableExtender
+android.app.NotificationChannel
+android.app.NotificationChannel$1
android.app.NotificationManager
android.app.NotificationManager$Policy
android.app.NotificationManager$Policy$1
android.app.OnActivityPausedListener
-android.app.PackageDeleteObserver
-android.app.PackageDeleteObserver$1
-android.app.PackageInstallObserver
-android.app.PackageInstallObserver$1
android.app.PendingIntent
android.app.PendingIntent$1
android.app.PendingIntent$CanceledException
android.app.PendingIntent$FinishedDispatcher
android.app.PendingIntent$OnFinished
+android.app.PendingIntent$OnMarshaledListener
+android.app.PictureInPictureArgs
+android.app.PictureInPictureArgs$1
android.app.Presentation
android.app.ProfilerInfo
android.app.ProgressDialog
android.app.QueuedWork
+android.app.QueuedWork$QueuedWorkHandler
android.app.ReceiverRestrictedContext
+android.app.RemoteAction
+android.app.RemoteAction$1
+android.app.RemoteAction$2
+android.app.RemoteAction$OnActionListener
android.app.RemoteInput
android.app.RemoteInput$1
android.app.RemoteInput$Builder
@@ -419,13 +420,14 @@ android.app.ResourcesManager$1
android.app.ResourcesManager$ActivityResources
android.app.ResultInfo
android.app.ResultInfo$1
+android.app.RetailDemoModeServiceInternal
+android.app.SearchManager
android.app.SearchableInfo
android.app.SearchableInfo$1
android.app.Service
android.app.ServiceConnectionLeaked
android.app.SharedElementCallback
android.app.SharedElementCallback$1
-android.app.SharedElementCallback$OnSharedElementsReadyListener
android.app.SharedPreferencesImpl
android.app.SharedPreferencesImpl$1
android.app.SharedPreferencesImpl$2
@@ -509,6 +511,11 @@ android.app.SystemServiceRegistry$71
android.app.SystemServiceRegistry$72
android.app.SystemServiceRegistry$73
android.app.SystemServiceRegistry$74
+android.app.SystemServiceRegistry$75
+android.app.SystemServiceRegistry$76
+android.app.SystemServiceRegistry$77
+android.app.SystemServiceRegistry$78
+android.app.SystemServiceRegistry$79
android.app.SystemServiceRegistry$8
android.app.SystemServiceRegistry$9
android.app.SystemServiceRegistry$CachedServiceFetcher
@@ -516,29 +523,43 @@ android.app.SystemServiceRegistry$ServiceFetcher
android.app.SystemServiceRegistry$StaticApplicationContextServiceFetcher
android.app.SystemServiceRegistry$StaticServiceFetcher
android.app.TaskStackBuilder
-android.app.TimePickerDialog
+android.app.TaskStackListener
android.app.TimePickerDialog$OnTimeSetListener
android.app.UiModeManager
-android.app.WaitResult;
+android.app.UserSwitchObserver
+android.app.VoiceInteractor$PickOptionRequest$Option
+android.app.WaitResult
android.app.WallpaperInfo
+android.app.WallpaperInfo$1
android.app.WallpaperManager
android.app.WallpaperManager$Globals
-android.app.admin.DeviceAdminInfo
-android.app.admin.DeviceAdminInfo$1
-android.app.admin.DeviceAdminInfo$PolicyInfo
android.app.admin.DevicePolicyManager
android.app.admin.DevicePolicyManagerInternal
android.app.admin.DevicePolicyManagerInternal$OnCrossProfileWidgetProvidersChangeListener
android.app.admin.IDevicePolicyManager
android.app.admin.IDevicePolicyManager$Stub
android.app.admin.IDevicePolicyManager$Stub$Proxy
+android.app.admin.PasswordMetrics
+android.app.admin.PasswordMetrics$1
android.app.admin.SecurityLog
android.app.admin.SecurityLog$SecurityEvent
android.app.admin.SecurityLog$SecurityEvent$1
+android.app.admin.SystemUpdateInfo
+android.app.admin.SystemUpdateInfo$1
android.app.admin.SystemUpdatePolicy
android.app.admin.SystemUpdatePolicy$1
android.app.assist.AssistContent
+android.app.assist.AssistContent$1
android.app.assist.AssistStructure
+android.app.assist.AssistStructure$1
+android.app.assist.AssistStructure$ParcelTransferReader
+android.app.assist.AssistStructure$ParcelTransferWriter
+android.app.assist.AssistStructure$SendChannel
+android.app.assist.AssistStructure$ViewNode
+android.app.assist.AssistStructure$ViewNodeBuilder
+android.app.assist.AssistStructure$ViewNodeText
+android.app.assist.AssistStructure$ViewStackEntry
+android.app.assist.AssistStructure$WindowNode
android.app.backup.BackupAgent
android.app.backup.BackupAgentHelper
android.app.backup.BackupDataInput
@@ -559,6 +580,7 @@ android.app.backup.IBackupManager$Stub$Proxy
android.app.backup.IBackupObserver
android.app.backup.IFullBackupRestoreObserver
android.app.backup.IRestoreSession
+android.app.backup.ISelectBackupTransportCallback
android.app.backup.RestoreDescription
android.app.backup.RestoreSet
android.app.backup.SharedPreferencesBackupHelper
@@ -597,10 +619,15 @@ android.app.trust.TrustManager$2
android.app.trust.TrustManager$TrustListener
android.app.usage.ConfigurationStats
android.app.usage.ConfigurationStats$1
+android.app.usage.ExternalStorageStats
+android.app.usage.IStorageStatsManager
+android.app.usage.IStorageStatsManager$Stub
android.app.usage.IUsageStatsManager
android.app.usage.IUsageStatsManager$Stub
android.app.usage.IUsageStatsManager$Stub$Proxy
android.app.usage.NetworkStatsManager
+android.app.usage.StorageStats
+android.app.usage.StorageStatsManager
android.app.usage.TimeSparseArray
android.app.usage.UsageEvents
android.app.usage.UsageEvents$1
@@ -626,17 +653,15 @@ android.bluetooth.BluetoothActivityEnergyInfo
android.bluetooth.BluetoothActivityEnergyInfo$1
android.bluetooth.BluetoothAdapter
android.bluetooth.BluetoothAdapter$1
-android.bluetooth.BluetoothAdapter$2
-android.bluetooth.BluetoothAdapter$BluetoothStateChangeCallback
-android.bluetooth.BluetoothAdapter$LeScanCallback
-android.bluetooth.BluetoothAudioConfig
android.bluetooth.BluetoothClass
android.bluetooth.BluetoothClass$1
android.bluetooth.BluetoothCodecConfig
+android.bluetooth.BluetoothCodecConfig$1
+android.bluetooth.BluetoothCodecStatus
+android.bluetooth.BluetoothCodecStatus$1
android.bluetooth.BluetoothDevice
android.bluetooth.BluetoothDevice$1
android.bluetooth.BluetoothDevice$2
-android.bluetooth.BluetoothGattCallbackWrapper
android.bluetooth.BluetoothGattCharacteristic
android.bluetooth.BluetoothGattDescriptor
android.bluetooth.BluetoothGattService
@@ -673,8 +698,6 @@ android.bluetooth.IBluetooth$Stub$Proxy
android.bluetooth.IBluetoothA2dp
android.bluetooth.IBluetoothA2dp$Stub
android.bluetooth.IBluetoothA2dp$Stub$Proxy
-android.bluetooth.IBluetoothA2dpSink
-android.bluetooth.IBluetoothA2dpSink$Stub
android.bluetooth.IBluetoothCallback
android.bluetooth.IBluetoothCallback$Stub
android.bluetooth.IBluetoothCallback$Stub$Proxy
@@ -682,14 +705,10 @@ android.bluetooth.IBluetoothGatt
android.bluetooth.IBluetoothGatt$Stub
android.bluetooth.IBluetoothGatt$Stub$Proxy
android.bluetooth.IBluetoothGattCallback
-android.bluetooth.IBluetoothGattCallback$Stub
-android.bluetooth.IBluetoothGattCallback$Stub$Proxy
android.bluetooth.IBluetoothGattServerCallback
android.bluetooth.IBluetoothHeadset
android.bluetooth.IBluetoothHeadset$Stub
android.bluetooth.IBluetoothHeadset$Stub$Proxy
-android.bluetooth.IBluetoothHeadsetClient
-android.bluetooth.IBluetoothHeadsetClient$Stub
android.bluetooth.IBluetoothHeadsetPhone
android.bluetooth.IBluetoothHeadsetPhone$Stub
android.bluetooth.IBluetoothHeadsetPhone$Stub$Proxy
@@ -714,8 +733,6 @@ android.bluetooth.IBluetoothPan$Stub$Proxy
android.bluetooth.IBluetoothPbap
android.bluetooth.IBluetoothPbap$Stub
android.bluetooth.IBluetoothPbap$Stub$Proxy
-android.bluetooth.IBluetoothPbapClient
-android.bluetooth.IBluetoothPbapClient$Stub
android.bluetooth.IBluetoothProfileServiceConnection
android.bluetooth.IBluetoothProfileServiceConnection$Stub
android.bluetooth.IBluetoothProfileServiceConnection$Stub$Proxy
@@ -735,11 +752,15 @@ android.bluetooth.UidTraffic
android.bluetooth.UidTraffic$1
android.bluetooth.le.AdvertiseData
android.bluetooth.le.AdvertiseSettings
-android.bluetooth.le.BluetoothLeAdvertiser
android.bluetooth.le.BluetoothLeScanner
android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper
android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1
+android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$2
android.bluetooth.le.BluetoothLeUtils
+android.bluetooth.le.IAdvertiserCallback
+android.bluetooth.le.IScannerCallback
+android.bluetooth.le.IScannerCallback$Stub
+android.bluetooth.le.IScannerCallback$Stub$Proxy
android.bluetooth.le.ScanCallback
android.bluetooth.le.ScanFilter
android.bluetooth.le.ScanFilter$1
@@ -825,6 +846,7 @@ android.content.IIntentSender$Stub
android.content.IIntentSender$Stub$Proxy
android.content.IOnPrimaryClipChangedListener
android.content.IOnPrimaryClipChangedListener$Stub
+android.content.IOnPrimaryClipChangedListener$Stub$Proxy
android.content.IRestrictionsManager
android.content.IRestrictionsManager$Stub
android.content.IRestrictionsManager$Stub$Proxy
@@ -840,14 +862,11 @@ android.content.ISyncStatusObserver$Stub$Proxy
android.content.Intent
android.content.Intent$1
android.content.Intent$FilterComparison
-android.content.Intent$ShortcutIconResource
-android.content.Intent$ShortcutIconResource$1
android.content.IntentFilter
android.content.IntentFilter$1
android.content.IntentFilter$AuthorityEntry
android.content.IntentFilter$MalformedMimeTypeException
android.content.IntentSender
-android.content.IntentSender$1
android.content.IntentSender$SendIntentException
android.content.Loader
android.content.Loader$ForceLoadContentObserver
@@ -892,11 +911,14 @@ android.content.UriMatcher
android.content.UriPermission
android.content.pm.ActivityInfo
android.content.pm.ActivityInfo$1
+android.content.pm.ActivityInfo$WindowLayout
android.content.pm.ApplicationInfo
android.content.pm.ApplicationInfo$1
android.content.pm.ComponentInfo
android.content.pm.ConfigurationInfo
android.content.pm.ConfigurationInfo$1
+android.content.pm.EphemeralResponse
+android.content.pm.FallbackCategoryProvider
android.content.pm.FeatureGroupInfo
android.content.pm.FeatureGroupInfo$1
android.content.pm.FeatureInfo
@@ -913,16 +935,9 @@ android.content.pm.IOnPermissionsChangeListener$Stub$Proxy
android.content.pm.IOtaDexopt
android.content.pm.IOtaDexopt$Stub
android.content.pm.IPackageDataObserver
-android.content.pm.IPackageDataObserver$Stub
-android.content.pm.IPackageDataObserver$Stub$Proxy
android.content.pm.IPackageDeleteObserver
-android.content.pm.IPackageDeleteObserver$Stub
android.content.pm.IPackageDeleteObserver2
-android.content.pm.IPackageDeleteObserver2$Stub
-android.content.pm.IPackageInstallObserver
-android.content.pm.IPackageInstallObserver$Stub
android.content.pm.IPackageInstallObserver2
-android.content.pm.IPackageInstallObserver2$Stub
android.content.pm.IPackageInstaller
android.content.pm.IPackageInstaller$Stub
android.content.pm.IPackageInstaller$Stub$Proxy
@@ -930,8 +945,6 @@ android.content.pm.IPackageInstallerCallback
android.content.pm.IPackageInstallerCallback$Stub
android.content.pm.IPackageInstallerCallback$Stub$Proxy
android.content.pm.IPackageInstallerSession
-android.content.pm.IPackageInstallerSession$Stub
-android.content.pm.IPackageInstallerSession$Stub$Proxy
android.content.pm.IPackageManager
android.content.pm.IPackageManager$Stub
android.content.pm.IPackageManager$Stub$Proxy
@@ -943,6 +956,7 @@ android.content.pm.IPackageStatsObserver$Stub
android.content.pm.IPackageStatsObserver$Stub$Proxy
android.content.pm.IShortcutService
android.content.pm.IShortcutService$Stub
+android.content.pm.IShortcutService$Stub$Proxy
android.content.pm.InstrumentationInfo
android.content.pm.InstrumentationInfo$1
android.content.pm.IntentFilterVerificationInfo
@@ -955,46 +969,49 @@ android.content.pm.LauncherApps$1
android.content.pm.LauncherApps$Callback
android.content.pm.LauncherApps$CallbackMessageHandler
android.content.pm.LauncherApps$CallbackMessageHandler$CallbackInfo
+android.content.pm.LauncherApps$ShortcutQuery
android.content.pm.PackageCleanItem
-android.content.pm.PackageCleanItem$1
android.content.pm.PackageInfo
android.content.pm.PackageInfo$1
android.content.pm.PackageInfoLite
-android.content.pm.PackageInfoLite$1
android.content.pm.PackageInstaller
android.content.pm.PackageInstaller$Session
android.content.pm.PackageInstaller$SessionCallback
android.content.pm.PackageInstaller$SessionCallbackDelegate
android.content.pm.PackageInstaller$SessionInfo
-android.content.pm.PackageInstaller$SessionInfo$1
android.content.pm.PackageInstaller$SessionParams
-android.content.pm.PackageInstaller$SessionParams$1
android.content.pm.PackageItemInfo
android.content.pm.PackageManager
-android.content.pm.PackageManager$LegacyPackageDeleteObserver
android.content.pm.PackageManager$MoveCallback
android.content.pm.PackageManager$NameNotFoundException
android.content.pm.PackageManager$OnPermissionsChangedListener
android.content.pm.PackageManagerInternal
+android.content.pm.PackageManagerInternal$ExternalSourcesPolicy
android.content.pm.PackageManagerInternal$PackagesProvider
android.content.pm.PackageManagerInternal$SyncAdapterPackagesProvider
android.content.pm.PackageParser
android.content.pm.PackageParser$Activity
+android.content.pm.PackageParser$Activity$1
android.content.pm.PackageParser$ActivityIntentInfo
android.content.pm.PackageParser$ApkLite
android.content.pm.PackageParser$Component
android.content.pm.PackageParser$IntentInfo
android.content.pm.PackageParser$NewPermissionInfo
android.content.pm.PackageParser$Package
+android.content.pm.PackageParser$Package$1
android.content.pm.PackageParser$PackageLite
android.content.pm.PackageParser$PackageParserException
android.content.pm.PackageParser$ParseComponentArgs
android.content.pm.PackageParser$ParsePackageItemArgs
android.content.pm.PackageParser$Permission
+android.content.pm.PackageParser$Permission$1
android.content.pm.PackageParser$PermissionGroup
+android.content.pm.PackageParser$PermissionGroup$1
android.content.pm.PackageParser$Provider
+android.content.pm.PackageParser$Provider$1
android.content.pm.PackageParser$ProviderIntentInfo
android.content.pm.PackageParser$Service
+android.content.pm.PackageParser$Service$1
android.content.pm.PackageParser$ServiceIntentInfo
android.content.pm.PackageParser$SplitNameComparator
android.content.pm.PackageParser$SplitPermissionInfo
@@ -1023,6 +1040,11 @@ android.content.pm.ResolveInfo
android.content.pm.ResolveInfo$1
android.content.pm.ServiceInfo
android.content.pm.ServiceInfo$1
+android.content.pm.SharedLibraryInfo
+android.content.pm.SharedLibraryInfo$1
+android.content.pm.ShortcutInfo
+android.content.pm.ShortcutInfo$1
+android.content.pm.ShortcutInfo$Builder
android.content.pm.ShortcutManager
android.content.pm.ShortcutServiceInternal
android.content.pm.ShortcutServiceInternal$ShortcutChangeListener
@@ -1032,7 +1054,18 @@ android.content.pm.UserInfo
android.content.pm.UserInfo$1
android.content.pm.VerifierDeviceIdentity
android.content.pm.VerifierInfo
+android.content.pm.VersionedPackage
+android.content.pm.VersionedPackage$1
android.content.pm.XmlSerializerAndParser
+android.content.pm.permission.IRuntimePermissionPresenter
+android.content.pm.permission.IRuntimePermissionPresenter$Stub
+android.content.pm.permission.IRuntimePermissionPresenter$Stub$Proxy
+android.content.pm.permission.RuntimePermissionPresentationInfo
+android.content.pm.permission.RuntimePermissionPresentationInfo$1
+android.content.pm.permission.RuntimePermissionPresenter
+android.content.pm.permission.RuntimePermissionPresenter$OnResultCallback
+android.content.pm.permission.RuntimePermissionPresenter$RemoteService
+android.content.pm.permission.RuntimePermissionPresenter$RemoteService$1
android.content.res.AssetFileDescriptor
android.content.res.AssetFileDescriptor$1
android.content.res.AssetFileDescriptor$AutoCloseInputStream
@@ -1108,6 +1141,7 @@ android.database.Observable
android.database.SQLException
android.database.sqlite.DatabaseObjectNotClosedException
android.database.sqlite.SQLiteAbortException
+android.database.sqlite.SQLiteAccessPermException
android.database.sqlite.SQLiteCantOpenDatabaseException
android.database.sqlite.SQLiteClosable
android.database.sqlite.SQLiteConnection
@@ -1143,6 +1177,7 @@ android.database.sqlite.SQLiteOpenHelper
android.database.sqlite.SQLiteProgram
android.database.sqlite.SQLiteQuery
android.database.sqlite.SQLiteQueryBuilder
+android.database.sqlite.SQLiteReadOnlyDatabaseException
android.database.sqlite.SQLiteSession
android.database.sqlite.SQLiteSession$Transaction
android.database.sqlite.SQLiteStatement
@@ -1169,6 +1204,7 @@ android.drm.DrmManagerClient$OnEventListener
android.drm.DrmManagerClient$OnInfoListener
android.drm.DrmOutputStream
android.drm.DrmSupportInfo
+android.graphics.BaseCanvas
android.graphics.Bitmap
android.graphics.Bitmap$1
android.graphics.Bitmap$CompressFormat
@@ -1195,23 +1231,20 @@ android.graphics.DashPathEffect
android.graphics.DiscretePathEffect
android.graphics.DrawFilter
android.graphics.EmbossMaskFilter
-android.graphics.FontConfig
-android.graphics.FontConfig$Alias
-android.graphics.FontConfig$Axis
-android.graphics.FontConfig$Family
-android.graphics.FontConfig$Font
android.graphics.FontFamily
android.graphics.FontListParser
+android.graphics.GraphicBuffer
+android.graphics.GraphicBuffer$1
android.graphics.ImageFormat
android.graphics.Insets
android.graphics.Interpolator
android.graphics.Interpolator$Result
-android.graphics.LayerRasterizer
android.graphics.LightingColorFilter
android.graphics.LinearGradient
android.graphics.MaskFilter
android.graphics.Matrix
android.graphics.Matrix$1
+android.graphics.Matrix$NoImagePreloadHolder
android.graphics.Matrix$ScaleToFit
android.graphics.Movie
android.graphics.NinePatch
@@ -1245,7 +1278,6 @@ android.graphics.PorterDuff$Mode
android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
android.graphics.RadialGradient
-android.graphics.Rasterizer
android.graphics.Rect
android.graphics.Rect$1
android.graphics.Rect$UnflattenHelper
@@ -1269,7 +1301,6 @@ android.graphics.Xfermode
android.graphics.YuvImage
android.graphics.drawable.Animatable
android.graphics.drawable.Animatable2
-android.graphics.drawable.Animatable2$AnimationCallback
android.graphics.drawable.AnimatedRotateDrawable
android.graphics.drawable.AnimatedRotateDrawable$1
android.graphics.drawable.AnimatedRotateDrawable$AnimatedRotateState
@@ -1281,7 +1312,6 @@ android.graphics.drawable.AnimatedStateListDrawable$FrameInterpolator
android.graphics.drawable.AnimatedStateListDrawable$Transition
android.graphics.drawable.AnimatedVectorDrawable
android.graphics.drawable.AnimatedVectorDrawable$1
-android.graphics.drawable.AnimatedVectorDrawable$2
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
@@ -1300,6 +1330,7 @@ android.graphics.drawable.Drawable$Callback
android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
android.graphics.drawable.DrawableContainer$1
+android.graphics.drawable.DrawableContainer$BlockInvalidateCallback
android.graphics.drawable.DrawableContainer$DrawableContainerState
android.graphics.drawable.DrawableInflater
android.graphics.drawable.DrawableWrapper
@@ -1348,13 +1379,31 @@ android.graphics.drawable.VectorDrawable
android.graphics.drawable.VectorDrawable$VClipPath
android.graphics.drawable.VectorDrawable$VFullPath
android.graphics.drawable.VectorDrawable$VFullPath$1
+android.graphics.drawable.VectorDrawable$VFullPath$10
+android.graphics.drawable.VectorDrawable$VFullPath$2
+android.graphics.drawable.VectorDrawable$VFullPath$3
+android.graphics.drawable.VectorDrawable$VFullPath$4
+android.graphics.drawable.VectorDrawable$VFullPath$5
+android.graphics.drawable.VectorDrawable$VFullPath$6
+android.graphics.drawable.VectorDrawable$VFullPath$7
+android.graphics.drawable.VectorDrawable$VFullPath$8
+android.graphics.drawable.VectorDrawable$VFullPath$9
android.graphics.drawable.VectorDrawable$VGroup
android.graphics.drawable.VectorDrawable$VGroup$1
+android.graphics.drawable.VectorDrawable$VGroup$2
+android.graphics.drawable.VectorDrawable$VGroup$3
+android.graphics.drawable.VectorDrawable$VGroup$4
+android.graphics.drawable.VectorDrawable$VGroup$5
+android.graphics.drawable.VectorDrawable$VGroup$6
+android.graphics.drawable.VectorDrawable$VGroup$7
+android.graphics.drawable.VectorDrawable$VGroup$8
+android.graphics.drawable.VectorDrawable$VGroup$9
android.graphics.drawable.VectorDrawable$VObject
android.graphics.drawable.VectorDrawable$VPath
+android.graphics.drawable.VectorDrawable$VPath$1
android.graphics.drawable.VectorDrawable$VectorDrawableState
+android.graphics.drawable.VectorDrawable$VectorDrawableState$1
android.graphics.drawable.shapes.OvalShape
-android.graphics.drawable.shapes.PathShape
android.graphics.drawable.shapes.RectShape
android.graphics.drawable.shapes.RoundRectShape
android.graphics.drawable.shapes.Shape
@@ -1362,7 +1411,6 @@ android.graphics.pdf.PdfDocument
android.graphics.pdf.PdfEditor
android.graphics.pdf.PdfRenderer
android.hardware.Camera
-android.hardware.Camera$Area
android.hardware.Camera$AutoFocusCallback
android.hardware.Camera$AutoFocusMoveCallback
android.hardware.Camera$CameraInfo
@@ -1376,9 +1424,13 @@ android.hardware.Camera$PictureCallback
android.hardware.Camera$PreviewCallback
android.hardware.Camera$ShutterCallback
android.hardware.Camera$Size
+android.hardware.CameraStatus
+android.hardware.CameraStatus$1
android.hardware.ConsumerIrManager
android.hardware.GeomagneticField
android.hardware.GeomagneticField$LegendreTable
+android.hardware.HardwareBuffer
+android.hardware.HardwareBuffer$1
android.hardware.ICameraService
android.hardware.ICameraService$Stub
android.hardware.ICameraService$Stub$Proxy
@@ -1418,8 +1470,11 @@ android.hardware.camera2.CameraDevice$StateCallback
android.hardware.camera2.CameraManager
android.hardware.camera2.CameraManager$AvailabilityCallback
android.hardware.camera2.CameraManager$CameraManagerGlobal
+android.hardware.camera2.CameraManager$CameraManagerGlobal$1
+android.hardware.camera2.CameraManager$CameraManagerGlobal$2
android.hardware.camera2.CameraManager$CameraManagerGlobal$3
android.hardware.camera2.CameraManager$CameraManagerGlobal$4
+android.hardware.camera2.CameraManager$CameraManagerGlobal$5
android.hardware.camera2.CameraManager$TorchCallback
android.hardware.camera2.CameraMetadata
android.hardware.camera2.CaptureFailure
@@ -1460,6 +1515,7 @@ android.hardware.camera2.impl.CameraCaptureSessionImpl$SequenceDrainListener
android.hardware.camera2.impl.CameraDeviceImpl
android.hardware.camera2.impl.CameraDeviceImpl$1
android.hardware.camera2.impl.CameraDeviceImpl$10
+android.hardware.camera2.impl.CameraDeviceImpl$11
android.hardware.camera2.impl.CameraDeviceImpl$2
android.hardware.camera2.impl.CameraDeviceImpl$3
android.hardware.camera2.impl.CameraDeviceImpl$4
@@ -1471,7 +1527,6 @@ android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks
android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$2
android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$3
android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$4
-android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$5
android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$6
android.hardware.camera2.impl.CameraDeviceImpl$CaptureCallback
android.hardware.camera2.impl.CameraDeviceImpl$CaptureCallbackHolder
@@ -1564,7 +1619,6 @@ android.hardware.camera2.params.StreamConfiguration
android.hardware.camera2.params.StreamConfigurationDuration
android.hardware.camera2.params.StreamConfigurationMap
android.hardware.camera2.params.TonemapCurve
-android.hardware.camera2.utils.ArrayUtils
android.hardware.camera2.utils.HashCodeHelpers
android.hardware.camera2.utils.SubmitInfo
android.hardware.camera2.utils.SubmitInfo$1
@@ -1604,21 +1658,11 @@ android.hardware.fingerprint.Fingerprint$1
android.hardware.fingerprint.FingerprintManager
android.hardware.fingerprint.FingerprintManager$1
android.hardware.fingerprint.FingerprintManager$2
-android.hardware.fingerprint.FingerprintManager$2$1
android.hardware.fingerprint.FingerprintManager$AuthenticationCallback
android.hardware.fingerprint.FingerprintManager$AuthenticationResult
-android.hardware.fingerprint.FingerprintManager$CryptoObject
-android.hardware.fingerprint.FingerprintManager$EnrollmentCallback
android.hardware.fingerprint.FingerprintManager$LockoutResetCallback
android.hardware.fingerprint.FingerprintManager$MyHandler
-android.hardware.fingerprint.FingerprintManager$OnAuthenticationCancelListener
-android.hardware.fingerprint.FingerprintManager$OnEnrollCancelListener
-android.hardware.fingerprint.FingerprintManager$RemovalCallback
-android.hardware.fingerprint.IFingerprintDaemon
-android.hardware.fingerprint.IFingerprintDaemon$Stub
-android.hardware.fingerprint.IFingerprintDaemon$Stub$Proxy
-android.hardware.fingerprint.IFingerprintDaemonCallback
-android.hardware.fingerprint.IFingerprintDaemonCallback$Stub
+android.hardware.fingerprint.IFingerprintClientActiveCallback
android.hardware.fingerprint.IFingerprintService
android.hardware.fingerprint.IFingerprintService$Stub
android.hardware.fingerprint.IFingerprintService$Stub$Proxy
@@ -1627,14 +1671,8 @@ android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback$Stub
android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback$Stub$Proxy
android.hardware.fingerprint.IFingerprintServiceReceiver
android.hardware.fingerprint.IFingerprintServiceReceiver$Stub
-android.hardware.fingerprint.IFingerprintServiceReceiver$Stub$Proxy
-android.hardware.hdmi.HdmiClient
android.hardware.hdmi.HdmiControlManager
-android.hardware.hdmi.HdmiPlaybackClient
android.hardware.hdmi.HdmiPlaybackClient$DisplayStatusCallback
-android.hardware.hdmi.HdmiTvClient
-android.hardware.hdmi.IHdmiControlService
-android.hardware.hdmi.IHdmiControlService$Stub
android.hardware.input.IInputDevicesChangedListener
android.hardware.input.IInputDevicesChangedListener$Stub
android.hardware.input.IInputDevicesChangedListener$Stub$Proxy
@@ -1654,13 +1692,15 @@ android.hardware.input.KeyboardLayout
android.hardware.input.KeyboardLayout$1
android.hardware.input.TouchCalibration
android.hardware.input.TouchCalibration$1
-android.hardware.location.ActivityChangedEvent
android.hardware.location.ActivityRecognitionHardware
-android.hardware.location.ActivityRecognitionHardware$SinkList
android.hardware.location.ContextHubInfo
android.hardware.location.ContextHubInfo$1
android.hardware.location.ContextHubManager
-android.hardware.location.ContextHubService
+android.hardware.location.ContextHubManager$1
+android.hardware.location.ContextHubManager$Callback
+android.hardware.location.ContextHubManager$ICallback
+android.hardware.location.ContextHubMessage
+android.hardware.location.ContextHubMessage$1
android.hardware.location.GeofenceHardware
android.hardware.location.GeofenceHardware$GeofenceHardwareMonitorCallbackWrapper
android.hardware.location.GeofenceHardwareCallback
@@ -1670,27 +1710,21 @@ android.hardware.location.GeofenceHardwareImpl$2
android.hardware.location.GeofenceHardwareImpl$3
android.hardware.location.GeofenceHardwareImpl$Reaper
android.hardware.location.GeofenceHardwareMonitorCallback
-android.hardware.location.GeofenceHardwareRequestParcelable
android.hardware.location.GeofenceHardwareService
android.hardware.location.GeofenceHardwareService$1
android.hardware.location.IActivityRecognitionHardware
android.hardware.location.IActivityRecognitionHardware$Stub
-android.hardware.location.IActivityRecognitionHardware$Stub$Proxy
android.hardware.location.IActivityRecognitionHardwareClient
android.hardware.location.IActivityRecognitionHardwareClient$Stub
android.hardware.location.IActivityRecognitionHardwareClient$Stub$Proxy
-android.hardware.location.IActivityRecognitionHardwareSink
-android.hardware.location.IActivityRecognitionHardwareSink$Stub
-android.hardware.location.IActivityRecognitionHardwareSink$Stub$Proxy
android.hardware.location.IActivityRecognitionHardwareWatcher
+android.hardware.location.IContextHubCallback
+android.hardware.location.IContextHubCallback$Stub
+android.hardware.location.IContextHubCallback$Stub$Proxy
android.hardware.location.IContextHubService
android.hardware.location.IContextHubService$Stub
+android.hardware.location.IContextHubService$Stub$Proxy
android.hardware.location.IFusedLocationHardware
-android.hardware.location.IFusedLocationHardware$Stub
-android.hardware.location.IFusedLocationHardware$Stub$Proxy
-android.hardware.location.IFusedLocationHardwareSink
-android.hardware.location.IFusedLocationHardwareSink$Stub
-android.hardware.location.IFusedLocationHardwareSink$Stub$Proxy
android.hardware.location.IGeofenceHardware
android.hardware.location.IGeofenceHardware$Stub
android.hardware.location.IGeofenceHardware$Stub$Proxy
@@ -1698,6 +1732,10 @@ android.hardware.location.IGeofenceHardwareMonitorCallback
android.hardware.location.IGeofenceHardwareMonitorCallback$Stub
android.hardware.location.IGeofenceHardwareMonitorCallback$Stub$Proxy
android.hardware.location.MemoryRegion
+android.hardware.location.MemoryRegion$1
+android.hardware.location.NanoApp
+android.hardware.location.NanoAppFilter
+android.hardware.location.NanoAppFilter$1
android.hardware.location.NanoAppInstanceInfo
android.hardware.location.NanoAppInstanceInfo$1
android.hardware.radio.RadioManager
@@ -1721,6 +1759,21 @@ android.hardware.radio.RadioMetadata
android.hardware.radio.RadioMetadata$1
android.hardware.radio.RadioModule
android.hardware.radio.RadioTuner
+android.hardware.radio.V1_0.Call
+android.hardware.radio.V1_0.CardStatus
+android.hardware.radio.V1_0.CdmaSignalStrength
+android.hardware.radio.V1_0.EvdoSignalStrength
+android.hardware.radio.V1_0.GsmSignalStrength
+android.hardware.radio.V1_0.IRadio
+android.hardware.radio.V1_0.IRadio$Proxy
+android.hardware.radio.V1_0.IRadioIndication
+android.hardware.radio.V1_0.IRadioIndication$Stub
+android.hardware.radio.V1_0.IRadioResponse
+android.hardware.radio.V1_0.IRadioResponse$Stub
+android.hardware.radio.V1_0.LteSignalStrength
+android.hardware.radio.V1_0.RadioResponseInfo
+android.hardware.radio.V1_0.SignalStrength
+android.hardware.radio.V1_0.TdScdmaSignalStrength
android.hardware.soundtrigger.IRecognitionStatusCallback
android.hardware.soundtrigger.IRecognitionStatusCallback$Stub
android.hardware.soundtrigger.KeyphraseEnrollmentInfo
@@ -1756,21 +1809,28 @@ android.hardware.usb.IUsbManager$Stub$Proxy
android.hardware.usb.UsbAccessory
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
-android.hardware.usb.UsbInterface
android.hardware.usb.UsbManager
android.hardware.usb.UsbPort
android.hardware.usb.UsbPort$1
android.hardware.usb.UsbPortStatus
android.hardware.usb.UsbPortStatus$1
android.hardware.usb.UsbRequest
+android.hidl.base.V1_0.IBase
android.icu.impl.BMPSet
android.icu.impl.CacheBase
android.icu.impl.CacheValue
android.icu.impl.CacheValue$NullValue
android.icu.impl.CacheValue$SoftValue
android.icu.impl.CacheValue$Strength
-android.icu.impl.CalendarData
+android.icu.impl.CalendarAstronomer
+android.icu.impl.CalendarAstronomer$2
+android.icu.impl.CalendarAstronomer$CoordFunc
+android.icu.impl.CalendarAstronomer$Equatorial
+android.icu.impl.CalendarAstronomer$MoonAge
+android.icu.impl.CalendarAstronomer$SolarLongitude
android.icu.impl.CalendarUtil
+android.icu.impl.CalendarUtil$CalendarPreferences
+android.icu.impl.CaseMap$StringContextIterator
android.icu.impl.CharTrie
android.icu.impl.CharacterIteration
android.icu.impl.ClassLoaderUtil
@@ -1778,6 +1838,8 @@ android.icu.impl.CurrencyData
android.icu.impl.CurrencyData$CurrencyDisplayInfo
android.icu.impl.CurrencyData$CurrencyDisplayInfoProvider
android.icu.impl.CurrencyData$CurrencySpacingInfo
+android.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingPattern
+android.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingType
android.icu.impl.DateNumberFormat
android.icu.impl.DontCareFieldPosition
android.icu.impl.Grego
@@ -1791,6 +1853,7 @@ android.icu.impl.ICUCache
android.icu.impl.ICUConfig
android.icu.impl.ICUCurrencyDisplayInfoProvider
android.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo
+android.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo$SpacingInfoSink
android.icu.impl.ICUCurrencyMetaInfo
android.icu.impl.ICUCurrencyMetaInfo$Collector
android.icu.impl.ICUCurrencyMetaInfo$CurrencyCollector
@@ -1808,8 +1871,11 @@ android.icu.impl.ICURegionDataTables
android.icu.impl.ICUResourceBundle
android.icu.impl.ICUResourceBundle$1
android.icu.impl.ICUResourceBundle$2
-android.icu.impl.ICUResourceBundle$2$1
+android.icu.impl.ICUResourceBundle$3
+android.icu.impl.ICUResourceBundle$3$1
+android.icu.impl.ICUResourceBundle$4
android.icu.impl.ICUResourceBundle$AvailEntry
+android.icu.impl.ICUResourceBundle$Loader
android.icu.impl.ICUResourceBundle$OpenType
android.icu.impl.ICUResourceBundle$WholeBundle
android.icu.impl.ICUResourceBundleImpl
@@ -1843,6 +1909,7 @@ android.icu.impl.IDNA2003
android.icu.impl.JavaTimeZone
android.icu.impl.LocaleDisplayNamesImpl
android.icu.impl.LocaleDisplayNamesImpl$Cache
+android.icu.impl.LocaleDisplayNamesImpl$CapitalizationContextSink
android.icu.impl.LocaleDisplayNamesImpl$CapitalizationContextUsage
android.icu.impl.LocaleDisplayNamesImpl$DataTable
android.icu.impl.LocaleDisplayNamesImpl$DataTables
@@ -1874,21 +1941,10 @@ android.icu.impl.PluralRulesLoader
android.icu.impl.ReplaceableUCharacterIterator
android.icu.impl.RuleCharacterIterator
android.icu.impl.SimpleCache
-android.icu.impl.SimplePatternFormatter
+android.icu.impl.SimpleFormatterImpl
android.icu.impl.SoftCache
android.icu.impl.StandardPlural
android.icu.impl.StringPrepDataReader
-android.icu.impl.TextTrieMap
-android.icu.impl.TextTrieMap$CharIterator
-android.icu.impl.TextTrieMap$Node
-android.icu.impl.TimeZoneNamesFactoryImpl
-android.icu.impl.TimeZoneNamesImpl
-android.icu.impl.TimeZoneNamesImpl$MZ2TZsCache
-android.icu.impl.TimeZoneNamesImpl$MZMapEntry
-android.icu.impl.TimeZoneNamesImpl$NameInfo
-android.icu.impl.TimeZoneNamesImpl$TZ2MZsCache
-android.icu.impl.TimeZoneNamesImpl$ZNames
-android.icu.impl.TimeZoneNamesImpl$ZNamesLoader
android.icu.impl.Trie
android.icu.impl.Trie$DataManipulate
android.icu.impl.Trie$DefaultGetFoldingOffset
@@ -1941,8 +1997,10 @@ android.icu.impl.UCharacterProperty$NormQuickCheckIntProperty
android.icu.impl.UPropertyAliases
android.icu.impl.UPropertyAliases$IsAcceptable
android.icu.impl.URLHandler$URLVisitor
+android.icu.impl.UResource$Array
android.icu.impl.UResource$Key
-android.icu.impl.UResource$TableSink
+android.icu.impl.UResource$Sink
+android.icu.impl.UResource$Table
android.icu.impl.UResource$Value
android.icu.impl.USerializedSet
android.icu.impl.Utility
@@ -1978,7 +2036,6 @@ android.icu.impl.locale.LocaleObjectCache
android.icu.impl.locale.LocaleObjectCache$CacheEntry
android.icu.impl.locale.LocaleSyntaxException
android.icu.lang.UCharacter
-android.icu.lang.UCharacter$StringContextIterator
android.icu.lang.UCharacterEnums$ECharacterCategory
android.icu.lang.UCharacterEnums$ECharacterDirection
android.icu.lang.UScript
@@ -2013,26 +2070,36 @@ android.icu.text.DateFormat
android.icu.text.DateFormat$BooleanAttribute
android.icu.text.DateFormat$Field
android.icu.text.DateFormatSymbols
+android.icu.text.DateFormatSymbols$1
+android.icu.text.DateFormatSymbols$CalendarDataSink
+android.icu.text.DateFormatSymbols$CalendarDataSink$AliasType
android.icu.text.DateFormatSymbols$CapitalizationContextUsage
android.icu.text.DateIntervalFormat
android.icu.text.DateIntervalFormat$BestMatchInfo
android.icu.text.DateIntervalFormat$SkeletonAndItsBestMatch
android.icu.text.DateIntervalInfo
+android.icu.text.DateIntervalInfo$DateIntervalSink
android.icu.text.DateIntervalInfo$PatternInfo
android.icu.text.DateTimePatternGenerator
+android.icu.text.DateTimePatternGenerator$AppendItemFormatsSink
+android.icu.text.DateTimePatternGenerator$AppendItemNamesSink
+android.icu.text.DateTimePatternGenerator$AvailableFormatsSink
android.icu.text.DateTimePatternGenerator$DTPGflags
android.icu.text.DateTimePatternGenerator$DateTimeMatcher
+android.icu.text.DateTimePatternGenerator$DayPeriodAllowedHoursSink
android.icu.text.DateTimePatternGenerator$DistanceInfo
android.icu.text.DateTimePatternGenerator$FormatParser
android.icu.text.DateTimePatternGenerator$PatternInfo
android.icu.text.DateTimePatternGenerator$PatternWithMatcher
android.icu.text.DateTimePatternGenerator$PatternWithSkeletonFlag
+android.icu.text.DateTimePatternGenerator$SkeletonFields
android.icu.text.DateTimePatternGenerator$VariableField
android.icu.text.DecimalFormat
android.icu.text.DecimalFormat$Unit
android.icu.text.DecimalFormatSymbols
android.icu.text.DecimalFormatSymbols$1
android.icu.text.DecimalFormatSymbols$CacheData
+android.icu.text.DecimalFormatSymbols$DecFmtDataSink
android.icu.text.DigitList
android.icu.text.DisplayContext
android.icu.text.DisplayContext$Type
@@ -2044,14 +2111,6 @@ android.icu.text.ListFormatter$FormattedListBuilder
android.icu.text.ListFormatter$Style
android.icu.text.LocaleDisplayNames
android.icu.text.LocaleDisplayNames$DialectHandling
-android.icu.text.MessageFormat
-android.icu.text.MessageFormat$AppendableWrapper
-android.icu.text.MessageFormat$Field
-android.icu.text.MessagePattern
-android.icu.text.MessagePattern$ApostropheMode
-android.icu.text.MessagePattern$ArgType
-android.icu.text.MessagePattern$Part
-android.icu.text.MessagePattern$Part$Type
android.icu.text.Normalizer
android.icu.text.Normalizer$FCDMode
android.icu.text.Normalizer$Mode
@@ -2073,6 +2132,9 @@ android.icu.text.NumberFormatServiceShim
android.icu.text.NumberFormatServiceShim$NFService
android.icu.text.NumberFormatServiceShim$NFService$1RBNumberFormatFactory
android.icu.text.NumberingSystem
+android.icu.text.NumberingSystem$1
+android.icu.text.NumberingSystem$2
+android.icu.text.NumberingSystem$LocaleLookupData
android.icu.text.PluralRanges
android.icu.text.PluralRanges$Matrix
android.icu.text.PluralRules
@@ -2100,20 +2162,18 @@ android.icu.text.RawCollationKey
android.icu.text.RelativeDateTimeFormatter
android.icu.text.RelativeDateTimeFormatter$AbsoluteUnit
android.icu.text.RelativeDateTimeFormatter$Cache
+android.icu.text.RelativeDateTimeFormatter$Cache$1
android.icu.text.RelativeDateTimeFormatter$Direction
android.icu.text.RelativeDateTimeFormatter$Loader
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink$DateTimeUnit
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink$RelativeSink
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink$RelativeTimeDetailSink
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink$RelativeTimeSink
-android.icu.text.RelativeDateTimeFormatter$RelDateTimeFmtDataSink$UnitSink
+android.icu.text.RelativeDateTimeFormatter$RelDateTimeDataSink
+android.icu.text.RelativeDateTimeFormatter$RelDateTimeDataSink$DateTimeUnit
android.icu.text.RelativeDateTimeFormatter$RelativeDateTimeFormatterData
android.icu.text.RelativeDateTimeFormatter$RelativeUnit
android.icu.text.RelativeDateTimeFormatter$Style
android.icu.text.Replaceable
android.icu.text.ReplaceableString
android.icu.text.RuleBasedBreakIterator
+android.icu.text.RuleBasedBreakIterator$LookAheadResults
android.icu.text.RuleBasedCollator
android.icu.text.RuleBasedCollator$CollationBuffer
android.icu.text.RuleBasedCollator$CollationKeyByteSink
@@ -2124,9 +2184,6 @@ android.icu.text.SimpleDateFormat
android.icu.text.SimpleDateFormat$PatternItem
android.icu.text.StringPrep
android.icu.text.StringPrepParseException
-android.icu.text.TimeZoneNames
-android.icu.text.TimeZoneNames$Cache
-android.icu.text.TimeZoneNames$Factory
android.icu.text.TimeZoneNames$NameType
android.icu.text.UCharacterIterator
android.icu.text.UFieldPosition
@@ -2155,12 +2212,19 @@ android.icu.util.Calendar$WeekDataCache
android.icu.util.CharsTrie
android.icu.util.CharsTrie$Entry
android.icu.util.CharsTrie$Iterator
+android.icu.util.ChineseCalendar
android.icu.util.Currency
+android.icu.util.Currency$1
android.icu.util.Currency$CurrencyUsage
android.icu.util.Currency$EquivalenceRelation
android.icu.util.CurrencyAmount
android.icu.util.Freezable
android.icu.util.GregorianCalendar
+android.icu.util.HebrewCalendar
+android.icu.util.ICUException
+android.icu.util.IndianCalendar
+android.icu.util.IslamicCalendar
+android.icu.util.IslamicCalendar$CalculationType
android.icu.util.LocaleData
android.icu.util.Measure
android.icu.util.MeasureUnit
@@ -2174,11 +2238,13 @@ android.icu.util.TimeUnit
android.icu.util.TimeZone
android.icu.util.TimeZone$ConstantZone
android.icu.util.ULocale
+android.icu.util.ULocale$1
+android.icu.util.ULocale$2
android.icu.util.ULocale$Category
android.icu.util.ULocale$JDKLocaleHelper
android.icu.util.ULocale$Type
android.icu.util.UResourceBundle
-android.icu.util.UResourceBundle$ResourceCacheKey
+android.icu.util.UResourceBundle$RootType
android.icu.util.UResourceBundleIterator
android.icu.util.UResourceTypeMismatchException
android.icu.util.VersionInfo
@@ -2196,26 +2262,17 @@ android.inputmethodservice.InputMethodService$InputMethodImpl
android.inputmethodservice.InputMethodService$InputMethodSessionImpl
android.inputmethodservice.InputMethodService$Insets
android.inputmethodservice.InputMethodService$SettingsObserver
-android.inputmethodservice.Keyboard
-android.inputmethodservice.Keyboard$Key
-android.inputmethodservice.Keyboard$Row
-android.inputmethodservice.KeyboardView
-android.inputmethodservice.KeyboardView$1
-android.inputmethodservice.KeyboardView$2
-android.inputmethodservice.KeyboardView$OnKeyboardActionListener
-android.inputmethodservice.KeyboardView$SwipeTracker
android.inputmethodservice.SoftInputWindow
+android.inputmethodservice.SoftInputWindow$Callback
android.location.Address
android.location.Address$1
android.location.Country
android.location.Country$1
android.location.CountryDetector
android.location.CountryDetector$ListenerTransport
+android.location.CountryDetector$ListenerTransport$1
android.location.CountryListener
android.location.Criteria
-android.location.Criteria$1
-android.location.FusedBatchOptions
-android.location.FusedBatchOptions$1
android.location.Geocoder
android.location.GeocoderParams
android.location.GeocoderParams$1
@@ -2237,11 +2294,8 @@ android.location.ICountryDetector$Stub$Proxy
android.location.ICountryListener
android.location.ICountryListener$Stub
android.location.ICountryListener$Stub$Proxy
-android.location.IFusedGeofenceHardware
-android.location.IFusedGeofenceHardware$Stub
android.location.IFusedProvider
android.location.IFusedProvider$Stub
-android.location.IFusedProvider$Stub$Proxy
android.location.IGeocodeProvider
android.location.IGeocodeProvider$Stub
android.location.IGeocodeProvider$Stub$Proxy
@@ -2283,7 +2337,6 @@ android.location.LocationManager$ListenerTransport$2
android.location.LocationProvider
android.location.LocationRequest
android.location.LocationRequest$1
-android.media.AmrInputStream
android.media.AudioAttributes
android.media.AudioAttributes$1
android.media.AudioAttributes$Builder
@@ -2302,6 +2355,7 @@ android.media.AudioHandle
android.media.AudioManager
android.media.AudioManager$1
android.media.AudioManager$2
+android.media.AudioManager$3
android.media.AudioManager$NativeEventHandlerDelegate
android.media.AudioManager$NativeEventHandlerDelegate$1
android.media.AudioManager$OnAmPortUpdateListener
@@ -2314,6 +2368,10 @@ android.media.AudioManagerInternal$RingerModeDelegate
android.media.AudioMixPort
android.media.AudioMixPortConfig
android.media.AudioPatch
+android.media.AudioPlaybackConfiguration
+android.media.AudioPlaybackConfiguration$1
+android.media.AudioPlaybackConfiguration$IPlayerShell
+android.media.AudioPlaybackConfiguration$PlayerDeathMonitor
android.media.AudioPort
android.media.AudioPortConfig
android.media.AudioPortEventHandler
@@ -2330,6 +2388,8 @@ android.media.AudioSystem$DynamicPolicyCallback
android.media.AudioSystem$ErrorCallback
android.media.AudioTimestamp
android.media.AudioTrack
+android.media.BufferingParams
+android.media.BufferingParams$1
android.media.CamcorderProfile
android.media.CameraProfile
android.media.Cea708CaptionRenderer
@@ -2338,11 +2398,9 @@ android.media.DecoderCapabilities
android.media.DeniedByServerException
android.media.EncoderCapabilities
android.media.ExifInterface
-android.media.ExifInterface$ByteOrderAwarenessDataInputStream
-android.media.ExifInterface$ByteOrderAwarenessDataOutputStream
+android.media.ExifInterface$ByteOrderedDataInputStream
android.media.ExifInterface$ExifAttribute
android.media.ExifInterface$ExifTag
-android.media.ExifInterface$Rational
android.media.IAudioFocusDispatcher
android.media.IAudioFocusDispatcher$Stub
android.media.IAudioFocusDispatcher$Stub$Proxy
@@ -2356,12 +2414,23 @@ android.media.IMediaHTTPConnection
android.media.IMediaHTTPConnection$Stub
android.media.IMediaHTTPService
android.media.IMediaHTTPService$Stub
+android.media.IMediaResourceMonitor
+android.media.IMediaResourceMonitor$Stub
android.media.IMediaRouterClient
android.media.IMediaRouterClient$Stub
android.media.IMediaRouterClient$Stub$Proxy
android.media.IMediaRouterService
android.media.IMediaRouterService$Stub
android.media.IMediaRouterService$Stub$Proxy
+android.media.IMediaScannerListener
+android.media.IMediaScannerListener$Stub
+android.media.IMediaScannerService
+android.media.IMediaScannerService$Stub
+android.media.IPlaybackConfigDispatcher
+android.media.IPlaybackConfigDispatcher$Stub
+android.media.IPlayer
+android.media.IPlayer$Stub
+android.media.IPlayer$Stub$Proxy
android.media.IRecordingConfigDispatcher
android.media.IRecordingConfigDispatcher$Stub
android.media.IRemoteVolumeController
@@ -2389,14 +2458,10 @@ android.media.ImageWriter$OnImageReleasedListener
android.media.ImageWriter$WriterSurfaceImage
android.media.ImageWriter$WriterSurfaceImage$SurfacePlane
android.media.JetPlayer
-android.media.MediaActionSound
-android.media.MediaActionSound$1
-android.media.MediaActionSound$SoundState
android.media.MediaCodec
android.media.MediaCodec$BufferInfo
android.media.MediaCodec$BufferMap
android.media.MediaCodec$BufferMap$CodecBuffer
-android.media.MediaCodec$Callback
android.media.MediaCodec$CodecException
android.media.MediaCodec$CryptoException
android.media.MediaCodec$CryptoInfo
@@ -2412,7 +2477,6 @@ android.media.MediaCodecInfo$Feature
android.media.MediaCodecInfo$VideoCapabilities
android.media.MediaCodecList
android.media.MediaCrypto
-android.media.MediaCryptoException
android.media.MediaDescription
android.media.MediaDescription$1
android.media.MediaDescription$Builder
@@ -2422,7 +2486,6 @@ android.media.MediaDrm$CryptoSession
android.media.MediaDrm$EventHandler
android.media.MediaDrm$KeyRequest
android.media.MediaDrm$MediaDrmStateException
-android.media.MediaDrm$OnEventListener
android.media.MediaDrm$ProvisionRequest
android.media.MediaDrmException
android.media.MediaExtractor
@@ -2440,7 +2503,8 @@ android.media.MediaMuxer
android.media.MediaPlayer
android.media.MediaPlayer$1
android.media.MediaPlayer$2
-android.media.MediaPlayer$2$1
+android.media.MediaPlayer$3
+android.media.MediaPlayer$3$1
android.media.MediaPlayer$EventHandler
android.media.MediaPlayer$OnBufferingUpdateListener
android.media.MediaPlayer$OnCompletionListener
@@ -2472,6 +2536,7 @@ android.media.MediaRouter$Static$Client
android.media.MediaRouter$Static$Client$1
android.media.MediaRouter$UserRouteInfo
android.media.MediaRouter$VolumeCallback
+android.media.MediaRouter$VolumeCallbackInfo
android.media.MediaRouter$VolumeChangeReceiver
android.media.MediaRouter$WifiDisplayStatusChangedReceiver
android.media.MediaRouterClientState
@@ -2479,7 +2544,13 @@ android.media.MediaRouterClientState$1
android.media.MediaRouterClientState$RouteInfo
android.media.MediaRouterClientState$RouteInfo$1
android.media.MediaScanner
+android.media.MediaScanner$FileEntry
+android.media.MediaScanner$MediaBulkDeleter
+android.media.MediaScanner$MyMediaScannerClient
+android.media.MediaScannerClient
android.media.MediaScannerConnection
+android.media.MediaScannerConnection$1
+android.media.MediaScannerConnection$ClientProxy
android.media.MediaScannerConnection$MediaScannerConnectionClient
android.media.MediaScannerConnection$OnScanCompletedListener
android.media.MediaSync
@@ -2492,6 +2563,9 @@ android.media.PlaybackParams
android.media.PlaybackParams$1
android.media.PlayerBase
android.media.PlayerBase$1
+android.media.PlayerBase$2
+android.media.PlayerBase$PlayerIdCard
+android.media.PlayerBase$PlayerIdCard$1
android.media.Rating
android.media.Rating$1
android.media.RemoteControlClient
@@ -2503,7 +2577,6 @@ android.media.Ringtone
android.media.Ringtone$MyOnCompletionListener
android.media.RingtoneManager
android.media.SoundPool
-android.media.SoundPool$1
android.media.SoundPool$Builder
android.media.SoundPool$EventHandler
android.media.SoundPool$OnLoadCompleteListener
@@ -2519,7 +2592,6 @@ android.media.ThumbnailUtils
android.media.ThumbnailUtils$SizedThumbnailBitmap
android.media.ToneGenerator
android.media.TtmlRenderer
-android.media.UnsupportedSchemeException
android.media.Utils
android.media.Utils$1
android.media.Utils$2
@@ -2527,10 +2599,8 @@ android.media.VolumePolicy
android.media.VolumePolicy$1
android.media.VolumeProvider
android.media.WebVttRenderer
-android.media.audiofx.AcousticEchoCanceler
android.media.audiofx.AudioEffect
android.media.audiofx.AudioEffect$Descriptor
-android.media.audiofx.AutomaticGainControl
android.media.audiofx.BassBoost
android.media.audiofx.BassBoost$Settings
android.media.audiofx.Equalizer
@@ -2540,12 +2610,20 @@ android.media.audiofx.PresetReverb
android.media.audiofx.Virtualizer
android.media.audiofx.Virtualizer$Settings
android.media.audiofx.Visualizer
+android.media.audiofx.Visualizer$OnDataCaptureListener
android.media.audiopolicy.AudioMix
android.media.audiopolicy.AudioMixingRule
android.media.audiopolicy.AudioMixingRule$AudioMixMatchCriterion
android.media.audiopolicy.AudioPolicyConfig
android.media.audiopolicy.IAudioPolicyCallback
android.media.audiopolicy.IAudioPolicyCallback$Stub
+android.media.browse.MediaBrowser
+android.media.browse.MediaBrowser$10
+android.media.browse.MediaBrowser$ConnectionCallback
+android.media.browse.MediaBrowser$MediaItem
+android.media.browse.MediaBrowser$MediaServiceConnection
+android.media.browse.MediaBrowser$MediaServiceConnection$1
+android.media.browse.MediaBrowser$ServiceCallbacks
android.media.midi.IMidiDeviceListener
android.media.midi.IMidiDeviceOpenCallback
android.media.midi.IMidiDeviceServer
@@ -2568,6 +2646,8 @@ android.media.projection.MediaProjectionManager$CallbackDelegate
android.media.session.IActiveSessionsListener
android.media.session.IActiveSessionsListener$Stub
android.media.session.IActiveSessionsListener$Stub$Proxy
+android.media.session.IOnMediaKeyListener
+android.media.session.IOnVolumeKeyLongPressListener
android.media.session.ISession
android.media.session.ISession$Stub
android.media.session.ISession$Stub$Proxy
@@ -2616,12 +2696,12 @@ android.media.tv.TvInputHardwareInfo$Builder
android.media.tv.TvInputManager
android.media.tv.TvStreamConfig
android.media.tv.TvStreamConfig$Builder
+android.metrics.LogMaker
android.mtp.MtpDatabase
android.mtp.MtpDevice
android.mtp.MtpDeviceInfo
android.mtp.MtpEvent
android.mtp.MtpObjectInfo
-android.mtp.MtpObjectInfo$Builder
android.mtp.MtpPropertyGroup
android.mtp.MtpPropertyList
android.mtp.MtpServer
@@ -2631,14 +2711,13 @@ android.net.ConnectivityManager
android.net.ConnectivityManager$CallbackHandler
android.net.ConnectivityManager$NetworkCallback
android.net.ConnectivityManager$OnNetworkActiveListener
-android.net.ConnectivityManager$OnStartTetheringCallback
android.net.ConnectivityManager$PacketKeepalive
android.net.ConnectivityManager$PacketKeepaliveCallback
android.net.ConnectivityMetricsEvent
android.net.ConnectivityMetricsEvent$1
android.net.ConnectivityMetricsEvent$Reference
-android.net.ConnectivityMetricsLogger
android.net.ConnectivityThread
+android.net.ConnectivityThread$Singleton
android.net.Credentials
android.net.DataUsageRequest
android.net.DhcpInfo
@@ -2648,16 +2727,22 @@ android.net.DhcpResults$1
android.net.EthernetManager
android.net.EthernetManager$1
android.net.EthernetManager$2
+android.net.EventLogTags
android.net.IConnectivityManager
android.net.IConnectivityManager$Stub
android.net.IConnectivityManager$Stub$Proxy
android.net.IConnectivityMetricsLogger
android.net.IConnectivityMetricsLogger$Stub
-android.net.IConnectivityMetricsLogger$Stub$Proxy
android.net.IEthernetManager
android.net.IEthernetManager$Stub
android.net.IEthernetServiceListener
android.net.IEthernetServiceListener$Stub
+android.net.IIpConnectivityMetrics
+android.net.IIpConnectivityMetrics$Stub
+android.net.INetd
+android.net.INetd$Stub
+android.net.INetd$Stub$Proxy
+android.net.INetdEventCallback
android.net.INetworkManagementEventObserver
android.net.INetworkManagementEventObserver$Stub
android.net.INetworkPolicyListener
@@ -2668,6 +2753,7 @@ android.net.INetworkPolicyManager$Stub
android.net.INetworkPolicyManager$Stub$Proxy
android.net.INetworkScoreCache
android.net.INetworkScoreCache$Stub
+android.net.INetworkScoreCache$Stub$Proxy
android.net.INetworkScoreService
android.net.INetworkScoreService$Stub
android.net.INetworkScoreService$Stub$Proxy
@@ -2703,6 +2789,7 @@ android.net.Network$1
android.net.Network$2
android.net.Network$NetworkBoundSocketFactory
android.net.NetworkAgent
+android.net.NetworkBadging
android.net.NetworkCapabilities
android.net.NetworkCapabilities$1
android.net.NetworkConfig
@@ -2724,6 +2811,7 @@ android.net.NetworkQuotaInfo
android.net.NetworkRequest
android.net.NetworkRequest$1
android.net.NetworkRequest$Builder
+android.net.NetworkRequest$Type
android.net.NetworkScoreManager
android.net.NetworkScorerAppManager
android.net.NetworkState
@@ -2744,13 +2832,17 @@ android.net.ParseException
android.net.Proxy
android.net.ProxyInfo
android.net.ProxyInfo$1
+android.net.RecommendationRequest
+android.net.RecommendationResult
android.net.RouteInfo
android.net.RouteInfo$1
android.net.RssiCurve
+android.net.RssiCurve$1
android.net.SSLCertificateSocketFactory
android.net.SSLCertificateSocketFactory$1
android.net.SSLSessionCache
android.net.ScoredNetwork
+android.net.ScoredNetwork$1
android.net.SntpClient
android.net.StaticIpConfiguration
android.net.StaticIpConfiguration$1
@@ -2770,7 +2862,7 @@ android.net.Uri$PathSegments
android.net.Uri$PathSegmentsBuilder
android.net.Uri$StringUri
android.net.UrlQuerySanitizer
-android.net.UrlQuerySanitizer$ValueSanitizer
+android.net.VpnService
android.net.WebAddress
android.net.WifiKey
android.net.WifiKey$1
@@ -2783,19 +2875,23 @@ android.net.http.HttpResponseCache
android.net.http.SslCertificate
android.net.http.SslError
android.net.http.X509TrustManagerExtensions
+android.net.metrics.ApfProgramEvent
+android.net.metrics.ApfProgramEvent$1
+android.net.metrics.ConnectStats
android.net.metrics.DefaultNetworkEvent
android.net.metrics.DefaultNetworkEvent$1
android.net.metrics.DhcpClientEvent
android.net.metrics.DhcpClientEvent$1
android.net.metrics.DnsEvent
android.net.metrics.DnsEvent$1
-android.net.metrics.IpConnectivityEvent
+android.net.metrics.IpConnectivityLog
android.net.metrics.IpManagerEvent
android.net.metrics.IpManagerEvent$1
-android.net.metrics.IpReachabilityEvent
-android.net.metrics.IpReachabilityEvent$1
android.net.metrics.NetworkEvent
android.net.metrics.NetworkEvent$1
+android.net.metrics.RaEvent
+android.net.metrics.RaEvent$1
+android.net.metrics.RaEvent$Builder
android.net.metrics.ValidationProbeEvent
android.net.metrics.ValidationProbeEvent$1
android.net.metrics.ValidationProbeEvent$Decoder
@@ -2805,8 +2901,6 @@ android.net.nsd.NsdManager
android.net.sip.ISipService
android.net.sip.ISipService$Stub
android.net.sip.SipManager
-android.net.sip.SipProfile
-android.net.sip.SipProfile$Builder
android.net.wifi.IRttManager
android.net.wifi.IRttManager$Stub
android.net.wifi.IRttManager$Stub$Proxy
@@ -2816,9 +2910,10 @@ android.net.wifi.IWifiManager$Stub$Proxy
android.net.wifi.IWifiScanner
android.net.wifi.IWifiScanner$Stub
android.net.wifi.IWifiScanner$Stub$Proxy
+android.net.wifi.ParcelUtil
+android.net.wifi.RssiPacketCountInfo
android.net.wifi.RttManager
android.net.wifi.RttManager$RttCapabilities
-android.net.wifi.RttManager$RttCapabilities$1
android.net.wifi.RttManager$RttListener
android.net.wifi.RttManager$RttResult
android.net.wifi.RttManager$ServiceHandler
@@ -2830,6 +2925,7 @@ android.net.wifi.SupplicantState
android.net.wifi.SupplicantState$1
android.net.wifi.WifiActivityEnergyInfo
android.net.wifi.WifiActivityEnergyInfo$1
+android.net.wifi.WifiChannel
android.net.wifi.WifiConfiguration
android.net.wifi.WifiConfiguration$1
android.net.wifi.WifiConfiguration$AuthAlgorithm
@@ -2843,9 +2939,6 @@ android.net.wifi.WifiConnectionStatistics
android.net.wifi.WifiConnectionStatistics$1
android.net.wifi.WifiEnterpriseConfig
android.net.wifi.WifiEnterpriseConfig$1
-android.net.wifi.WifiEnterpriseConfig$Eap
-android.net.wifi.WifiEnterpriseConfig$Phase2
-android.net.wifi.WifiEnterpriseConfig$SupplicantLoader
android.net.wifi.WifiInfo
android.net.wifi.WifiInfo$1
android.net.wifi.WifiLinkLayerStats
@@ -2854,25 +2947,30 @@ android.net.wifi.WifiManager
android.net.wifi.WifiManager$ActionListener
android.net.wifi.WifiManager$MulticastLock
android.net.wifi.WifiManager$WifiLock
+android.net.wifi.WifiNetworkScoreCache
+android.net.wifi.WifiNetworkScoreCache$CacheListener
android.net.wifi.WifiScanner
android.net.wifi.WifiScanner$ActionListener
android.net.wifi.WifiScanner$ChannelSpec
-android.net.wifi.WifiScanner$OperationResult
-android.net.wifi.WifiScanner$OperationResult$1
android.net.wifi.WifiScanner$ParcelableScanData
android.net.wifi.WifiScanner$ParcelableScanData$1
+android.net.wifi.WifiScanner$ParcelableScanResults
+android.net.wifi.WifiScanner$ParcelableScanResults$1
android.net.wifi.WifiScanner$PnoScanListener
android.net.wifi.WifiScanner$ScanData
android.net.wifi.WifiScanner$ScanData$1
android.net.wifi.WifiScanner$ScanListener
android.net.wifi.WifiScanner$ScanSettings
android.net.wifi.WifiScanner$ScanSettings$1
+android.net.wifi.WifiScanner$ScanSettings$HiddenNetwork
android.net.wifi.WifiScanner$ServiceHandler
android.net.wifi.WifiSsid
android.net.wifi.WifiSsid$1
+android.net.wifi.WifiWakeReasonAndCounts
android.net.wifi.WpsInfo
android.net.wifi.WpsInfo$1
-android.net.wifi.nan.WifiNanManager
+android.net.wifi.aware.WifiAwareManager
+android.net.wifi.hotspot2.PasspointConfiguration
android.net.wifi.p2p.IWifiP2pManager
android.net.wifi.p2p.IWifiP2pManager$Stub
android.net.wifi.p2p.WifiP2pConfig
@@ -2924,7 +3022,6 @@ android.nfc.NfcAdapter
android.nfc.NfcAdapter$1
android.nfc.NfcAdapter$CreateBeamUrisCallback
android.nfc.NfcAdapter$CreateNdefMessageCallback
-android.nfc.NfcAdapter$NfcUnlockHandler
android.nfc.NfcAdapter$OnNdefPushCompleteCallback
android.nfc.NfcEvent
android.nfc.NfcManager
@@ -2975,11 +3072,17 @@ android.opengl.GLSurfaceView$EglHelper
android.opengl.GLSurfaceView$GLThread
android.opengl.GLSurfaceView$GLThreadManager
android.opengl.GLSurfaceView$Renderer
+android.opengl.GLSurfaceView$SimpleEGLConfigChooser
android.opengl.GLU
android.opengl.GLUtils
android.opengl.Matrix
android.opengl.Visibility
+android.os.-$Lambda$0$-dncxFEc2F2bgG2fsIoC6FC6WNE
+android.os.-$Lambda$1$-dncxFEc2F2bgG2fsIoC6FC6WNE
+android.os.-$Lambda$5$6x30vPJhBKUfNY8tswxuZo3DCe0
+android.os.-$Lambda$67$OsaxDBgigpqjZN1F4C6nYRYm1YQ
android.os.AsyncResult
+android.os.AsyncTask
android.os.AsyncTask$1
android.os.AsyncTask$2
android.os.AsyncTask$3
@@ -2999,12 +3102,14 @@ android.os.BatteryProperties$1
android.os.BatteryStats
android.os.BatteryStats$BitDescription
android.os.BatteryStats$ControllerActivityCounter
+android.os.BatteryStats$Counter
android.os.BatteryStats$DailyItem
android.os.BatteryStats$HistoryEventTracker
android.os.BatteryStats$HistoryItem
android.os.BatteryStats$HistoryPrinter
android.os.BatteryStats$HistoryStepDetails
android.os.BatteryStats$HistoryTag
+android.os.BatteryStats$IntToString
android.os.BatteryStats$LevelStepTracker
android.os.BatteryStats$LongCounter
android.os.BatteryStats$PackageChange
@@ -3013,6 +3118,7 @@ android.os.BatteryStats$Uid
android.os.BatteryStats$Uid$Pid
android.os.BatteryStats$Uid$Pkg
android.os.BatteryStats$Uid$Pkg$Serv
+android.os.BatteryStats$Uid$Proc
android.os.BatteryStats$Uid$Sensor
android.os.BatteryStats$Uid$Wakelock
android.os.Binder
@@ -3041,16 +3147,20 @@ android.os.DropBoxManager$Entry$1
android.os.Environment
android.os.Environment$UserEnvironment
android.os.FactoryTest
-android.os.FileBridge
-android.os.FileBridge$FileBridgeOutputStream
+android.os.FileObserver
android.os.FileObserver$ObserverThread
android.os.FileUtils
+android.os.GraphicsEnvironment
android.os.Handler
android.os.Handler$BlockingRunnable
android.os.Handler$Callback
android.os.Handler$MessengerImpl
android.os.HandlerThread
android.os.HardwarePropertiesManager
+android.os.HwBinder
+android.os.HwBlob
+android.os.HwParcel
+android.os.HwRemoteBinder
android.os.IBatteryPropertiesListener
android.os.IBatteryPropertiesListener$Stub
android.os.IBatteryPropertiesRegistrar
@@ -3061,11 +3171,22 @@ android.os.IBinder$DeathRecipient
android.os.ICancellationSignal
android.os.ICancellationSignal$Stub
android.os.ICancellationSignal$Stub$Proxy
+android.os.IDeviceIdentifiersPolicyService
+android.os.IDeviceIdentifiersPolicyService$Stub
android.os.IDeviceIdleController
android.os.IDeviceIdleController$Stub
android.os.IDeviceIdleController$Stub$Proxy
android.os.IHardwarePropertiesManager
android.os.IHardwarePropertiesManager$Stub
+android.os.IHardwarePropertiesManager$Stub$Proxy
+android.os.IHwBinder
+android.os.IHwBinder$DeathRecipient
+android.os.IHwInterface
+android.os.IIncidentManager
+android.os.IIncidentManager$Stub
+android.os.IInstalld
+android.os.IInstalld$Stub
+android.os.IInstalld$Stub$Proxy
android.os.IInterface
android.os.IMaintenanceActivityListener
android.os.IMessenger
@@ -3083,10 +3204,8 @@ android.os.IPowerManager$Stub$Proxy
android.os.IProcessInfoService
android.os.IProcessInfoService$Stub
android.os.IProgressListener
-android.os.IProgressListener$Stub
android.os.IRecoverySystem
android.os.IRecoverySystem$Stub
-android.os.IRecoverySystem$Stub$Proxy
android.os.IRecoverySystemProgressListener
android.os.IRemoteCallback
android.os.IRemoteCallback$Stub
@@ -3102,6 +3221,7 @@ android.os.IUserManager$Stub$Proxy
android.os.IVibratorService
android.os.IVibratorService$Stub
android.os.IVibratorService$Stub$Proxy
+android.os.IncidentManager
android.os.LocaleList
android.os.LocaleList$1
android.os.Looper
@@ -3114,7 +3234,6 @@ android.os.MessageQueue$IdleHandler
android.os.MessageQueue$OnFileDescriptorEventListener
android.os.Messenger
android.os.Messenger$1
-android.os.NetworkOnMainThreadException
android.os.NullVibrator
android.os.OperationCanceledException
android.os.Parcel
@@ -3140,6 +3259,8 @@ android.os.PatternMatcher$1
android.os.PersistableBundle
android.os.PersistableBundle$1
android.os.PersistableBundle$MyReadMapCallback
+android.os.PooledStringReader
+android.os.PooledStringWriter
android.os.PowerManager
android.os.PowerManager$WakeLock
android.os.PowerManager$WakeLock$1
@@ -3147,12 +3268,14 @@ android.os.PowerManagerInternal
android.os.PowerManagerInternal$LowPowerModeListener
android.os.Process
android.os.Process$ProcessStartResult
-android.os.Process$ZygoteState
android.os.RecoverySystem
-android.os.RecoverySystem$ProgressListener
android.os.Registrant
android.os.RegistrantList
android.os.RemoteCallback
+android.os.RemoteCallback$1
+android.os.RemoteCallback$2
+android.os.RemoteCallback$3
+android.os.RemoteCallback$OnResultListener
android.os.RemoteCallbackList
android.os.RemoteCallbackList$Callback
android.os.RemoteException
@@ -3162,9 +3285,13 @@ android.os.ResultReceiver$MyResultReceiver
android.os.ResultReceiver$MyRunnable
android.os.SELinux
android.os.ServiceManager
+android.os.ServiceManager$ServiceNotFoundException
android.os.ServiceManagerNative
android.os.ServiceManagerProxy
android.os.ServiceSpecificException
+android.os.ShellCallback
+android.os.ShellCallback$1
+android.os.ShellCommand
android.os.StatFs
android.os.StrictMode
android.os.StrictMode$1
@@ -3190,6 +3317,7 @@ android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
android.os.StrictMode$ViolationInfo
+android.os.StrictMode$ViolationInfo$1
android.os.StrictMode$VmPolicy
android.os.StrictMode$VmPolicy$Builder
android.os.SynchronousResultReceiver
@@ -3202,11 +3330,9 @@ android.os.SystemService$State
android.os.SystemVibrator
android.os.TokenWatcher
android.os.TokenWatcher$1
-android.os.TokenWatcher$Death
android.os.Trace
android.os.Trace$1
android.os.TransactionTooLargeException
-android.os.TransactionTracker
android.os.UEventObserver
android.os.UEventObserver$UEvent
android.os.UEventObserver$UEventThread
@@ -3219,26 +3345,30 @@ android.os.UserManagerInternal$UserRestrictionsListener
android.os.Vibrator
android.os.WorkSource
android.os.WorkSource$1
+android.os.ZygoteProcess
+android.os.ZygoteProcess$ZygoteState
android.os.ZygoteStartFailedEx
+android.os.health.HealthStats
android.os.health.HealthStatsParceler
android.os.health.SystemHealthManager
+android.os.health.TimerStat
android.os.storage.DiskInfo
android.os.storage.DiskInfo$1
-android.os.storage.IStorageManager
-android.os.storage.IStorageManager$Stub
-android.os.storage.IStorageManager$Stub$Proxy
+android.os.storage.IObbActionListener
+android.os.storage.IObbActionListener$Stub
android.os.storage.IStorageEventListener
android.os.storage.IStorageEventListener$Stub
android.os.storage.IStorageEventListener$Stub$Proxy
+android.os.storage.IStorageManager
+android.os.storage.IStorageManager$Stub
+android.os.storage.IStorageManager$Stub$Proxy
android.os.storage.IStorageShutdownObserver
-android.os.storage.IObbActionListener
-android.os.storage.IObbActionListener$Stub
-android.os.storage.StorageManagerInternal
-android.os.storage.StorageManagerInternal$ExternalStorageMountPolicy
android.os.storage.StorageEventListener
android.os.storage.StorageManager
android.os.storage.StorageManager$ObbActionListener
android.os.storage.StorageManager$StorageEventListenerDelegate
+android.os.storage.StorageManagerInternal
+android.os.storage.StorageManagerInternal$ExternalStorageMountPolicy
android.os.storage.StorageVolume
android.os.storage.StorageVolume$1
android.os.storage.VolumeInfo
@@ -3246,30 +3376,30 @@ android.os.storage.VolumeInfo$1
android.os.storage.VolumeInfo$2
android.os.storage.VolumeRecord
android.os.storage.VolumeRecord$1
+android.permissionpresenterservice.RuntimePermissionPresenterService
+android.permissionpresenterservice.RuntimePermissionPresenterService$1
+android.permissionpresenterservice.RuntimePermissionPresenterService$MyHandler
+android.preference.CheckBoxPreference
android.preference.DialogPreference
-android.preference.GenericInflater
android.preference.GenericInflater$Parent
android.preference.ListPreference
android.preference.Preference
+android.preference.Preference$BaseSavedState
+android.preference.Preference$BaseSavedState$1
android.preference.Preference$OnPreferenceChangeInternalListener
android.preference.Preference$OnPreferenceChangeListener
android.preference.Preference$OnPreferenceClickListener
android.preference.PreferenceActivity
-android.preference.PreferenceActivity$1
-android.preference.PreferenceActivity$Header
-android.preference.PreferenceActivity$Header$1
android.preference.PreferenceFragment
android.preference.PreferenceFragment$1
android.preference.PreferenceFragment$2
android.preference.PreferenceFragment$3
android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
android.preference.PreferenceFrameLayout
-android.preference.PreferenceFrameLayout$LayoutParams
android.preference.PreferenceGroup
android.preference.PreferenceGroupAdapter
android.preference.PreferenceGroupAdapter$1
android.preference.PreferenceGroupAdapter$PreferenceLayout
-android.preference.PreferenceInflater
android.preference.PreferenceManager
android.preference.PreferenceManager$OnActivityDestroyListener
android.preference.PreferenceManager$OnPreferenceTreeClickListener
@@ -3284,8 +3414,6 @@ android.preference.SwitchPreference$Listener
android.preference.TwoStatePreference
android.print.IPrintDocumentAdapter
android.print.IPrintJobStateChangeListener
-android.print.IPrintJobStateChangeListener$Stub
-android.print.IPrintJobStateChangeListener$Stub$Proxy
android.print.IPrintManager
android.print.IPrintManager$Stub
android.print.IPrintManager$Stub$Proxy
@@ -3297,7 +3425,6 @@ android.print.IPrintSpooler$Stub
android.print.IPrintSpooler$Stub$Proxy
android.print.IPrintSpoolerCallbacks
android.print.IPrintSpoolerCallbacks$Stub
-android.print.IPrintSpoolerCallbacks$Stub$Proxy
android.print.IPrintSpoolerClient
android.print.IPrintSpoolerClient$Stub
android.print.IPrintSpoolerClient$Stub$Proxy
@@ -3313,31 +3440,25 @@ android.print.PrintDocumentAdapter$LayoutResultCallback
android.print.PrintDocumentAdapter$WriteResultCallback
android.print.PrintDocumentInfo
android.print.PrintDocumentInfo$Builder
-android.print.PrintJob
android.print.PrintJobId
android.print.PrintJobInfo
-android.print.PrintJobInfo$1
android.print.PrintManager
android.print.PrintManager$1
-android.print.PrintManager$PrintJobStateChangeListener
-android.print.PrintManager$PrintJobStateChangeListenerWrapper
android.print.PrintManager$PrintServicesChangeListener
android.print.PrintManager$PrintServicesChangeListenerWrapper
android.print.PrintServicesLoader
android.print.PrintServicesLoader$1
android.print.PrintServicesLoader$MyHandler
android.print.PrinterId
-android.print.pdf.PrintedPdfDocument
android.printservice.IPrintServiceClient
android.printservice.IPrintServiceClient$Stub
android.printservice.PrintServiceInfo
android.printservice.PrintServiceInfo$1
android.printservice.recommendation.IRecommendationsChangeListener
+android.provider.-$Lambda$46$87WmhkvObehVg0OMBzwa_MTVV8g
android.provider.BaseColumns
android.provider.BlockedNumberContract
android.provider.BlockedNumberContract$BlockedNumbers
-android.provider.BlockedNumberContract$SystemContract
-android.provider.BlockedNumberContract$SystemContract$BlockSuppressionStatus
android.provider.CalendarContract
android.provider.CalendarContract$Attendees
android.provider.CalendarContract$AttendeesColumns
@@ -3366,12 +3487,16 @@ android.provider.CalendarContract$SyncState
android.provider.CallLog
android.provider.CallLog$Calls
android.provider.Contacts
+android.provider.Contacts$ContactMethods
+android.provider.Contacts$ContactMethodsColumns
+android.provider.Contacts$PeopleColumns
android.provider.ContactsContract
android.provider.ContactsContract$AggregationExceptions
android.provider.ContactsContract$BaseSyncColumns
android.provider.ContactsContract$CommonDataKinds$BaseTypes
android.provider.ContactsContract$CommonDataKinds$Callable
android.provider.ContactsContract$CommonDataKinds$CommonColumns
+android.provider.ContactsContract$CommonDataKinds$Contactables
android.provider.ContactsContract$CommonDataKinds$Email
android.provider.ContactsContract$CommonDataKinds$Event
android.provider.ContactsContract$CommonDataKinds$Im
@@ -3384,7 +3509,6 @@ android.provider.ContactsContract$ContactNameColumns
android.provider.ContactsContract$ContactOptionsColumns
android.provider.ContactsContract$ContactStatusColumns
android.provider.ContactsContract$Contacts
-android.provider.ContactsContract$Contacts$AggregationSuggestions$Builder
android.provider.ContactsContract$ContactsColumns
android.provider.ContactsContract$Data
android.provider.ContactsContract$DataColumns
@@ -3396,7 +3520,6 @@ android.provider.ContactsContract$DeletedContactsColumns
android.provider.ContactsContract$Directory
android.provider.ContactsContract$DisplayPhoto
android.provider.ContactsContract$Groups
-android.provider.ContactsContract$Groups$EntityIteratorImpl
android.provider.ContactsContract$GroupsColumns
android.provider.ContactsContract$MetadataSync
android.provider.ContactsContract$MetadataSyncColumns
@@ -3407,7 +3530,6 @@ android.provider.ContactsContract$Profile
android.provider.ContactsContract$ProviderStatus
android.provider.ContactsContract$QuickContact
android.provider.ContactsContract$RawContacts
-android.provider.ContactsContract$RawContacts$EntityIteratorImpl
android.provider.ContactsContract$RawContactsColumns
android.provider.ContactsContract$RawContactsEntity
android.provider.ContactsContract$Settings
@@ -3417,8 +3539,8 @@ android.provider.ContactsContract$StreamItems
android.provider.ContactsContract$StreamItemsColumns
android.provider.ContactsContract$SyncColumns
android.provider.ContactsContract$SyncState
+android.provider.ContactsInternal
android.provider.DocumentsContract
-android.provider.DocumentsContract$Root
android.provider.DocumentsProvider
android.provider.Downloads
android.provider.Downloads$Impl
@@ -3449,12 +3571,11 @@ android.provider.SearchIndexableResource
android.provider.SearchIndexablesContract
android.provider.SearchIndexablesProvider
android.provider.SearchRecentSuggestions
-android.provider.SearchRecentSuggestions$1
android.provider.Settings
+android.provider.Settings$ContentProviderHolder
android.provider.Settings$GenerationTracker
android.provider.Settings$Global
android.provider.Settings$NameValueCache
-android.provider.Settings$NameValueCache$-java_lang_String_getStringForUser_android_content_ContentResolver_cr_java_lang_String_name_int_userHandle_LambdaImpl0
android.provider.Settings$NameValueTable
android.provider.Settings$Secure
android.provider.Settings$SettingNotFoundException
@@ -3491,18 +3612,21 @@ android.provider.UserDictionary$Words
android.provider.VoicemailContract$Status
android.provider.VoicemailContract$Voicemails
android.renderscript.Allocation
+android.renderscript.Allocation$MipmapControl
android.renderscript.BaseObj
android.renderscript.Element
-android.renderscript.Matrix4f
-android.renderscript.RSRuntimeException
+android.renderscript.Element$DataKind
+android.renderscript.Element$DataType
android.renderscript.RenderScript
+android.renderscript.RenderScript$ContextType
+android.renderscript.RenderScript$MessageThread
android.renderscript.RenderScriptCacheDir
android.renderscript.Script
android.renderscript.ScriptIntrinsic
android.renderscript.ScriptIntrinsicBlur
android.renderscript.Type
-android.security.Credentials
-android.security.FrameworkNetworkSecurityPolicy
+android.renderscript.Type$Builder
+android.renderscript.Type$CubemapFace
android.security.GateKeeper
android.security.IKeyChainService
android.security.IKeyChainService$Stub
@@ -3513,10 +3637,11 @@ android.security.IKeystoreService$Stub$Proxy
android.security.KeyChain
android.security.KeyChain$1
android.security.KeyChain$KeyChainConnection
-android.security.KeyChainAliasCallback
android.security.KeyStore
-android.security.KeyStore$State
android.security.NetworkSecurityPolicy
+android.security.keymaster.IKeyAttestationApplicationIdProvider
+android.security.keymaster.IKeyAttestationApplicationIdProvider$Stub
+android.security.keymaster.KeyAttestationApplicationId
android.security.keymaster.KeymasterArguments
android.security.keymaster.KeymasterArguments$1
android.security.keystore.AndroidKeyStoreBCWorkaroundProvider
@@ -3558,12 +3683,20 @@ android.security.net.config.PinSet
android.security.net.config.RootTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.security.net.config.SystemCertificateSource
-android.security.net.config.TrustAnchor
+android.security.net.config.SystemCertificateSource$NoPreloadHolder
android.security.net.config.TrustedCertificateStoreAdapter
android.security.net.config.UserCertificateSource
+android.security.net.config.UserCertificateSource$NoPreloadHolder
+android.security.net.config.XmlConfigSource
+android.security.net.config.XmlConfigSource$ParserException
+android.service.autofill.IAutoFillManagerService
+android.service.autofill.IAutoFillManagerService$Stub
+android.service.autofill.IAutoFillManagerService$Stub$Proxy
android.service.carrier.CarrierIdentifier
+android.service.carrier.CarrierIdentifier$1
android.service.carrier.ICarrierService
android.service.carrier.ICarrierService$Stub
+android.service.carrier.ICarrierService$Stub$Proxy
android.service.chooser.ChooserTarget
android.service.chooser.ChooserTargetService
android.service.dreams.DreamManagerInternal
@@ -3579,13 +3712,22 @@ android.service.dreams.IDreamManager$Stub$Proxy
android.service.dreams.IDreamService
android.service.dreams.IDreamService$Stub
android.service.dreams.IDreamService$Stub$Proxy
-android.service.gatekeeper.GateKeeperResponse
-android.service.gatekeeper.GateKeeperResponse$1
android.service.gatekeeper.IGateKeeperService
android.service.gatekeeper.IGateKeeperService$Stub
android.service.gatekeeper.IGateKeeperService$Stub$Proxy
-android.service.media.CameraPrewarmService
+android.service.media.IMediaBrowserService
+android.service.media.IMediaBrowserService$Stub
+android.service.media.IMediaBrowserService$Stub$Proxy
+android.service.media.IMediaBrowserServiceCallbacks
+android.service.media.IMediaBrowserServiceCallbacks$Stub
+android.service.media.IMediaBrowserServiceCallbacks$Stub$Proxy
android.service.media.MediaBrowserService
+android.service.media.MediaBrowserService$1
+android.service.media.MediaBrowserService$BrowserRoot
+android.service.media.MediaBrowserService$ConnectionRecord
+android.service.media.MediaBrowserService$Result
+android.service.media.MediaBrowserService$ServiceBinder
+android.service.media.MediaBrowserService$ServiceBinder$1
android.service.notification.Adjustment
android.service.notification.Condition
android.service.notification.Condition$1
@@ -3596,6 +3738,7 @@ android.service.notification.IConditionListener
android.service.notification.IConditionListener$Stub
android.service.notification.IConditionProvider
android.service.notification.IConditionProvider$Stub
+android.service.notification.IConditionProvider$Stub$Proxy
android.service.notification.INotificationListener
android.service.notification.INotificationListener$Stub
android.service.notification.INotificationListener$Stub$Proxy
@@ -3608,9 +3751,6 @@ android.service.notification.NotificationListenerService$NotificationListenerWra
android.service.notification.NotificationListenerService$Ranking
android.service.notification.NotificationListenerService$RankingMap
android.service.notification.NotificationListenerService$RankingMap$1
-android.service.notification.NotificationAssistantService
-android.service.notification.NotificationAssistantService$MyHandler
-android.service.notification.NotificationAssistantService$NotificationRankingServiceWrapper
android.service.notification.NotificationRankingUpdate
android.service.notification.NotificationRankingUpdate$1
android.service.notification.StatusBarNotification
@@ -3619,9 +3759,7 @@ android.service.notification.ZenModeConfig
android.service.notification.ZenModeConfig$1
android.service.notification.ZenModeConfig$Diff
android.service.notification.ZenModeConfig$EventInfo
-android.service.notification.ZenModeConfig$Migration
android.service.notification.ZenModeConfig$ScheduleInfo
-android.service.notification.ZenModeConfig$XmlV1
android.service.notification.ZenModeConfig$ZenRule
android.service.notification.ZenModeConfig$ZenRule$1
android.service.persistentdata.IPersistentDataBlockService
@@ -3632,6 +3770,7 @@ android.service.quicksettings.IQSService
android.service.quicksettings.IQSService$Stub
android.service.quicksettings.IQSTileService
android.service.quicksettings.Tile
+android.service.quicksettings.Tile$1
android.service.quicksettings.TileService
android.service.textservice.SpellCheckerService
android.service.textservice.SpellCheckerService$InternalISpellCheckerSession
@@ -3640,16 +3779,6 @@ android.service.textservice.SpellCheckerService$SentenceLevelAdapter$SentenceTex
android.service.textservice.SpellCheckerService$SentenceLevelAdapter$SentenceWordItem
android.service.textservice.SpellCheckerService$Session
android.service.textservice.SpellCheckerService$SpellCheckerServiceBinder
-android.service.trust.ITrustAgentService
-android.service.trust.ITrustAgentService$Stub
-android.service.trust.ITrustAgentService$Stub$Proxy
-android.service.trust.ITrustAgentServiceCallback
-android.service.trust.ITrustAgentServiceCallback$Stub
-android.service.trust.ITrustAgentServiceCallback$Stub$Proxy
-android.service.trust.TrustAgentService
-android.service.trust.TrustAgentService$1
-android.service.trust.TrustAgentService$ConfigurationData
-android.service.trust.TrustAgentService$TrustAgentServiceWrapper
android.service.voice.AlwaysOnHotwordDetector
android.service.voice.AlwaysOnHotwordDetector$Callback
android.service.voice.AlwaysOnHotwordDetector$EventPayload
@@ -3660,12 +3789,33 @@ android.service.voice.IVoiceInteractionService
android.service.voice.IVoiceInteractionService$Stub
android.service.voice.IVoiceInteractionService$Stub$Proxy
android.service.voice.IVoiceInteractionSession
+android.service.voice.IVoiceInteractionSession$Stub
+android.service.voice.IVoiceInteractionSession$Stub$Proxy
+android.service.voice.IVoiceInteractionSessionService
+android.service.voice.IVoiceInteractionSessionService$Stub
+android.service.voice.IVoiceInteractionSessionService$Stub$Proxy
android.service.voice.VoiceInteractionManagerInternal
android.service.voice.VoiceInteractionService
android.service.voice.VoiceInteractionService$1
android.service.voice.VoiceInteractionService$MyHandler
android.service.voice.VoiceInteractionServiceInfo
android.service.voice.VoiceInteractionSession
+android.service.voice.VoiceInteractionSession$1
+android.service.voice.VoiceInteractionSession$2
+android.service.voice.VoiceInteractionSession$2$1
+android.service.voice.VoiceInteractionSession$3
+android.service.voice.VoiceInteractionSession$4
+android.service.voice.VoiceInteractionSession$AbortVoiceRequest
+android.service.voice.VoiceInteractionSession$CommandRequest
+android.service.voice.VoiceInteractionSession$CompleteVoiceRequest
+android.service.voice.VoiceInteractionSession$ConfirmationRequest
+android.service.voice.VoiceInteractionSession$Insets
+android.service.voice.VoiceInteractionSession$MyCallbacks
+android.service.voice.VoiceInteractionSession$PickOptionRequest
+android.service.voice.VoiceInteractionSession$Request
+android.service.voice.VoiceInteractionSessionService
+android.service.voice.VoiceInteractionSessionService$1
+android.service.voice.VoiceInteractionSessionService$2
android.service.vr.IVrManager
android.service.vr.IVrManager$Stub
android.service.vr.IVrManager$Stub$Proxy
@@ -3732,6 +3882,7 @@ android.system.StructAddrinfo
android.system.StructFlock
android.system.StructGroupReq
android.system.StructGroupSourceReq
+android.system.StructIfaddrs
android.system.StructLinger
android.system.StructPasswd
android.system.StructPollfd
@@ -3741,6 +3892,7 @@ android.system.StructTimeval
android.system.StructUcred
android.system.StructUtsname
android.system.UnixSocketAddress
+android.telecom.-$Lambda$3$afyb_ODGzn3xMew6fjs8ANSIdVo
android.telecom.AudioState
android.telecom.AudioState$1
android.telecom.Call
@@ -3759,8 +3911,8 @@ android.telecom.Conferenceable
android.telecom.Connection
android.telecom.Connection$1
android.telecom.Connection$2
+android.telecom.Connection$FailureSignalingConnection
android.telecom.Connection$Listener
-android.telecom.Connection$VideoProvider
android.telecom.ConnectionRequest
android.telecom.ConnectionRequest$1
android.telecom.ConnectionService
@@ -3782,12 +3934,29 @@ android.telecom.InCallService$1
android.telecom.InCallService$2
android.telecom.InCallService$InCallServiceBinder
android.telecom.InCallService$VideoCall
-android.telecom.InCallService$VideoCall$Callback
android.telecom.Log
android.telecom.Log$1
+android.telecom.Logging.-$Lambda$2$OwO3BlCgqcOx28O1BaOAPVPor24
+android.telecom.Logging.-$Lambda$35$OwO3BlCgqcOx28O1BaOAPVPor24
+android.telecom.Logging.-$Lambda$47$OwO3BlCgqcOx28O1BaOAPVPor24
+android.telecom.Logging.EventManager
+android.telecom.Logging.EventManager$Event
+android.telecom.Logging.EventManager$EventListener
+android.telecom.Logging.EventManager$EventRecord
+android.telecom.Logging.EventManager$Loggable
+android.telecom.Logging.EventManager$TimedEventPair
+android.telecom.Logging.Runnable
+android.telecom.Logging.Runnable$1
+android.telecom.Logging.Session
+android.telecom.Logging.Session$Info
+android.telecom.Logging.Session$Info$1
+android.telecom.Logging.SessionManager
+android.telecom.Logging.SessionManager$ICurrentThreadId
+android.telecom.Logging.SessionManager$ISessionCleanupTimeoutMs
+android.telecom.Logging.SessionManager$ISessionIdQueryHandler
+android.telecom.Logging.SessionManager$ISessionListener
android.telecom.ParcelableCall
android.telecom.ParcelableCall$1
-android.telecom.ParcelableCallAnalytics
android.telecom.ParcelableConference
android.telecom.ParcelableConnection
android.telecom.ParcelableConnection$1
@@ -3799,40 +3968,41 @@ android.telecom.PhoneAccount$Builder
android.telecom.PhoneAccountHandle
android.telecom.PhoneAccountHandle$1
android.telecom.RemoteConnectionManager
-android.telecom.Response
android.telecom.StatusHints
+android.telecom.TelecomAnalytics
+android.telecom.TelecomAnalytics$SessionTiming
+android.telecom.TelecomAnalytics$SessionTiming$1
android.telecom.TelecomManager
+android.telecom.TimedEvent
android.telecom.VideoProfile
android.telecom.VideoProfile$1
-android.telecom.Voicemail
-android.telecom.Voicemail$Builder
android.telephony.CarrierConfigManager
android.telephony.CellBroadcastMessage
android.telephony.CellIdentityCdma
android.telephony.CellIdentityGsm
android.telephony.CellIdentityLte
-android.telephony.CellIdentityLte$1
android.telephony.CellIdentityWcdma
+android.telephony.CellIdentityWcdma$1
android.telephony.CellInfo
android.telephony.CellInfo$1
android.telephony.CellInfoCdma
android.telephony.CellInfoGsm
android.telephony.CellInfoLte
-android.telephony.CellInfoLte$1
android.telephony.CellInfoWcdma
+android.telephony.CellInfoWcdma$1
android.telephony.CellLocation
android.telephony.CellSignalStrength
android.telephony.CellSignalStrengthCdma
android.telephony.CellSignalStrengthGsm
android.telephony.CellSignalStrengthLte
-android.telephony.CellSignalStrengthLte$1
android.telephony.CellSignalStrengthWcdma
+android.telephony.CellSignalStrengthWcdma$1
+android.telephony.ClientRequestStats
+android.telephony.ClientRequestStats$1
android.telephony.DisconnectCause
android.telephony.IccOpenLogicalChannelResponse
android.telephony.ModemActivityInfo
android.telephony.ModemActivityInfo$1
-android.telephony.NeighboringCellInfo
-android.telephony.NeighboringCellInfo$1
android.telephony.PhoneNumberFormattingTextWatcher
android.telephony.PhoneNumberUtils
android.telephony.PhoneStateListener
@@ -3843,7 +4013,6 @@ android.telephony.PreciseCallState$1
android.telephony.PreciseDataConnectionState
android.telephony.PreciseDataConnectionState$1
android.telephony.RadioAccessFamily
-android.telephony.RadioAccessFamily$1
android.telephony.Rlog
android.telephony.ServiceState
android.telephony.ServiceState$1
@@ -3858,26 +4027,41 @@ android.telephony.SubscriptionManager
android.telephony.SubscriptionManager$OnSubscriptionsChangedListener
android.telephony.SubscriptionManager$OnSubscriptionsChangedListener$1
android.telephony.SubscriptionManager$OnSubscriptionsChangedListener$2
+android.telephony.TelephonyHistogram
+android.telephony.TelephonyHistogram$1
android.telephony.TelephonyManager
android.telephony.TelephonyManager$MultiSimVariants
+android.telephony.VisualVoicemailSmsFilterSettings
android.telephony.VoLteServiceState
android.telephony.VoLteServiceState$1
android.telephony.cdma.CdmaCellLocation
+android.telephony.cdma.CdmaSmsCbProgramData
android.telephony.gsm.GsmCellLocation
android.telephony.gsm.SmsMessage
android.text.AndroidBidi
android.text.AndroidCharacter
android.text.Annotation
-android.text.AutoText
android.text.BidiFormatter
android.text.BidiFormatter$DirectionalityEstimator
android.text.BoringLayout
android.text.BoringLayout$Metrics
+android.text.CharSequenceCharacterIterator
android.text.ClipboardManager
android.text.DynamicLayout
android.text.DynamicLayout$ChangeWatcher
android.text.Editable
android.text.Editable$Factory
+android.text.FontConfig
+android.text.FontConfig$1
+android.text.FontConfig$Alias
+android.text.FontConfig$Alias$1
+android.text.FontConfig$Axis
+android.text.FontConfig$Axis$1
+android.text.FontConfig$Family
+android.text.FontConfig$Family$1
+android.text.FontConfig$Font
+android.text.FontConfig$Font$1
+android.text.FontManager
android.text.GetChars
android.text.GraphicsOperations
android.text.Html
@@ -3888,6 +4072,8 @@ android.text.HtmlToSpannedConverter
android.text.HtmlToSpannedConverter$Bold
android.text.HtmlToSpannedConverter$Href
android.text.Hyphenator
+android.text.ITextClassificationService
+android.text.ITextClassificationService$Stub
android.text.InputFilter
android.text.InputFilter$LengthFilter
android.text.InputType
@@ -3947,16 +4133,12 @@ android.text.method.ArrowKeyMovementMethod
android.text.method.BaseKeyListener
android.text.method.BaseMovementMethod
android.text.method.DialerKeyListener
-android.text.method.DigitsKeyListener
android.text.method.KeyListener
android.text.method.LinkMovementMethod
android.text.method.MetaKeyKeyListener
android.text.method.MovementMethod
android.text.method.NumberKeyListener
android.text.method.PasswordTransformationMethod
-android.text.method.PasswordTransformationMethod$PasswordCharSequence
-android.text.method.PasswordTransformationMethod$ViewReference
-android.text.method.PasswordTransformationMethod$Visible
android.text.method.QwertyKeyListener
android.text.method.QwertyKeyListener$Replaced
android.text.method.ReplacementTransformationMethod
@@ -3974,7 +4156,6 @@ android.text.method.TransformationMethod2
android.text.method.WordIterator
android.text.style.AbsoluteSizeSpan
android.text.style.AlignmentSpan
-android.text.style.AlignmentSpan$Standard
android.text.style.BackgroundColorSpan
android.text.style.BulletSpan
android.text.style.CharacterStyle
@@ -3993,7 +4174,6 @@ android.text.style.LineHeightSpan$WithDensity
android.text.style.MetricAffectingSpan
android.text.style.MetricAffectingSpan$Passthrough
android.text.style.ParagraphStyle
-android.text.style.QuoteSpan
android.text.style.RelativeSizeSpan
android.text.style.ReplacementSpan
android.text.style.SpellCheckSpan
@@ -4001,7 +4181,6 @@ android.text.style.StrikethroughSpan
android.text.style.StyleSpan
android.text.style.SubscriptSpan
android.text.style.SuggestionSpan
-android.text.style.SuggestionSpan$1
android.text.style.SuperscriptSpan
android.text.style.TabStopSpan
android.text.style.TextAppearanceSpan
@@ -4011,7 +4190,6 @@ android.text.style.TtsSpan$DigitsBuilder
android.text.style.TtsSpan$SemioticClassBuilder
android.text.style.TtsSpan$TelephoneBuilder
android.text.style.TtsSpan$TextBuilder
-android.text.style.TtsSpan$VerbatimBuilder
android.text.style.TypefaceSpan
android.text.style.URLSpan
android.text.style.UnderlineSpan
@@ -4027,7 +4205,6 @@ android.text.util.Linkify$MatchFilter
android.text.util.Linkify$TransformFilter
android.text.util.Rfc822Token
android.text.util.Rfc822Tokenizer
-android.transition.ArcMotion
android.transition.AutoTransition
android.transition.ChangeBounds
android.transition.ChangeBounds$1
@@ -4050,8 +4227,6 @@ android.transition.ChangeTransform$3
android.transition.ChangeTransform$GhostListener
android.transition.ChangeTransform$PathAnimatorMatrix
android.transition.ChangeTransform$Transforms
-android.transition.CircularPropagation
-android.transition.Explode
android.transition.Fade
android.transition.Fade$1
android.transition.Fade$FadeAnimatorListener
@@ -4073,7 +4248,6 @@ android.transition.Transition$1
android.transition.Transition$2
android.transition.Transition$3
android.transition.Transition$AnimationInfo
-android.transition.Transition$ArrayListManager
android.transition.Transition$EpicenterCallback
android.transition.Transition$TransitionListener
android.transition.Transition$TransitionListenerAdapter
@@ -4086,7 +4260,6 @@ android.transition.TransitionSet
android.transition.TransitionSet$1
android.transition.TransitionSet$TransitionSetListener
android.transition.TransitionUtils
-android.transition.TransitionUtils$MatrixEvaluator
android.transition.TransitionValues
android.transition.TransitionValuesMaps
android.transition.TranslationAnimationCreator
@@ -4108,7 +4281,7 @@ android.util.Base64
android.util.Base64$Coder
android.util.Base64$Decoder
android.util.Base64$Encoder
-android.util.Base64DataException
+android.util.BootTimingsTraceLog
android.util.ContainerHelpers
android.util.DebugUtils
android.util.DisplayMetrics
@@ -4129,12 +4302,14 @@ android.util.LocalLog$ReadOnlyLocalLog
android.util.Log
android.util.Log$1
android.util.Log$ImmediateLogWriter
-android.util.Log$TerribleFailure
+android.util.Log$NoPreloadHolder
android.util.Log$TerribleFailureHandler
android.util.LogPrinter
+android.util.LongArray
android.util.LongSparseArray
android.util.LongSparseLongArray
android.util.LruCache
+android.util.MalformedJsonException
android.util.MapCollections
android.util.MapCollections$ArrayIterator
android.util.MapCollections$EntrySet
@@ -4160,6 +4335,7 @@ android.util.Printer
android.util.Property
android.util.Range
android.util.Rational
+android.util.ReflectiveProperty
android.util.Singleton
android.util.Size
android.util.SizeF
@@ -4171,7 +4347,6 @@ android.util.SparseLongArray
android.util.Spline
android.util.Spline$MonotoneCubicSpline
android.util.StateSet
-android.util.StringBuilderPrinter
android.util.SuperNotCalledException
android.util.TimeFormatException
android.util.TimeUtils
@@ -4183,18 +4358,17 @@ android.util.Xml
android.util.Xml$Encoding
android.util.Xml$XmlSerializerFactory
android.util.apk.ApkSignatureSchemeV2Verifier
+android.util.apk.ApkSignatureSchemeV2Verifier$ByteBufferDataSource
+android.util.apk.ApkSignatureSchemeV2Verifier$DataSource
+android.util.apk.ApkSignatureSchemeV2Verifier$MemoryMappedFileDataSource
+android.util.apk.ApkSignatureSchemeV2Verifier$SignatureInfo
android.util.apk.ApkSignatureSchemeV2Verifier$SignatureNotFoundException
+android.util.apk.ApkSignatureSchemeV2Verifier$VerbatimX509Certificate
+android.util.apk.ApkSignatureSchemeV2Verifier$WrappedX509Certificate
android.util.apk.ZipUtils
android.util.jar.StrictJarFile
-android.util.jar.StrictJarFile$EntryIterator
-android.util.jar.StrictJarFile$JarFileInputStream
-android.util.jar.StrictJarFile$RAFStream
-android.util.jar.StrictJarFile$ZipInflaterInputStream
-android.util.jar.StrictJarManifest
-android.util.jar.StrictJarManifest$Chunk
-android.util.jar.StrictJarManifestReader
-android.util.jar.StrictJarVerifier
-android.util.jar.StrictJarVerifier$VerifierEntry
+android.view.-$Lambda$48$iU_USrtPm1XIm5H9QYQvXfBGDE4
+android.view.-$Lambda$49$iU_USrtPm1XIm5H9QYQvXfBGDE4
android.view.AbsSavedState
android.view.AbsSavedState$1
android.view.AbsSavedState$2
@@ -4218,8 +4392,6 @@ android.view.ContextMenu
android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
-android.view.Display$ColorTransform
-android.view.Display$ColorTransform$1
android.view.Display$HdrCapabilities
android.view.Display$HdrCapabilities$1
android.view.Display$Mode
@@ -4246,8 +4418,6 @@ android.view.GestureDetector$OnDoubleTapListener
android.view.GestureDetector$OnGestureListener
android.view.GestureDetector$SimpleOnGestureListener
android.view.GhostView
-android.view.GraphicBuffer
-android.view.GraphicBuffer$1
android.view.Gravity
android.view.HandlerActionQueue
android.view.HandlerActionQueue$HandlerAction
@@ -4265,8 +4435,15 @@ android.view.IGraphicsStats$Stub
android.view.IGraphicsStats$Stub$Proxy
android.view.IInputFilter
android.view.IOnKeyguardExitResult
+android.view.IPinnedStackController
+android.view.IPinnedStackController$Stub
+android.view.IPinnedStackController$Stub$Proxy
+android.view.IPinnedStackListener
+android.view.IPinnedStackListener$Stub
+android.view.IPinnedStackListener$Stub$Proxy
android.view.IRotationWatcher
android.view.IRotationWatcher$Stub
+android.view.IRotationWatcher$Stub$Proxy
android.view.IWindow
android.view.IWindow$Stub
android.view.IWindow$Stub$Proxy
@@ -4306,8 +4483,6 @@ android.view.KeyEvent
android.view.KeyEvent$1
android.view.KeyEvent$Callback
android.view.KeyEvent$DispatcherState
-android.view.KeyboardShortcutGroup
-android.view.KeyboardShortcutInfo
android.view.LayoutInflater
android.view.LayoutInflater$Factory
android.view.LayoutInflater$Factory2
@@ -4326,16 +4501,20 @@ android.view.MotionEvent$PointerCoords
android.view.MotionEvent$PointerProperties
android.view.NotificationHeaderView
android.view.NotificationHeaderView$1
+android.view.NotificationHeaderView$2
android.view.NotificationHeaderView$HeaderTouchListener
android.view.OrientationEventListener
android.view.OrientationEventListener$SensorEventListenerImpl
android.view.PointerIcon
android.view.PointerIcon$1
+android.view.RecordingCanvas
android.view.RemotableViewMethod
android.view.RenderNode
+android.view.RenderNode$NoImagePreloadHolder
android.view.RenderNodeAnimator
android.view.RenderNodeAnimator$1
android.view.RenderNodeAnimator$DelayedAnimationHelper
+android.view.RenderNodeAnimatorSetHelper
android.view.ScaleGestureDetector
android.view.ScaleGestureDetector$1
android.view.ScaleGestureDetector$OnScaleGestureListener
@@ -4346,6 +4525,7 @@ android.view.SubMenu
android.view.Surface
android.view.Surface$1
android.view.Surface$CompatibleCanvas
+android.view.Surface$HwuiContext
android.view.Surface$OutOfResourcesException
android.view.SurfaceControl
android.view.SurfaceControl$PhysicalDisplayInfo
@@ -4363,7 +4543,7 @@ android.view.TextureView
android.view.TextureView$1
android.view.TextureView$SurfaceTextureListener
android.view.ThreadedRenderer
-android.view.ThreadedRenderer$HardwareDrawCallbacks
+android.view.ThreadedRenderer$DrawCallbacks
android.view.ThreadedRenderer$ProcessInitializer
android.view.TouchDelegate
android.view.VelocityTracker
@@ -4411,21 +4591,24 @@ android.view.View$OnTouchListener
android.view.View$PerformClick
android.view.View$ScrollabilityCache
android.view.View$TintInfo
+android.view.View$TooltipInfo
android.view.View$TransformationInfo
android.view.View$UnsetPressedState
android.view.ViewAnimationUtils
android.view.ViewConfiguration
+android.view.ViewDebug$CapturedViewProperty
+android.view.ViewDebug$ExportedProperty
android.view.ViewDebug$HierarchyHandler
android.view.ViewGroup
android.view.ViewGroup$1
android.view.ViewGroup$2
android.view.ViewGroup$3
+android.view.ViewGroup$4
android.view.ViewGroup$LayoutParams
android.view.ViewGroup$MarginLayoutParams
android.view.ViewGroup$OnHierarchyChangeListener
android.view.ViewGroup$TouchTarget
android.view.ViewGroupOverlay
-android.view.ViewHierarchyEncoder
android.view.ViewManager
android.view.ViewOutlineProvider
android.view.ViewOutlineProvider$1
@@ -4488,6 +4671,7 @@ android.view.ViewTreeObserver$OnTouchModeChangeListener
android.view.Window
android.view.Window$Callback
android.view.Window$OnWindowDismissedCallback
+android.view.Window$OnWindowSwipeDismissedCallback
android.view.Window$WindowControllerCallback
android.view.WindowAnimationFrameStats
android.view.WindowAnimationFrameStats$1
@@ -4519,18 +4703,20 @@ android.view.WindowManagerPolicy$InputConsumer
android.view.WindowManagerPolicy$OnKeyguardExitResult
android.view.WindowManagerPolicy$PointerEventListener
android.view.WindowManagerPolicy$ScreenOnListener
+android.view.WindowManagerPolicy$StartingSurface
android.view.WindowManagerPolicy$WindowManagerFuncs
android.view.WindowManagerPolicy$WindowState
android.view.accessibility.AccessibilityEvent
-android.view.accessibility.AccessibilityEvent$1
android.view.accessibility.AccessibilityEventSource
android.view.accessibility.AccessibilityManager
android.view.accessibility.AccessibilityManager$1
+android.view.accessibility.AccessibilityManager$AccessibilityServicesStateChangeListener
android.view.accessibility.AccessibilityManager$AccessibilityStateChangeListener
android.view.accessibility.AccessibilityManager$HighTextContrastChangeListener
android.view.accessibility.AccessibilityManager$MyHandler
android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener
android.view.accessibility.AccessibilityNodeInfo
+android.view.accessibility.AccessibilityNodeInfo$1
android.view.accessibility.AccessibilityNodeInfo$AccessibilityAction
android.view.accessibility.AccessibilityNodeInfo$CollectionInfo
android.view.accessibility.AccessibilityNodeInfo$CollectionItemInfo
@@ -4560,6 +4746,8 @@ android.view.animation.Animation$Description
android.view.animation.Animation$NoImagePreloadHolder
android.view.animation.AnimationSet
android.view.animation.AnimationUtils
+android.view.animation.AnimationUtils$1
+android.view.animation.AnimationUtils$AnimationState
android.view.animation.BaseInterpolator
android.view.animation.ClipRectAnimation
android.view.animation.CycleInterpolator
@@ -4575,12 +4763,16 @@ android.view.animation.RotateAnimation
android.view.animation.ScaleAnimation
android.view.animation.Transformation
android.view.animation.TranslateAnimation
+android.view.autofill.AutoFillId
+android.view.autofill.AutoFillId$1
+android.view.autofill.AutoFillManager
+android.view.autofill.AutoFillType
+android.view.autofill.AutoFillType$1
android.view.inputmethod.BaseInputConnection
android.view.inputmethod.CompletionInfo
android.view.inputmethod.CompletionInfo$1
android.view.inputmethod.ComposingText
android.view.inputmethod.CorrectionInfo
-android.view.inputmethod.CorrectionInfo$1
android.view.inputmethod.CursorAnchorInfo
android.view.inputmethod.CursorAnchorInfo$Builder
android.view.inputmethod.EditorInfo
@@ -4594,6 +4786,7 @@ android.view.inputmethod.InputBinding$1
android.view.inputmethod.InputConnection
android.view.inputmethod.InputConnectionInspector
android.view.inputmethod.InputConnectionWrapper
+android.view.inputmethod.InputContentInfo
android.view.inputmethod.InputMethod
android.view.inputmethod.InputMethod$SessionCallback
android.view.inputmethod.InputMethodInfo
@@ -4613,6 +4806,8 @@ android.view.inputmethod.InputMethodSubtype
android.view.inputmethod.InputMethodSubtype$1
android.view.inputmethod.InputMethodSubtype$InputMethodSubtypeBuilder
android.view.inputmethod.InputMethodSubtypeArray
+android.view.textclassifier.TextClassificationManager
+android.view.textclassifier.TextLanguage
android.view.textservice.SentenceSuggestionsInfo
android.view.textservice.SentenceSuggestionsInfo$1
android.view.textservice.SpellCheckerInfo
@@ -4644,10 +4839,13 @@ android.webkit.JavascriptInterface
android.webkit.JsPromptResult
android.webkit.JsResult
android.webkit.MimeTypeMap
+android.webkit.ServiceWorkerClient
android.webkit.ServiceWorkerController
+android.webkit.ServiceWorkerWebSettings
android.webkit.SslErrorHandler
android.webkit.TokenBindingService
android.webkit.URLUtil
+android.webkit.UserPackage
android.webkit.ValueCallback
android.webkit.WebBackForwardList
android.webkit.WebChromeClient
@@ -4656,7 +4854,6 @@ android.webkit.WebHistoryItem
android.webkit.WebIconDatabase
android.webkit.WebMessage
android.webkit.WebMessagePort
-android.webkit.WebResourceError
android.webkit.WebResourceRequest
android.webkit.WebResourceResponse
android.webkit.WebSettings
@@ -4692,12 +4889,13 @@ android.webkit.WebViewProviderInfo
android.webkit.WebViewProviderInfo$1
android.webkit.WebViewProviderResponse
android.webkit.WebViewProviderResponse$1
+android.webkit.WebViewZygote
+android.widget.-$Lambda$50$tfOQKOmkDz_xLYaBQX_cysn8vbE
android.widget.AbsListView
android.widget.AbsListView$3
android.widget.AbsListView$4
android.widget.AbsListView$AbsPositionScroller
android.widget.AbsListView$AdapterDataSetObserver
-android.widget.AbsListView$CheckForLongPress
android.widget.AbsListView$CheckForTap
android.widget.AbsListView$FlingRunnable
android.widget.AbsListView$FlingRunnable$1
@@ -4708,6 +4906,7 @@ android.widget.AbsListView$MultiChoiceModeWrapper
android.widget.AbsListView$OnScrollListener
android.widget.AbsListView$PerformClick
android.widget.AbsListView$PositionScroller
+android.widget.AbsListView$PositionScroller$1
android.widget.AbsListView$RecycleBin
android.widget.AbsListView$RecyclerListener
android.widget.AbsListView$SavedState
@@ -4745,7 +4944,6 @@ android.widget.AdapterView$OnItemClickListener
android.widget.AdapterView$OnItemLongClickListener
android.widget.AdapterView$OnItemSelectedListener
android.widget.AdapterView$SelectionNotifier
-android.widget.Advanceable
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
android.widget.AutoCompleteTextView$DropDownItemClickListener
@@ -4767,7 +4965,6 @@ android.widget.CompoundButton$SavedState
android.widget.CompoundButton$SavedState$1
android.widget.CursorAdapter
android.widget.CursorFilter$CursorFilterClient
-android.widget.DatePicker
android.widget.DatePicker$OnDateChangedListener
android.widget.DateTimeView
android.widget.DateTimeView$ReceiverInfo
@@ -4780,7 +4977,6 @@ android.widget.Editor
android.widget.Editor$1
android.widget.Editor$2
android.widget.Editor$Blink
-android.widget.Editor$CorrectionHighlighter
android.widget.Editor$CursorAnchorInfoNotifier
android.widget.Editor$CursorController
android.widget.Editor$EditOperation
@@ -4793,6 +4989,7 @@ android.widget.Editor$InsertionHandleView$2
android.widget.Editor$InsertionPointCursorController
android.widget.Editor$PositionListener
android.widget.Editor$ProcessTextIntentActionsHandler
+android.widget.Editor$SelectionHandleView
android.widget.Editor$SelectionModifierCursorController
android.widget.Editor$SpanController
android.widget.Editor$SuggestionHelper
@@ -4801,7 +4998,6 @@ android.widget.Editor$TextRenderNode
android.widget.Editor$TextViewPositionListener
android.widget.Editor$UndoInputFilter
android.widget.ExpandableListConnector
-android.widget.ExpandableListView
android.widget.FastScroller
android.widget.FastScroller$1
android.widget.FastScroller$2
@@ -4895,7 +5091,6 @@ android.widget.PopupWindow
android.widget.PopupWindow$1
android.widget.PopupWindow$2
android.widget.PopupWindow$3
-android.widget.PopupWindow$4
android.widget.PopupWindow$OnDismissListener
android.widget.PopupWindow$PopupBackgroundView
android.widget.PopupWindow$PopupDecorView
@@ -4903,6 +5098,7 @@ android.widget.PopupWindow$PopupDecorView$1
android.widget.PopupWindow$PopupDecorView$2
android.widget.PopupWindow$PopupDecorView$2$1
android.widget.PopupWindow$PopupDecorView$3
+android.widget.PopupWindow$PopupDecorView$4
android.widget.ProgressBar
android.widget.ProgressBar$1
android.widget.ProgressBar$ProgressTintInfo
@@ -4942,10 +5138,7 @@ android.widget.RemoteViews$RuntimeAction
android.widget.RemoteViews$SetDrawableParameters
android.widget.RemoteViews$SetOnClickPendingIntent
android.widget.RemoteViews$SetOnClickPendingIntent$1
-android.widget.RemoteViews$SetRemoteInputsAction
-android.widget.RemoteViews$TextViewDrawableAction
android.widget.RemoteViews$ViewGroupAction
-android.widget.RemoteViews$ViewPaddingAction
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RemoteViewsService
android.widget.RemoteViewsService$RemoteViewsFactory
@@ -4972,11 +5165,10 @@ android.widget.SearchView$9
android.widget.SearchView$OnCloseListener
android.widget.SearchView$OnQueryTextListener
android.widget.SearchView$SearchAutoComplete
+android.widget.SearchView$UpdatableTouchDelegate
android.widget.SectionIndexer
android.widget.SeekBar
android.widget.SeekBar$OnSeekBarChangeListener
-android.widget.SimpleAdapter
-android.widget.SimpleAdapter$ViewBinder
android.widget.SimpleCursorAdapter
android.widget.Space
android.widget.SpellChecker
@@ -4984,7 +5176,6 @@ android.widget.SpellChecker$1
android.widget.SpellChecker$SpellParser
android.widget.Spinner
android.widget.Spinner$1
-android.widget.Spinner$DialogPopup
android.widget.Spinner$DropDownAdapter
android.widget.Spinner$DropdownPopup
android.widget.Spinner$DropdownPopup$1
@@ -5034,7 +5225,6 @@ android.widget.TimePicker$OnTimeChangedListener
android.widget.Toast
android.widget.Toast$TN
android.widget.Toast$TN$1
-android.widget.Toast$TN$2
android.widget.ToggleButton
android.widget.Toolbar
android.widget.Toolbar$1
@@ -5058,6 +5248,7 @@ android.widget.ViewFlipper$1
android.widget.ViewFlipper$2
android.widget.ViewSwitcher
android.widget.WrapperListAdapter
+android.widget.ZoomButtonsController
com.android.dex.ClassData
com.android.dex.ClassData$Method
com.android.dex.ClassDef
@@ -5084,9 +5275,19 @@ com.android.dex.util.ByteInput
com.android.dex.util.ByteOutput
com.android.dex.util.ExceptionWithContext
com.android.dex.util.FileUtils
+com.android.framework.protobuf.nano.CodedInputByteBufferNano
+com.android.framework.protobuf.nano.CodedOutputByteBufferNano
+com.android.framework.protobuf.nano.ExtendableMessageNano
+com.android.framework.protobuf.nano.InternalNano
+com.android.framework.protobuf.nano.InvalidProtocolBufferNanoException
+com.android.framework.protobuf.nano.MessageNano
+com.android.framework.protobuf.nano.WireFormatNano
+com.android.i18n.phonenumbers.AlternateFormatsCountryCodeSet
com.android.i18n.phonenumbers.AsYouTypeFormatter
com.android.i18n.phonenumbers.CountryCodeToRegionCodeMap
com.android.i18n.phonenumbers.MetadataLoader
+com.android.i18n.phonenumbers.MetadataManager
+com.android.i18n.phonenumbers.MetadataManager$1
com.android.i18n.phonenumbers.MetadataSource
com.android.i18n.phonenumbers.MultiFileMetadataSourceImpl
com.android.i18n.phonenumbers.NumberParseException
@@ -5095,7 +5296,6 @@ com.android.i18n.phonenumbers.PhoneNumberMatcher
com.android.i18n.phonenumbers.PhoneNumberMatcher$State
com.android.i18n.phonenumbers.PhoneNumberUtil
com.android.i18n.phonenumbers.PhoneNumberUtil$1
-com.android.i18n.phonenumbers.PhoneNumberUtil$2
com.android.i18n.phonenumbers.PhoneNumberUtil$Leniency
com.android.i18n.phonenumbers.PhoneNumberUtil$Leniency$1
com.android.i18n.phonenumbers.PhoneNumberUtil$Leniency$2
@@ -5113,19 +5313,13 @@ com.android.i18n.phonenumbers.Phonenumber$PhoneNumber$CountryCodeSource
com.android.i18n.phonenumbers.RegexCache
com.android.i18n.phonenumbers.RegexCache$LRUCache
com.android.i18n.phonenumbers.RegexCache$LRUCache$1
+com.android.i18n.phonenumbers.ShortNumbersRegionCodeSet
com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder
-com.android.i18n.phonenumbers.prefixmapper.DefaultMapStorage
com.android.i18n.phonenumbers.prefixmapper.MappingFileProvider
-com.android.i18n.phonenumbers.prefixmapper.PhonePrefixMap
-com.android.i18n.phonenumbers.prefixmapper.PhonePrefixMapStorageStrategy
com.android.i18n.phonenumbers.prefixmapper.PrefixFileReader
-com.android.ims.ImsCall
-com.android.ims.ImsCall$ImsCallSessionListenerProxy
com.android.ims.ImsCall$Listener
com.android.ims.ImsCallForwardInfo
com.android.ims.ImsCallProfile
-com.android.ims.ImsCallProfile$1
-com.android.ims.ImsConferenceState
com.android.ims.ImsConfig
com.android.ims.ImsConfigListener
com.android.ims.ImsConfigListener$Stub
@@ -5140,37 +5334,77 @@ com.android.ims.ImsManager$1
com.android.ims.ImsManager$2
com.android.ims.ImsManager$ImsRegistrationListenerProxy
com.android.ims.ImsManager$ImsServiceDeathRecipient
+com.android.ims.ImsMultiEndpoint
+com.android.ims.ImsMultiEndpoint$ImsExternalCallStateListenerProxy
com.android.ims.ImsReasonInfo
com.android.ims.ImsReasonInfo$1
com.android.ims.ImsSsInfo
-com.android.ims.ImsStreamMediaProfile
-com.android.ims.ImsStreamMediaProfile$1
-com.android.ims.ImsSuppServiceNotification
-com.android.ims.internal.ICall
com.android.ims.internal.IImsCallSession
-com.android.ims.internal.IImsCallSession$Stub
com.android.ims.internal.IImsCallSessionListener
-com.android.ims.internal.IImsCallSessionListener$Stub
com.android.ims.internal.IImsConfig
com.android.ims.internal.IImsConfig$Stub
+com.android.ims.internal.IImsConfig$Stub$Proxy
com.android.ims.internal.IImsEcbm
com.android.ims.internal.IImsEcbm$Stub
com.android.ims.internal.IImsEcbmListener
com.android.ims.internal.IImsEcbmListener$Stub
+com.android.ims.internal.IImsExternalCallStateListener
+com.android.ims.internal.IImsExternalCallStateListener$Stub
com.android.ims.internal.IImsMultiEndpoint
+com.android.ims.internal.IImsMultiEndpoint$Stub
com.android.ims.internal.IImsRegistrationListener
com.android.ims.internal.IImsRegistrationListener$Stub
+com.android.ims.internal.IImsRegistrationListener$Stub$Proxy
com.android.ims.internal.IImsService
com.android.ims.internal.IImsService$Stub
+com.android.ims.internal.IImsService$Stub$Proxy
+com.android.ims.internal.IImsServiceController
+com.android.ims.internal.IImsServiceFeatureListener
com.android.ims.internal.IImsUt
com.android.ims.internal.IImsUt$Stub
com.android.ims.internal.IImsUtListener
com.android.ims.internal.IImsUtListener$Stub
-com.android.ims.internal.IImsVideoCallProvider
-com.android.ims.internal.ImsCallSession
-com.android.ims.internal.ImsCallSession$IImsCallSessionListenerProxy
-com.android.ims.internal.ImsCallSession$Listener
-com.android.ims.internal.ImsCallSession$State
+com.android.ims.internal.uce.common.CapInfo
+com.android.ims.internal.uce.common.CapInfo$1
+com.android.ims.internal.uce.common.StatusCode
+com.android.ims.internal.uce.common.StatusCode$1
+com.android.ims.internal.uce.common.UceLong
+com.android.ims.internal.uce.common.UceLong$1
+com.android.ims.internal.uce.options.IOptionsListener
+com.android.ims.internal.uce.options.IOptionsService
+com.android.ims.internal.uce.presence.IPresenceListener
+com.android.ims.internal.uce.presence.IPresenceListener$Stub
+com.android.ims.internal.uce.presence.IPresenceListener$Stub$Proxy
+com.android.ims.internal.uce.presence.IPresenceService
+com.android.ims.internal.uce.presence.IPresenceService$Stub
+com.android.ims.internal.uce.presence.IPresenceService$Stub$Proxy
+com.android.ims.internal.uce.presence.PresCapInfo
+com.android.ims.internal.uce.presence.PresCmdId
+com.android.ims.internal.uce.presence.PresCmdId$1
+com.android.ims.internal.uce.presence.PresCmdStatus
+com.android.ims.internal.uce.presence.PresCmdStatus$1
+com.android.ims.internal.uce.presence.PresPublishTriggerType
+com.android.ims.internal.uce.presence.PresPublishTriggerType$1
+com.android.ims.internal.uce.presence.PresResInfo
+com.android.ims.internal.uce.presence.PresResInfo$1
+com.android.ims.internal.uce.presence.PresResInstanceInfo
+com.android.ims.internal.uce.presence.PresResInstanceInfo$1
+com.android.ims.internal.uce.presence.PresRlmiInfo
+com.android.ims.internal.uce.presence.PresRlmiInfo$1
+com.android.ims.internal.uce.presence.PresServiceInfo
+com.android.ims.internal.uce.presence.PresSipResponse
+com.android.ims.internal.uce.presence.PresSipResponse$1
+com.android.ims.internal.uce.presence.PresSubscriptionState
+com.android.ims.internal.uce.presence.PresSubscriptionState$1
+com.android.ims.internal.uce.presence.PresTupleInfo
+com.android.ims.internal.uce.presence.PresTupleInfo$1
+com.android.ims.internal.uce.uceservice.IUceListener
+com.android.ims.internal.uce.uceservice.IUceListener$Stub
+com.android.ims.internal.uce.uceservice.IUceService
+com.android.ims.internal.uce.uceservice.IUceService$Stub
+com.android.ims.internal.uce.uceservice.IUceService$Stub$Proxy
+com.android.ims.internal.uce.uceservice.ImsUceManager
+com.android.ims.internal.uce.uceservice.ImsUceManager$UceServiceDeathRecipient
com.android.internal.R$styleable
com.android.internal.alsa.AlsaCardsParser
com.android.internal.alsa.AlsaCardsParser$AlsaCardRecord
@@ -5185,17 +5419,6 @@ com.android.internal.app.AlertController$ButtonHandler
com.android.internal.app.AlertController$CheckedItemAdapter
com.android.internal.app.AlertController$RecycleListView
com.android.internal.app.AssistUtils
-com.android.internal.app.ChooserActivity
-com.android.internal.app.ChooserActivity$1
-com.android.internal.app.ChooserActivity$BaseChooserTargetComparator
-com.android.internal.app.ChooserActivity$ChooserListAdapter
-com.android.internal.app.ChooserActivity$ChooserRowAdapter
-com.android.internal.app.ChooserActivity$ChooserRowAdapter$1
-com.android.internal.app.ChooserActivity$ChooserRowAdapter$2
-com.android.internal.app.ChooserActivity$ChooserRowAdapter$3
-com.android.internal.app.ChooserActivity$OffsetDataSetObserver
-com.android.internal.app.ChooserActivity$RowScale
-com.android.internal.app.ChooserActivity$RowViewHolder
com.android.internal.app.IAppOpsCallback
com.android.internal.app.IAppOpsCallback$Stub
com.android.internal.app.IAppOpsCallback$Stub$Proxy
@@ -5203,6 +5426,7 @@ com.android.internal.app.IAppOpsService
com.android.internal.app.IAppOpsService$Stub
com.android.internal.app.IAppOpsService$Stub$Proxy
com.android.internal.app.IAssistScreenshotReceiver
+com.android.internal.app.IAssistScreenshotReceiver$Stub
com.android.internal.app.IBatteryStats
com.android.internal.app.IBatteryStats$Stub
com.android.internal.app.IBatteryStats$Stub$Proxy
@@ -5214,41 +5438,34 @@ com.android.internal.app.ISoundTriggerService$Stub
com.android.internal.app.IVoiceInteractionManagerService
com.android.internal.app.IVoiceInteractionManagerService$Stub
com.android.internal.app.IVoiceInteractionManagerService$Stub$Proxy
+com.android.internal.app.IVoiceInteractionSessionListener
+com.android.internal.app.IVoiceInteractionSessionListener$Stub
+com.android.internal.app.IVoiceInteractionSessionListener$Stub$Proxy
com.android.internal.app.IVoiceInteractionSessionShowCallback
com.android.internal.app.IVoiceInteractionSessionShowCallback$Stub
+com.android.internal.app.IVoiceInteractionSessionShowCallback$Stub$Proxy
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
-com.android.internal.app.IntentForwarderActivity
+com.android.internal.app.IVoiceInteractor$Stub$Proxy
com.android.internal.app.LocaleHelper
com.android.internal.app.LocalePicker
com.android.internal.app.LocalePickerWithRegion$LocaleSelectedListener
-com.android.internal.app.PlatLogoActivity
+com.android.internal.app.NightDisplayController
+com.android.internal.app.NightDisplayController$1
+com.android.internal.app.NightDisplayController$Callback
+com.android.internal.app.NightDisplayController$LocalTime
com.android.internal.app.ProcessMap
com.android.internal.app.ResolverActivity
-com.android.internal.app.ResolverActivity$1
-com.android.internal.app.ResolverActivity$2
-com.android.internal.app.ResolverActivity$3
-com.android.internal.app.ResolverActivity$DisplayResolveInfo
-com.android.internal.app.ResolverActivity$LoadAdapterIconTask
-com.android.internal.app.ResolverActivity$LoadIconTask
-com.android.internal.app.ResolverActivity$ResolveListAdapter
-com.android.internal.app.ResolverActivity$ResolvedComponentInfo
-com.android.internal.app.ResolverActivity$TargetInfo
-com.android.internal.app.ResolverActivity$ViewHolder
-com.android.internal.app.ResolverComparator
-com.android.internal.app.ResolverComparator$ScoredTarget
com.android.internal.app.ToolbarActionBar
com.android.internal.app.ToolbarActionBar$1
com.android.internal.app.ToolbarActionBar$2
com.android.internal.app.ToolbarActionBar$ActionMenuPresenterCallback
com.android.internal.app.ToolbarActionBar$MenuBuilderCallback
com.android.internal.app.ToolbarActionBar$ToolbarCallbackWrapper
-com.android.internal.app.UnlaunchableAppActivity
com.android.internal.app.WindowDecorActionBar
com.android.internal.app.WindowDecorActionBar$1
com.android.internal.app.WindowDecorActionBar$2
com.android.internal.app.WindowDecorActionBar$3
-com.android.internal.app.WindowDecorActionBar$ActionModeImpl
com.android.internal.app.procstats.DumpUtils
com.android.internal.app.procstats.DurationsTable
com.android.internal.app.procstats.IProcessStats
@@ -5280,11 +5497,16 @@ com.android.internal.backup.IBackupTransport$Stub$Proxy
com.android.internal.backup.LocalTransport
com.android.internal.backup.LocalTransportService
com.android.internal.content.NativeLibraryHelper
-com.android.internal.content.NativeLibraryHelper$Handle
com.android.internal.content.PackageHelper
com.android.internal.content.PackageMonitor
com.android.internal.content.ReferrerIntent
com.android.internal.content.ReferrerIntent$1
+com.android.internal.font.IFontManager
+com.android.internal.font.IFontManager$Stub
+com.android.internal.graphics.drawable.AnimationScaleListDrawable
+com.android.internal.graphics.drawable.AnimationScaleListDrawable$AnimationScaleListState
+com.android.internal.hardware.AmbientDisplayConfiguration
+com.android.internal.inputmethod.IInputContentUriToken
com.android.internal.inputmethod.InputMethodSubtypeHandle
com.android.internal.inputmethod.InputMethodSubtypeSwitchingController
com.android.internal.inputmethod.InputMethodSubtypeSwitchingController$ControllerImpl
@@ -5295,6 +5517,7 @@ com.android.internal.inputmethod.InputMethodSubtypeSwitchingController$InputMeth
com.android.internal.inputmethod.InputMethodSubtypeSwitchingController$StaticRotationList
com.android.internal.inputmethod.InputMethodUtils
com.android.internal.inputmethod.InputMethodUtils$1
+com.android.internal.inputmethod.InputMethodUtils$InputMethodListBuilder
com.android.internal.inputmethod.InputMethodUtils$InputMethodSettings
com.android.internal.inputmethod.LocaleUtils
com.android.internal.inputmethod.LocaleUtils$LocaleExtractor
@@ -5320,6 +5543,7 @@ com.android.internal.net.VpnConfig
com.android.internal.net.VpnInfo
com.android.internal.net.VpnProfile
com.android.internal.os.AndroidPrintStream
+com.android.internal.os.AppFuseMount
com.android.internal.os.AtomicFile
com.android.internal.os.BackgroundThread
com.android.internal.os.BatterySipper
@@ -5333,6 +5557,8 @@ com.android.internal.os.BatteryStatsImpl$BatchTimer
com.android.internal.os.BatteryStatsImpl$BatteryCallback
com.android.internal.os.BatteryStatsImpl$Clocks
com.android.internal.os.BatteryStatsImpl$ControllerActivityCounterImpl
+com.android.internal.os.BatteryStatsImpl$Counter
+com.android.internal.os.BatteryStatsImpl$DurationTimer
com.android.internal.os.BatteryStatsImpl$ExternalStatsSync
com.android.internal.os.BatteryStatsImpl$LongSamplingCounter
com.android.internal.os.BatteryStatsImpl$MyHandler
@@ -5350,6 +5576,7 @@ com.android.internal.os.BatteryStatsImpl$Uid$2
com.android.internal.os.BatteryStatsImpl$Uid$3
com.android.internal.os.BatteryStatsImpl$Uid$Pkg
com.android.internal.os.BatteryStatsImpl$Uid$Pkg$Serv
+com.android.internal.os.BatteryStatsImpl$Uid$Proc
com.android.internal.os.BatteryStatsImpl$Uid$Sensor
com.android.internal.os.BatteryStatsImpl$Uid$Wakelock
com.android.internal.os.BinderInternal
@@ -5358,6 +5585,9 @@ com.android.internal.os.BluetoothPowerCalculator
com.android.internal.os.CameraPowerCalculator
com.android.internal.os.CpuPowerCalculator
com.android.internal.os.FlashlightPowerCalculator
+com.android.internal.os.FuseAppLoop
+com.android.internal.os.FuseAppLoop$1
+com.android.internal.os.FuseAppLoop$UnmountedException
com.android.internal.os.HandlerCaller
com.android.internal.os.HandlerCaller$Callback
com.android.internal.os.HandlerCaller$MyHandler
@@ -5368,15 +5598,18 @@ com.android.internal.os.IParcelFileDescriptorFactory
com.android.internal.os.IResultReceiver
com.android.internal.os.IResultReceiver$Stub
com.android.internal.os.IResultReceiver$Stub$Proxy
-com.android.internal.os.InstallerConnection
-com.android.internal.os.InstallerConnection$InstallerException
+com.android.internal.os.IShellCallback
+com.android.internal.os.IShellCallback$Stub
+com.android.internal.os.IShellCallback$Stub$Proxy
com.android.internal.os.KernelCpuSpeedReader
+com.android.internal.os.KernelMemoryBandwidthStats
com.android.internal.os.KernelUidCpuTimeReader
com.android.internal.os.KernelWakelockReader
com.android.internal.os.KernelWakelockStats
com.android.internal.os.KernelWakelockStats$Entry
com.android.internal.os.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
+com.android.internal.os.MemoryPowerCalculator
com.android.internal.os.MobileRadioPowerCalculator
com.android.internal.os.PathClassLoaderFactory
com.android.internal.os.PowerCalculator
@@ -5384,31 +5617,35 @@ com.android.internal.os.PowerProfile
com.android.internal.os.PowerProfile$CpuClusterKey
com.android.internal.os.ProcessCpuTracker
com.android.internal.os.ProcessCpuTracker$1
+com.android.internal.os.ProcessCpuTracker$FilterStats
com.android.internal.os.ProcessCpuTracker$Stats
+com.android.internal.os.RoSystemProperties
com.android.internal.os.RuntimeInit
com.android.internal.os.RuntimeInit$1
com.android.internal.os.RuntimeInit$Arguments
-com.android.internal.os.RuntimeInit$UncaughtHandler
+com.android.internal.os.RuntimeInit$KillApplicationHandler
+com.android.internal.os.RuntimeInit$LoggingHandler
com.android.internal.os.SamplingProfilerIntegration
com.android.internal.os.SensorPowerCalculator
com.android.internal.os.SomeArgs
+com.android.internal.os.TransferPipe
com.android.internal.os.WakelockPowerCalculator
-com.android.internal.os.WifiPowerEstimator
+com.android.internal.os.WifiPowerCalculator
com.android.internal.os.Zygote
+com.android.internal.os.Zygote$MethodAndArgsCaller
com.android.internal.os.ZygoteConnection
com.android.internal.os.ZygoteConnection$Arguments
com.android.internal.os.ZygoteInit
-com.android.internal.os.ZygoteInit$MethodAndArgsCaller
com.android.internal.os.ZygoteSecurityException
+com.android.internal.os.ZygoteServer
com.android.internal.policy.DecorContext
com.android.internal.policy.DecorView
com.android.internal.policy.DecorView$1
-com.android.internal.policy.DecorView$4
-com.android.internal.policy.DecorView$ActionModeCallback2Wrapper
com.android.internal.policy.DecorView$ColorViewState
com.android.internal.policy.DividerSnapAlgorithm
com.android.internal.policy.DividerSnapAlgorithm$SnapTarget
com.android.internal.policy.DockedDividerUtils
+com.android.internal.policy.IKeyguardDismissCallback
com.android.internal.policy.IKeyguardDrawnCallback
com.android.internal.policy.IKeyguardDrawnCallback$Stub
com.android.internal.policy.IKeyguardDrawnCallback$Stub$Proxy
@@ -5433,6 +5670,8 @@ com.android.internal.policy.PhoneWindow$PanelFeatureState$SavedState$1
com.android.internal.policy.PhoneWindow$PhoneWindowMenuCallback
com.android.internal.policy.PhoneWindow$RotationWatcher
com.android.internal.policy.PhoneWindow$RotationWatcher$1
+com.android.internal.policy.PipMotionHelper
+com.android.internal.policy.PipSnapAlgorithm
com.android.internal.statusbar.IStatusBar
com.android.internal.statusbar.IStatusBar$Stub
com.android.internal.statusbar.IStatusBar$Stub$Proxy
@@ -5463,10 +5702,8 @@ com.android.internal.telecom.IVideoProvider$Stub
com.android.internal.telecom.RemoteServiceCallback
com.android.internal.telecom.RemoteServiceCallback$Stub
com.android.internal.telecom.RemoteServiceCallback$Stub$Proxy
-com.android.internal.telephony.ATParseEx
-com.android.internal.telephony.AsyncEmergencyContactNotifier
+com.android.internal.telephony.AppSmsManager
com.android.internal.telephony.BaseCommands
-com.android.internal.telephony.BlockChecker
com.android.internal.telephony.Call
com.android.internal.telephony.Call$SrvccState
com.android.internal.telephony.Call$State
@@ -5480,28 +5717,30 @@ com.android.internal.telephony.CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler
com.android.internal.telephony.CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler$CallerInfoWorkerHandler
com.android.internal.telephony.CallerInfoAsyncQuery$CookieWrapper
com.android.internal.telephony.CallerInfoAsyncQuery$OnQueryCompleteListener
+com.android.internal.telephony.CarrierActionAgent
com.android.internal.telephony.CarrierAppUtils
com.android.internal.telephony.CarrierServiceBindHelper
com.android.internal.telephony.CarrierServiceBindHelper$1
com.android.internal.telephony.CarrierServiceBindHelper$2
com.android.internal.telephony.CarrierServiceBindHelper$AppBinding
com.android.internal.telephony.CarrierServiceBindHelper$CarrierServicePackageMonitor
+com.android.internal.telephony.CarrierServiceStateTracker
+com.android.internal.telephony.CarrierServiceStateTracker$1
+com.android.internal.telephony.CarrierSignalAgent
+com.android.internal.telephony.CarrierSignalAgent$1
com.android.internal.telephony.CellBroadcastHandler
com.android.internal.telephony.CellNetworkScanResult
+com.android.internal.telephony.ClientWakelockAccountant
+com.android.internal.telephony.ClientWakelockTracker
com.android.internal.telephony.CommandException
com.android.internal.telephony.CommandException$Error
com.android.internal.telephony.CommandsInterface
com.android.internal.telephony.CommandsInterface$RadioState
com.android.internal.telephony.Connection
-com.android.internal.telephony.Connection$Listener
-com.android.internal.telephony.Connection$ListenerBase
-com.android.internal.telephony.Connection$PostDialListener
-com.android.internal.telephony.Connection$PostDialState
com.android.internal.telephony.DctConstants$Activity
com.android.internal.telephony.DctConstants$State
com.android.internal.telephony.DebugService
com.android.internal.telephony.DefaultPhoneNotifier
-com.android.internal.telephony.DriverCall
com.android.internal.telephony.EncodeException
com.android.internal.telephony.GsmAlphabet
com.android.internal.telephony.GsmAlphabet$TextEncodingDetails
@@ -5513,6 +5752,7 @@ com.android.internal.telephony.GsmCdmaPhone
com.android.internal.telephony.GsmCdmaPhone$1
com.android.internal.telephony.GsmCdmaPhone$2
com.android.internal.telephony.HardwareConfig
+com.android.internal.telephony.HbpcdUtils
com.android.internal.telephony.ICarrierConfigLoader
com.android.internal.telephony.ICarrierConfigLoader$Stub
com.android.internal.telephony.ICarrierConfigLoader$Stub$Proxy
@@ -5520,7 +5760,6 @@ com.android.internal.telephony.IIccPhoneBook
com.android.internal.telephony.IIccPhoneBook$Stub
com.android.internal.telephony.IMms
com.android.internal.telephony.IMms$Stub
-com.android.internal.telephony.IMms$Stub$Proxy
com.android.internal.telephony.IOnSubscriptionsChangedListener
com.android.internal.telephony.IOnSubscriptionsChangedListener$Stub
com.android.internal.telephony.IOnSubscriptionsChangedListener$Stub$Proxy
@@ -5554,20 +5793,16 @@ com.android.internal.telephony.IccSmsInterfaceManager$CdmaBroadcastRangeManager
com.android.internal.telephony.IccSmsInterfaceManager$CellBroadcastRangeManager
com.android.internal.telephony.ImsSMSDispatcher
com.android.internal.telephony.InboundSmsHandler
+com.android.internal.telephony.InboundSmsHandler$1
com.android.internal.telephony.InboundSmsHandler$DefaultState
com.android.internal.telephony.InboundSmsHandler$DeliveringState
com.android.internal.telephony.InboundSmsHandler$IdleState
-com.android.internal.telephony.InboundSmsHandler$SmsBroadcastReceiver
+com.android.internal.telephony.InboundSmsHandler$NewMessageNotificationActionReceiver
com.android.internal.telephony.InboundSmsHandler$StartupState
com.android.internal.telephony.InboundSmsHandler$WaitingState
-com.android.internal.telephony.InboundSmsTracker
com.android.internal.telephony.IntRangeManager
-com.android.internal.telephony.IntRangeManager$ClientRange
-com.android.internal.telephony.IntRangeManager$IntRange
com.android.internal.telephony.MccTable
com.android.internal.telephony.MccTable$MccEntry
-com.android.internal.telephony.MmiCode
-com.android.internal.telephony.MmiCode$State
com.android.internal.telephony.OperatorInfo
com.android.internal.telephony.Phone
com.android.internal.telephony.Phone$1
@@ -5576,7 +5811,6 @@ com.android.internal.telephony.PhoneConstants$State
com.android.internal.telephony.PhoneFactory
com.android.internal.telephony.PhoneInternalInterface
com.android.internal.telephony.PhoneInternalInterface$DataActivityState
-com.android.internal.telephony.PhoneInternalInterface$SuppService
com.android.internal.telephony.PhoneNotifier
com.android.internal.telephony.PhoneStateIntentReceiver
com.android.internal.telephony.PhoneSubInfoController
@@ -5592,43 +5826,39 @@ com.android.internal.telephony.RIL$1
com.android.internal.telephony.RIL$2
com.android.internal.telephony.RIL$RILReceiver
com.android.internal.telephony.RIL$RILSender
+com.android.internal.telephony.RIL$RadioProxyDeathRecipient
+com.android.internal.telephony.RIL$RilHandler
com.android.internal.telephony.RILConstants
com.android.internal.telephony.RILRequest
com.android.internal.telephony.RadioCapability
+com.android.internal.telephony.RadioIndication
+com.android.internal.telephony.RadioResponse
+com.android.internal.telephony.RatRatcheter
+com.android.internal.telephony.RatRatcheter$1
com.android.internal.telephony.RestrictedState
com.android.internal.telephony.RetryManager
-com.android.internal.telephony.RetryManager$RetryRec
+com.android.internal.telephony.RilWakelockInfo
com.android.internal.telephony.SMSDispatcher
com.android.internal.telephony.SMSDispatcher$SettingsObserver
-com.android.internal.telephony.SMSDispatcher$SmsTracker
com.android.internal.telephony.ServiceStateTracker
com.android.internal.telephony.ServiceStateTracker$1
com.android.internal.telephony.ServiceStateTracker$2
com.android.internal.telephony.ServiceStateTracker$3
com.android.internal.telephony.ServiceStateTracker$CellInfoResult
com.android.internal.telephony.ServiceStateTracker$SstSubscriptionsChangedListener
-com.android.internal.telephony.SmsAddress
com.android.internal.telephony.SmsApplication
com.android.internal.telephony.SmsApplication$SmsApplicationData
com.android.internal.telephony.SmsApplication$SmsPackageMonitor
com.android.internal.telephony.SmsBroadcastUndelivered
com.android.internal.telephony.SmsBroadcastUndelivered$1
com.android.internal.telephony.SmsBroadcastUndelivered$ScanRawTableThread
-com.android.internal.telephony.SmsConstants$MessageClass
-com.android.internal.telephony.SmsHeader
-com.android.internal.telephony.SmsHeader$PortAddrs
com.android.internal.telephony.SmsMessageBase
-com.android.internal.telephony.SmsMessageBase$SubmitPduBase
-com.android.internal.telephony.SmsNumberUtils
-com.android.internal.telephony.SmsResponse
com.android.internal.telephony.SmsStorageMonitor
com.android.internal.telephony.SmsStorageMonitor$1
com.android.internal.telephony.SmsUsageMonitor
com.android.internal.telephony.SmsUsageMonitor$SettingsObserver
com.android.internal.telephony.SmsUsageMonitor$SettingsObserverHandler
-com.android.internal.telephony.SmsUsageMonitor$ShortCodePatternMatcher
com.android.internal.telephony.SubscriptionController
-com.android.internal.telephony.SubscriptionController$1
com.android.internal.telephony.SubscriptionController$ScLocalLog
com.android.internal.telephony.SubscriptionInfoUpdater
com.android.internal.telephony.SubscriptionInfoUpdater$1
@@ -5639,10 +5869,8 @@ com.android.internal.telephony.SubscriptionMonitor$2
com.android.internal.telephony.TelephonyCapabilities
com.android.internal.telephony.TelephonyComponentFactory
com.android.internal.telephony.TelephonyDevController
-com.android.internal.telephony.TelephonyEventLog
com.android.internal.telephony.TelephonyTester
com.android.internal.telephony.TelephonyTester$1
-com.android.internal.telephony.UUSInfo
com.android.internal.telephony.UiccPhoneBookController
com.android.internal.telephony.UiccSmsController
com.android.internal.telephony.WakeLockStateMachine
@@ -5651,45 +5879,36 @@ com.android.internal.telephony.WakeLockStateMachine$DefaultState
com.android.internal.telephony.WakeLockStateMachine$IdleState
com.android.internal.telephony.WakeLockStateMachine$WaitingState
com.android.internal.telephony.WapPushOverSms
+com.android.internal.telephony.WapPushOverSms$1
+com.android.internal.telephony.WapPushOverSms$BindServiceThread
com.android.internal.telephony.cat.AppInterface
-com.android.internal.telephony.cat.CatException
+com.android.internal.telephony.cat.AppInterface$CommandType
+com.android.internal.telephony.cat.CatCmdMessage
+com.android.internal.telephony.cat.CatCmdMessage$BrowserSettings
+com.android.internal.telephony.cat.CatCmdMessage$CallSettings
+com.android.internal.telephony.cat.CatCmdMessage$SetupEventListSettings
com.android.internal.telephony.cat.CatLog
+com.android.internal.telephony.cat.CatResponseMessage
com.android.internal.telephony.cat.CatService
-com.android.internal.telephony.cat.CommandParamsFactory
-com.android.internal.telephony.cat.IconLoader
-com.android.internal.telephony.cat.ResultException
-com.android.internal.telephony.cat.RilMessageDecoder
-com.android.internal.telephony.cat.RilMessageDecoder$StateCmdParamsReady
-com.android.internal.telephony.cat.RilMessageDecoder$StateStart
-com.android.internal.telephony.cdma.CdmaCallWaitingNotification
+com.android.internal.telephony.cat.Input
+com.android.internal.telephony.cat.Item
+com.android.internal.telephony.cat.LaunchBrowserMode
+com.android.internal.telephony.cat.Menu
+com.android.internal.telephony.cat.ResultCode
+com.android.internal.telephony.cat.TextMessage
+com.android.internal.telephony.cat.ToneSettings
com.android.internal.telephony.cdma.CdmaInboundSmsHandler
-com.android.internal.telephony.cdma.CdmaInformationRecords$CdmaDisplayInfoRec
-com.android.internal.telephony.cdma.CdmaInformationRecords$CdmaSignalInfoRec
com.android.internal.telephony.cdma.CdmaSMSDispatcher
com.android.internal.telephony.cdma.CdmaServiceCategoryProgramHandler
com.android.internal.telephony.cdma.CdmaServiceCategoryProgramHandler$1
-com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo
com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager
com.android.internal.telephony.cdma.EriInfo
com.android.internal.telephony.cdma.EriManager
+com.android.internal.telephony.cdma.EriManager$EriDisplayInformation
com.android.internal.telephony.cdma.EriManager$EriFile
-com.android.internal.telephony.cdma.SignalToneUtil
com.android.internal.telephony.dataconnection.ApnContext
-com.android.internal.telephony.dataconnection.ApnSetting
-com.android.internal.telephony.dataconnection.DataCallResponse
-com.android.internal.telephony.dataconnection.DataCallResponse$SetupResult
com.android.internal.telephony.dataconnection.DataConnection
-com.android.internal.telephony.dataconnection.DataConnection$ConnectionParams
-com.android.internal.telephony.dataconnection.DataConnection$DcActivatingState
-com.android.internal.telephony.dataconnection.DataConnection$DcActiveState
-com.android.internal.telephony.dataconnection.DataConnection$DcDefaultState
-com.android.internal.telephony.dataconnection.DataConnection$DcDisconnectingState
-com.android.internal.telephony.dataconnection.DataConnection$DcDisconnectionErrorCreatingConnection
-com.android.internal.telephony.dataconnection.DataConnection$DcInactiveState
-com.android.internal.telephony.dataconnection.DataConnection$DcNetworkAgent
-com.android.internal.telephony.dataconnection.DataConnection$DisconnectParams
-com.android.internal.telephony.dataconnection.DataConnection$UpdateLinkPropertyResult
-com.android.internal.telephony.dataconnection.DcAsyncChannel
+com.android.internal.telephony.dataconnection.DataEnabledSettings
com.android.internal.telephony.dataconnection.DcController
com.android.internal.telephony.dataconnection.DcController$1
com.android.internal.telephony.dataconnection.DcController$DccDefaultState
@@ -5716,19 +5935,24 @@ com.android.internal.telephony.dataconnection.TelephonyNetworkFactory$InternalHa
com.android.internal.telephony.gsm.GsmCellBroadcastHandler
com.android.internal.telephony.gsm.GsmInboundSmsHandler
com.android.internal.telephony.gsm.GsmSMSDispatcher
-com.android.internal.telephony.gsm.GsmSmsAddress
-com.android.internal.telephony.gsm.SimTlv
-com.android.internal.telephony.gsm.SmsBroadcastConfigInfo
com.android.internal.telephony.gsm.SmsMessage
-com.android.internal.telephony.gsm.SmsMessage$PduParser
-com.android.internal.telephony.gsm.SmsMessage$SubmitPdu
-com.android.internal.telephony.gsm.SuppServiceNotification
com.android.internal.telephony.gsm.UsimDataDownloadHandler
-com.android.internal.telephony.gsm.UsimPhoneBookManager
+com.android.internal.telephony.ims.-$Lambda$2$6hDwuvYxqWrzW_Ex5wc53XnUOpg
+com.android.internal.telephony.ims.-$Lambda$3$6hDwuvYxqWrzW_Ex5wc53XnUOpg
+com.android.internal.telephony.ims.-$Lambda$4$6hDwuvYxqWrzW_Ex5wc53XnUOpg
+com.android.internal.telephony.ims.ImsResolver
+com.android.internal.telephony.ims.ImsResolver$1
+com.android.internal.telephony.ims.ImsResolver$2
+com.android.internal.telephony.ims.ImsResolver$3
+com.android.internal.telephony.ims.ImsResolver$ImsServiceControllerFactory
+com.android.internal.telephony.ims.ImsResolver$SubscriptionManagerProxy
+com.android.internal.telephony.ims.ImsServiceController$ImsServiceControllerCallbacks
com.android.internal.telephony.imsphone.ImsExternalCallTracker
+com.android.internal.telephony.imsphone.ImsExternalCallTracker$1
+com.android.internal.telephony.imsphone.ImsExternalCallTracker$2
com.android.internal.telephony.imsphone.ImsExternalCallTracker$ExternalCallStateListener
com.android.internal.telephony.imsphone.ImsExternalCallTracker$ExternalConnectionListener
-com.android.internal.telephony.imsphone.ImsExternalConnection
+com.android.internal.telephony.imsphone.ImsExternalCallTracker$ImsCallNotify
com.android.internal.telephony.imsphone.ImsExternalConnection$Listener
com.android.internal.telephony.imsphone.ImsPhone
com.android.internal.telephony.imsphone.ImsPhone$1
@@ -5742,64 +5966,43 @@ com.android.internal.telephony.imsphone.ImsPhoneCallTracker$2
com.android.internal.telephony.imsphone.ImsPhoneCallTracker$3
com.android.internal.telephony.imsphone.ImsPhoneCallTracker$4
com.android.internal.telephony.imsphone.ImsPhoneCallTracker$5
-com.android.internal.telephony.imsphone.ImsPhoneCallTracker$6
+com.android.internal.telephony.imsphone.ImsPhoneCallTracker$PhoneStateListener
com.android.internal.telephony.imsphone.ImsPhoneCommandInterface
-com.android.internal.telephony.imsphone.ImsPhoneConnection
-com.android.internal.telephony.imsphone.ImsPhoneConnection$MyHandler
com.android.internal.telephony.imsphone.ImsPhoneFactory
-com.android.internal.telephony.imsphone.ImsPhoneMmiCode
com.android.internal.telephony.imsphone.ImsPullCall
-com.android.internal.telephony.sip.SipPhone
-com.android.internal.telephony.sip.SipPhoneBase
+com.android.internal.telephony.metrics.CallSessionEventBuilder
+com.android.internal.telephony.metrics.InProgressCallSession
+com.android.internal.telephony.metrics.InProgressSmsSession
+com.android.internal.telephony.metrics.SmsSessionEventBuilder
+com.android.internal.telephony.metrics.TelephonyEventBuilder
+com.android.internal.telephony.metrics.TelephonyMetrics
+com.android.internal.telephony.nano.TelephonyProto$ImsCapabilities
+com.android.internal.telephony.nano.TelephonyProto$ImsConnectionState
+com.android.internal.telephony.nano.TelephonyProto$ImsReasonInfo
+com.android.internal.telephony.nano.TelephonyProto$RilDataCall
+com.android.internal.telephony.nano.TelephonyProto$SmsSession$Event
+com.android.internal.telephony.nano.TelephonyProto$TelephonyCallSession$Event
+com.android.internal.telephony.nano.TelephonyProto$TelephonyCallSession$Event$RilCall
+com.android.internal.telephony.nano.TelephonyProto$TelephonyEvent
+com.android.internal.telephony.nano.TelephonyProto$TelephonyServiceState
+com.android.internal.telephony.nano.TelephonyProto$TelephonyServiceState$TelephonyOperator
+com.android.internal.telephony.nano.TelephonyProto$TelephonySettings
com.android.internal.telephony.test.SimulatedRadioControl
-com.android.internal.telephony.uicc.AdnRecord
-com.android.internal.telephony.uicc.AdnRecord$1
-com.android.internal.telephony.uicc.AdnRecordCache
-com.android.internal.telephony.uicc.AdnRecordLoader
com.android.internal.telephony.uicc.IccCardApplicationStatus
-com.android.internal.telephony.uicc.IccCardApplicationStatus$AppState
com.android.internal.telephony.uicc.IccCardApplicationStatus$AppType
-com.android.internal.telephony.uicc.IccCardApplicationStatus$PersoSubState
com.android.internal.telephony.uicc.IccCardProxy
com.android.internal.telephony.uicc.IccCardStatus
com.android.internal.telephony.uicc.IccCardStatus$CardState
com.android.internal.telephony.uicc.IccCardStatus$PinState
com.android.internal.telephony.uicc.IccConstants
-com.android.internal.telephony.uicc.IccFileHandler
-com.android.internal.telephony.uicc.IccFileHandler$LoadLinearFixedContext
-com.android.internal.telephony.uicc.IccIoResult
com.android.internal.telephony.uicc.IccRecords
-com.android.internal.telephony.uicc.IccRecords$IccRecordLoaded
-com.android.internal.telephony.uicc.IccServiceTable
+com.android.internal.telephony.uicc.IccRefreshResponse
com.android.internal.telephony.uicc.IccUtils
-com.android.internal.telephony.uicc.IsimFileHandler
-com.android.internal.telephony.uicc.IsimRecords
-com.android.internal.telephony.uicc.IsimUiccRecords
-com.android.internal.telephony.uicc.IsimUiccRecords$EfIsimDomainLoaded
-com.android.internal.telephony.uicc.IsimUiccRecords$EfIsimImpiLoaded
-com.android.internal.telephony.uicc.IsimUiccRecords$EfIsimImpuLoaded
-com.android.internal.telephony.uicc.IsimUiccRecords$EfIsimIstLoaded
-com.android.internal.telephony.uicc.IsimUiccRecords$EfIsimPcscfLoaded
-com.android.internal.telephony.uicc.SIMRecords
-com.android.internal.telephony.uicc.SIMRecords$1
-com.android.internal.telephony.uicc.SIMRecords$EfPlLoaded
-com.android.internal.telephony.uicc.SIMRecords$EfUsimLiLoaded
-com.android.internal.telephony.uicc.SIMRecords$GetSpnFsmState
-com.android.internal.telephony.uicc.SpnOverride
com.android.internal.telephony.uicc.UiccCard
com.android.internal.telephony.uicc.UiccCard$1
com.android.internal.telephony.uicc.UiccCardApplication
-com.android.internal.telephony.uicc.UiccCardApplication$1
-com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules
-com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules$1
com.android.internal.telephony.uicc.UiccController
-com.android.internal.telephony.uicc.UiccPkcs15
-com.android.internal.telephony.uicc.UiccPkcs15$FileHandler
-com.android.internal.telephony.uicc.UiccPkcs15$Pkcs15Selector
-com.android.internal.telephony.uicc.UsimFileHandler
-com.android.internal.telephony.uicc.UsimServiceTable
-com.android.internal.telephony.uicc.UsimServiceTable$UsimService
-com.android.internal.telephony.uicc.VoiceMailConstants
+com.android.internal.telephony.uicc.UiccStateChangedLauncher
com.android.internal.textservice.ISpellCheckerService
com.android.internal.textservice.ISpellCheckerService$Stub
com.android.internal.textservice.ISpellCheckerService$Stub$Proxy
@@ -5827,6 +6030,9 @@ com.android.internal.util.AsyncChannel$AsyncChannelConnection
com.android.internal.util.AsyncChannel$DeathMonitor
com.android.internal.util.AsyncChannel$SyncMessenger
com.android.internal.util.AsyncChannel$SyncMessenger$SyncHandler
+com.android.internal.util.ConcurrentUtils
+com.android.internal.util.ConcurrentUtils$1
+com.android.internal.util.ConcurrentUtils$1$1
com.android.internal.util.DumpUtils$Dump
com.android.internal.util.FastMath
com.android.internal.util.FastPrintWriter
@@ -5849,7 +6055,6 @@ com.android.internal.util.MemInfoReader
com.android.internal.util.MessageUtils
com.android.internal.util.NotificationColorUtil
com.android.internal.util.NotificationColorUtil$ColorUtilsFromCompat
-com.android.internal.util.ParcelableString
com.android.internal.util.Preconditions
com.android.internal.util.Predicate
com.android.internal.util.ProcFileReader
@@ -5864,7 +6069,8 @@ com.android.internal.util.StateMachine$SmHandler
com.android.internal.util.StateMachine$SmHandler$HaltingState
com.android.internal.util.StateMachine$SmHandler$QuittingState
com.android.internal.util.StateMachine$SmHandler$StateInfo
-com.android.internal.util.UserIcons
+com.android.internal.util.ToBooleanFunction
+com.android.internal.util.TokenBucket
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.WakeupMessage
com.android.internal.util.XmlUtils
@@ -5873,12 +6079,6 @@ com.android.internal.util.XmlUtils$WriteMapCallback
com.android.internal.view.ActionBarPolicy
com.android.internal.view.BaseIWindow
com.android.internal.view.BaseSurfaceHolder
-com.android.internal.view.FloatingActionMode
-com.android.internal.view.FloatingActionMode$1
-com.android.internal.view.FloatingActionMode$2
-com.android.internal.view.FloatingActionMode$3
-com.android.internal.view.FloatingActionMode$4
-com.android.internal.view.FloatingActionMode$FloatingToolbarVisibilityHelper
com.android.internal.view.IInputConnectionWrapper
com.android.internal.view.IInputConnectionWrapper$MyHandler
com.android.internal.view.IInputConnectionWrapper$SomeArgs
@@ -5907,11 +6107,13 @@ com.android.internal.view.InputBindResult
com.android.internal.view.InputBindResult$1
com.android.internal.view.InputConnectionWrapper
com.android.internal.view.InputConnectionWrapper$InputContextCallback
+com.android.internal.view.OneShotPreDrawListener
com.android.internal.view.RootViewSurfaceTaker
com.android.internal.view.RotationPolicy
-com.android.internal.view.RotationPolicy$1
com.android.internal.view.RotationPolicy$RotationPolicyListener
com.android.internal.view.RotationPolicy$RotationPolicyListener$1
+com.android.internal.view.SurfaceCallbackHelper
+com.android.internal.view.SurfaceCallbackHelper$1
com.android.internal.view.WindowManagerPolicyThread
com.android.internal.view.animation.FallbackLUTInterpolator
com.android.internal.view.animation.HasNativeInterpolator
@@ -5921,7 +6123,6 @@ com.android.internal.view.menu.ActionMenuItem
com.android.internal.view.menu.ActionMenuItemView
com.android.internal.view.menu.ActionMenuItemView$PopupCallback
com.android.internal.view.menu.BaseMenuPresenter
-com.android.internal.view.menu.ContextMenuBuilder
com.android.internal.view.menu.ListMenuItemView
com.android.internal.view.menu.MenuAdapter
com.android.internal.view.menu.MenuBuilder
@@ -5941,12 +6142,12 @@ com.android.internal.view.menu.StandardMenuPopup
com.android.internal.view.menu.StandardMenuPopup$1
com.android.internal.view.menu.StandardMenuPopup$2
com.android.internal.view.menu.SubMenuBuilder
+com.android.internal.widget.-$Lambda$6$LaTFiUorkqfcqmu-zMQbCLeO77c
com.android.internal.widget.AbsActionBarView
com.android.internal.widget.AbsActionBarView$VisibilityAnimListener
com.android.internal.widget.ActionBarContainer
com.android.internal.widget.ActionBarContainer$ActionBarBackgroundDrawable
com.android.internal.widget.ActionBarContextView
-com.android.internal.widget.ActionBarContextView$1
com.android.internal.widget.ActionBarOverlayLayout
com.android.internal.widget.ActionBarOverlayLayout$1
com.android.internal.widget.ActionBarOverlayLayout$2
@@ -5958,60 +6159,29 @@ com.android.internal.widget.ActionBarOverlayLayout$LayoutParams
com.android.internal.widget.AlertDialogLayout
com.android.internal.widget.BackgroundFallback
com.android.internal.widget.ButtonBarLayout
+com.android.internal.widget.CachingIconView
com.android.internal.widget.DecorContentParent
com.android.internal.widget.DecorToolbar
com.android.internal.widget.DialogTitle
com.android.internal.widget.EditableInputConnection
-com.android.internal.widget.FloatingToolbar
-com.android.internal.widget.FloatingToolbar$1
-com.android.internal.widget.FloatingToolbar$2
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$1
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$12
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$13
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$14
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$15
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$16
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$2
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$3
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$4
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$5
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$LogAccelerateInterpolator
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$OverflowPanel
-com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup$OverflowPanelViewHelper
+com.android.internal.widget.ICheckCredentialProgressCallback
com.android.internal.widget.ILockSettings
com.android.internal.widget.ILockSettings$Stub
com.android.internal.widget.ILockSettings$Stub$Proxy
com.android.internal.widget.ImageFloatingTextView
-com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
-com.android.internal.widget.LockPatternChecker
-com.android.internal.widget.LockPatternChecker$3
-com.android.internal.widget.LockPatternChecker$5
-com.android.internal.widget.LockPatternChecker$OnCheckCallback
-com.android.internal.widget.LockPatternChecker$OnVerifyCallback
com.android.internal.widget.LockPatternUtils
-com.android.internal.widget.LockPatternUtils$1
com.android.internal.widget.LockPatternUtils$RequestThrottledException
com.android.internal.widget.LockPatternUtils$StrongAuthTracker
com.android.internal.widget.LockPatternUtils$StrongAuthTracker$1
com.android.internal.widget.LockPatternUtils$StrongAuthTracker$H
com.android.internal.widget.MediaNotificationView
com.android.internal.widget.NotificationActionListLayout
-com.android.internal.widget.NotificationActionListLayout$-void__clinit___LambdaImpl0
+com.android.internal.widget.NotificationExpandButton
com.android.internal.widget.PreferenceImageView
-com.android.internal.widget.ResolverDrawerLayout
-com.android.internal.widget.ResolverDrawerLayout$1
-com.android.internal.widget.ResolverDrawerLayout$LayoutParams
-com.android.internal.widget.ResolverDrawerLayout$OnDismissedListener
com.android.internal.widget.ScrollBarUtils
-com.android.internal.widget.TextViewInputDisabler
-com.android.internal.widget.TextViewInputDisabler$1
com.android.internal.widget.ToolbarWidgetWrapper
com.android.internal.widget.ToolbarWidgetWrapper$1
-com.android.internal.widget.ToolbarWidgetWrapper$2
-com.android.internal.widget.ToolbarWidgetWrapper$3
com.android.internal.widget.VerifyCredentialResponse
-com.android.internal.widget.VerifyCredentialResponse$1
com.android.okhttp.Address
com.android.okhttp.AndroidInternal
com.android.okhttp.AndroidShimResponseCache
@@ -6031,6 +6201,8 @@ com.android.okhttp.ConnectionPool$1
com.android.okhttp.ConnectionSpec
com.android.okhttp.ConnectionSpec$Builder
com.android.okhttp.Dispatcher
+com.android.okhttp.Dns
+com.android.okhttp.Dns$1
com.android.okhttp.Handshake
com.android.okhttp.Headers
com.android.okhttp.Headers$Builder
@@ -6059,12 +6231,11 @@ com.android.okhttp.internal.DiskLruCache
com.android.okhttp.internal.DiskLruCache$1
com.android.okhttp.internal.DiskLruCache$2
com.android.okhttp.internal.DiskLruCache$3
+com.android.okhttp.internal.DiskLruCache$Editor
com.android.okhttp.internal.DiskLruCache$Entry
com.android.okhttp.internal.FaultHidingSink
com.android.okhttp.internal.Internal
com.android.okhttp.internal.InternalCache
-com.android.okhttp.internal.Network
-com.android.okhttp.internal.Network$1
com.android.okhttp.internal.OptionalMethod
com.android.okhttp.internal.Platform
com.android.okhttp.internal.RouteDatabase
@@ -6075,17 +6246,17 @@ com.android.okhttp.internal.http.AuthenticatorAdapter
com.android.okhttp.internal.http.CacheStrategy
com.android.okhttp.internal.http.CacheStrategy$Factory
com.android.okhttp.internal.http.HeaderParser
-com.android.okhttp.internal.http.HttpConnection
-com.android.okhttp.internal.http.HttpConnection$AbstractSource
-com.android.okhttp.internal.http.HttpConnection$ChunkedSink
-com.android.okhttp.internal.http.HttpConnection$ChunkedSource
-com.android.okhttp.internal.http.HttpConnection$FixedLengthSink
-com.android.okhttp.internal.http.HttpConnection$FixedLengthSource
-com.android.okhttp.internal.http.HttpConnection$UnknownLengthSource
+com.android.okhttp.internal.http.Http1xStream
+com.android.okhttp.internal.http.Http1xStream$AbstractSource
+com.android.okhttp.internal.http.Http1xStream$ChunkedSink
+com.android.okhttp.internal.http.Http1xStream$ChunkedSource
+com.android.okhttp.internal.http.Http1xStream$FixedLengthSink
+com.android.okhttp.internal.http.Http1xStream$FixedLengthSource
+com.android.okhttp.internal.http.Http1xStream$UnknownLengthSource
com.android.okhttp.internal.http.HttpEngine
com.android.okhttp.internal.http.HttpEngine$1
com.android.okhttp.internal.http.HttpMethod
-com.android.okhttp.internal.http.HttpTransport
+com.android.okhttp.internal.http.HttpStream
com.android.okhttp.internal.http.OkHeaders
com.android.okhttp.internal.http.OkHeaders$1
com.android.okhttp.internal.http.RealResponseBody
@@ -6095,12 +6266,13 @@ com.android.okhttp.internal.http.RetryableSink
com.android.okhttp.internal.http.RouteException
com.android.okhttp.internal.http.RouteSelector
com.android.okhttp.internal.http.StatusLine
-com.android.okhttp.internal.http.Transport
+com.android.okhttp.internal.http.StreamAllocation
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection
com.android.okhttp.internal.huc.HttpURLConnectionImpl
com.android.okhttp.internal.huc.HttpsURLConnectionImpl
com.android.okhttp.internal.io.FileSystem
com.android.okhttp.internal.io.FileSystem$1
+com.android.okhttp.internal.io.RealConnection
com.android.okhttp.internal.tls.OkHostnameVerifier
com.android.okhttp.okio.AsyncTimeout
com.android.okhttp.okio.AsyncTimeout$1
@@ -6144,20 +6316,34 @@ com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers
com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers
com.android.org.bouncycastle.crypto.AsymmetricBlockCipher
+com.android.org.bouncycastle.crypto.BlockCipher
+com.android.org.bouncycastle.crypto.BufferedBlockCipher
com.android.org.bouncycastle.crypto.CipherKeyGenerator
+com.android.org.bouncycastle.crypto.CipherParameters
com.android.org.bouncycastle.crypto.CryptoException
+com.android.org.bouncycastle.crypto.DataLengthException
com.android.org.bouncycastle.crypto.Digest
com.android.org.bouncycastle.crypto.ExtendedDigest
com.android.org.bouncycastle.crypto.InvalidCipherTextException
com.android.org.bouncycastle.crypto.KeyGenerationParameters
+com.android.org.bouncycastle.crypto.OutputLengthException
+com.android.org.bouncycastle.crypto.RuntimeCryptoException
com.android.org.bouncycastle.crypto.digests.AndroidDigestFactory
com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryInterface
com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryOpenSSL
com.android.org.bouncycastle.crypto.digests.OpenSSLDigest
com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$SHA1
com.android.org.bouncycastle.crypto.encodings.OAEPEncoding
+com.android.org.bouncycastle.crypto.engines.AESEngine
com.android.org.bouncycastle.crypto.engines.RSABlindedEngine
com.android.org.bouncycastle.crypto.engines.RSACoreEngine
+com.android.org.bouncycastle.crypto.paddings.BlockCipherPadding
+com.android.org.bouncycastle.crypto.paddings.PKCS7Padding
+com.android.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher
+com.android.org.bouncycastle.crypto.params.KeyParameter
+com.android.org.bouncycastle.crypto.params.ParametersWithRandom
+com.android.org.bouncycastle.jcajce.PBKDFKey
+com.android.org.bouncycastle.jcajce.PKCS12Key
com.android.org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings
com.android.org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings
com.android.org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings
@@ -6195,6 +6381,8 @@ com.android.org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings
com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi
com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$Std
com.android.org.bouncycastle.jcajce.provider.symmetric.AES
+com.android.org.bouncycastle.jcajce.provider.symmetric.AES$ECB
+com.android.org.bouncycastle.jcajce.provider.symmetric.AES$ECB$1
com.android.org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen
com.android.org.bouncycastle.jcajce.provider.symmetric.AES$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4
@@ -6205,18 +6393,31 @@ com.android.org.bouncycastle.jcajce.provider.symmetric.DES
com.android.org.bouncycastle.jcajce.provider.symmetric.DES$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.DESede
com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12
com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.RC2
com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.SymmetricAlgorithmProvider
com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish
com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$GenericBlockCipher
com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider
+com.android.org.bouncycastle.jcajce.provider.symmetric.util.PBE
com.android.org.bouncycastle.jcajce.provider.util.AlgorithmProvider
com.android.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider
com.android.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
com.android.org.bouncycastle.jcajce.provider.util.DigestFactory
+com.android.org.bouncycastle.jcajce.spec.AEADParameterSpec
com.android.org.bouncycastle.jcajce.util.BCJcaJceHelper
com.android.org.bouncycastle.jcajce.util.JcaJceHelper
com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper
@@ -6226,19 +6427,25 @@ com.android.org.bouncycastle.jce.provider.BouncyCastleProvider$1
com.android.org.bouncycastle.jce.provider.BouncyCastleProviderConfiguration
com.android.org.bouncycastle.util.Arrays
com.android.org.bouncycastle.util.Encodable
+com.android.org.bouncycastle.util.Pack
com.android.org.bouncycastle.util.Strings
com.android.org.bouncycastle.util.Strings$1
+com.android.org.conscrypt.AbstractOpenSSLSession
com.android.org.conscrypt.AbstractSessionContext
com.android.org.conscrypt.AbstractSessionContext$1
com.android.org.conscrypt.AddressUtils
com.android.org.conscrypt.ByteArray
-com.android.org.conscrypt.CertPinManager
+com.android.org.conscrypt.CertBlacklist
com.android.org.conscrypt.CertificatePriorityComparator
com.android.org.conscrypt.ChainStrengthAnalyzer
com.android.org.conscrypt.ClientSessionContext
com.android.org.conscrypt.ClientSessionContext$HostAndPort
com.android.org.conscrypt.CryptoUpcalls
+com.android.org.conscrypt.EvpMdRef$MD5
+com.android.org.conscrypt.EvpMdRef$SHA1
+com.android.org.conscrypt.EvpMdRef$SHA256
com.android.org.conscrypt.FileClientSessionCache
+com.android.org.conscrypt.FileClientSessionCache$CacheFile
com.android.org.conscrypt.FileClientSessionCache$Impl
com.android.org.conscrypt.Hex
com.android.org.conscrypt.JSSEProvider
@@ -6277,7 +6484,6 @@ com.android.org.conscrypt.OpenSSLMessageDigestJDK
com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5
com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1
com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA256
-com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA512
com.android.org.conscrypt.OpenSSLProvider
com.android.org.conscrypt.OpenSSLRSAKeyFactory
com.android.org.conscrypt.OpenSSLRSAKeyPairGenerator
@@ -6304,10 +6510,8 @@ com.android.org.conscrypt.OpenSSLX509CertificateFactory$1
com.android.org.conscrypt.OpenSSLX509CertificateFactory$2
com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser
com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException
-com.android.org.conscrypt.PinEntryException
-com.android.org.conscrypt.PinListEntry
-com.android.org.conscrypt.PinManagerException
com.android.org.conscrypt.Platform
+com.android.org.conscrypt.Platform$NoPreloadHolder
com.android.org.conscrypt.SSLClientSessionCache
com.android.org.conscrypt.SSLParametersImpl
com.android.org.conscrypt.SSLParametersImpl$AliasChooser
@@ -6325,12 +6529,20 @@ com.android.org.conscrypt.TrustedCertificateStore$2
com.android.org.conscrypt.TrustedCertificateStore$4
com.android.org.conscrypt.TrustedCertificateStore$5
com.android.org.conscrypt.TrustedCertificateStore$CertSelector
+com.android.org.conscrypt.ct.CTLogInfo
+com.android.org.conscrypt.ct.CTLogStore
+com.android.org.conscrypt.ct.CTLogStoreImpl
+com.android.org.conscrypt.ct.CTLogStoreImpl$InvalidLogFileException
+com.android.org.conscrypt.ct.CTPolicy
+com.android.org.conscrypt.ct.CTPolicyImpl
+com.android.org.conscrypt.ct.CTVerifier
+com.android.org.conscrypt.ct.KnownLogs
+com.android.org.conscrypt.ct.SerializationException
com.android.org.conscrypt.util.ArrayUtils
com.android.org.conscrypt.util.EmptyArray
com.android.server.AppWidgetBackupBridge
com.android.server.BootReceiver
com.android.server.BootReceiver$1
-com.android.server.BootReceiver$2
com.android.server.LocalServices
com.android.server.NetworkManagementSocketTagger
com.android.server.NetworkManagementSocketTagger$1
@@ -6340,6 +6552,7 @@ com.android.server.SystemConfig$PermissionEntry
com.android.server.WidgetBackupProvider
com.android.server.backup.AccountSyncSettingsBackupHelper
com.android.server.net.BaseNetworkObserver
+com.android.server.net.DnsServerEntry
com.android.server.net.DnsServerRepository
com.android.server.net.NetlinkTracker
com.android.server.net.NetlinkTracker$Callback
@@ -6349,6 +6562,17 @@ com.android.server.sip.SipService$MyExecutor
com.android.server.sip.SipWakeLock
com.android.server.sip.SipWakeupTimer
com.android.server.sip.SipWakeupTimer$MyEventComparator
+com.android.server.wifi.nano.WifiMetricsProto$AlertReasonCount
+com.android.server.wifi.nano.WifiMetricsProto$ConnectionEvent
+com.android.server.wifi.nano.WifiMetricsProto$RouterFingerPrint
+com.android.server.wifi.nano.WifiMetricsProto$RssiPollCount
+com.android.server.wifi.nano.WifiMetricsProto$SoftApDurationBucket
+com.android.server.wifi.nano.WifiMetricsProto$SoftApReturnCodeCount
+com.android.server.wifi.nano.WifiMetricsProto$WifiLog
+com.android.server.wifi.nano.WifiMetricsProto$WifiLog$ScanReturnEntry
+com.android.server.wifi.nano.WifiMetricsProto$WifiLog$WifiSystemStateEntry
+com.android.server.wifi.nano.WifiMetricsProto$WifiScoreCount
+com.android.server.wm.nano.WindowManagerProtos$TaskSnapshotProto
com.google.android.collect.Lists
com.google.android.collect.Maps
com.google.android.collect.Sets
@@ -6362,15 +6586,21 @@ com.google.android.mms.MmsException
com.google.android.mms.pdu.GenericPdu
com.google.android.mms.pdu.PduComposer
com.google.android.mms.pdu.PduPersister
+dalvik.annotation.optimization.CriticalNative
+dalvik.annotation.optimization.FastNative
dalvik.system.BaseDexClassLoader
+dalvik.system.BaseDexClassLoader$Reporter
dalvik.system.BlockGuard
dalvik.system.BlockGuard$1
dalvik.system.BlockGuard$2
dalvik.system.BlockGuard$BlockGuardPolicyException
dalvik.system.BlockGuard$Policy
+dalvik.system.ClassExt
dalvik.system.CloseGuard
dalvik.system.CloseGuard$DefaultReporter
+dalvik.system.CloseGuard$DefaultTracker
dalvik.system.CloseGuard$Reporter
+dalvik.system.CloseGuard$Tracker
dalvik.system.DalvikLogHandler
dalvik.system.DalvikLogging
dalvik.system.DexClassLoader
@@ -6378,6 +6608,10 @@ dalvik.system.DexFile
dalvik.system.DexFile$DFEnum
dalvik.system.DexPathList
dalvik.system.DexPathList$Element
+dalvik.system.DexPathList$NativeLibraryElement
+dalvik.system.EmulatedStackFrame
+dalvik.system.EmulatedStackFrame$Range
+dalvik.system.InMemoryDexClassLoader$DexData
dalvik.system.PathClassLoader
dalvik.system.SocketTagger
dalvik.system.SocketTagger$1
@@ -6385,11 +6619,6 @@ dalvik.system.VMDebug
dalvik.system.VMRuntime
dalvik.system.VMStack
dalvik.system.ZygoteHooks
-java.beans.ChangeListenerMap
-java.beans.PropertyChangeEvent
-java.beans.PropertyChangeListener
-java.beans.PropertyChangeSupport
-java.beans.PropertyChangeSupport$PropertyChangeListenerMap
java.io.Bits
java.io.BufferedInputStream
java.io.BufferedOutputStream
@@ -6406,6 +6635,7 @@ java.io.DataInput
java.io.DataInputStream
java.io.DataOutput
java.io.DataOutputStream
+java.io.DefaultFileSystem
java.io.EOFException
java.io.ExpiringCache
java.io.ExpiringCache$1
@@ -6413,7 +6643,9 @@ java.io.ExpiringCache$Entry
java.io.Externalizable
java.io.File
java.io.File$PathStatus
+java.io.File$TempDirectory
java.io.FileDescriptor
+java.io.FileDescriptor$1
java.io.FileFilter
java.io.FileInputStream
java.io.FileInputStream$UseManualSkipException
@@ -6433,6 +6665,7 @@ java.io.InputStreamReader
java.io.InterruptedIOException
java.io.InvalidClassException
java.io.InvalidObjectException
+java.io.NotSerializableException
java.io.ObjectInput
java.io.ObjectInputStream
java.io.ObjectInputStream$BlockDataInputStream
@@ -6444,6 +6677,7 @@ java.io.ObjectOutput
java.io.ObjectOutputStream
java.io.ObjectOutputStream$BlockDataOutputStream
java.io.ObjectOutputStream$HandleTable
+java.io.ObjectOutputStream$PutField
java.io.ObjectOutputStream$ReplaceTable
java.io.ObjectStreamClass
java.io.ObjectStreamClass$1
@@ -6474,13 +6708,17 @@ java.io.SequenceInputStream
java.io.SerialCallbackContext
java.io.Serializable
java.io.SerializablePermission
+java.io.StreamCorruptedException
java.io.StringBufferInputStream
java.io.StringReader
java.io.StringWriter
+java.io.SyncFailedException
java.io.UTFDataFormatException
java.io.UnixFileSystem
java.io.UnsupportedEncodingException
java.io.Writer
+java.lang.-$Lambda$250$S9HjrJh0nDg7IyU6wZdPArnZWRQ
+java.lang.-$Lambda$251$S9HjrJh0nDg7IyU6wZdPArnZWRQ
java.lang.AbstractMethodError
java.lang.AbstractStringBuilder
java.lang.AndroidHardcodedSystemProperties
@@ -6497,8 +6735,6 @@ java.lang.Byte$ByteCache
java.lang.CaseMapper
java.lang.CaseMapper$1
java.lang.CharSequence
-java.lang.CharSequence$-java_util_stream_IntStream_chars__LambdaImpl0
-java.lang.CharSequence$-java_util_stream_IntStream_codePoints__LambdaImpl0
java.lang.CharSequence$1CharIterator
java.lang.CharSequence$1CodePointIterator
java.lang.Character
@@ -6530,9 +6766,6 @@ java.lang.Error
java.lang.Exception
java.lang.ExceptionInInitializerError
java.lang.Float
-java.lang.FloatingDecimal
-java.lang.FloatingDecimal$1
-java.lang.FloatingDecimal$2
java.lang.IllegalAccessError
java.lang.IllegalAccessException
java.lang.IllegalArgumentException
@@ -6542,6 +6775,7 @@ java.lang.IllegalThreadStateException
java.lang.IncompatibleClassChangeError
java.lang.IndexOutOfBoundsException
java.lang.InheritableThreadLocal
+java.lang.InstantiationError
java.lang.InstantiationException
java.lang.Integer
java.lang.Integer$IntegerCache
@@ -6553,7 +6787,8 @@ java.lang.LinkageError
java.lang.Long
java.lang.Long$LongCache
java.lang.Math
-java.lang.Math$NoImagePreloadHolder
+java.lang.Math$RandomNumberGeneratorHolder
+java.lang.NegativeArraySizeException
java.lang.NoClassDefFoundError
java.lang.NoSuchFieldError
java.lang.NoSuchFieldException
@@ -6585,7 +6820,6 @@ java.lang.SecurityException
java.lang.SecurityManager
java.lang.Short
java.lang.Short$ShortCache
-java.lang.Shutdown
java.lang.StackOverflowError
java.lang.StackTraceElement
java.lang.StrictMath
@@ -6593,7 +6827,6 @@ java.lang.String
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
-java.lang.StringCoding
java.lang.StringFactory
java.lang.StringIndexOutOfBoundsException
java.lang.System
@@ -6635,6 +6868,22 @@ java.lang.annotation.IncompleteAnnotationException
java.lang.annotation.Inherited
java.lang.annotation.Retention
java.lang.annotation.Target
+java.lang.invoke.MethodHandle
+java.lang.invoke.MethodHandleImpl
+java.lang.invoke.MethodHandleImpl$HandleInfo
+java.lang.invoke.MethodHandleInfo
+java.lang.invoke.MethodHandleStatics
+java.lang.invoke.MethodHandles
+java.lang.invoke.MethodType
+java.lang.invoke.MethodType$ConcurrentWeakInternSet
+java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry
+java.lang.invoke.MethodTypeForm
+java.lang.invoke.Transformers$BindTo
+java.lang.invoke.Transformers$Collector
+java.lang.invoke.Transformers$Spreader
+java.lang.invoke.Transformers$Transformer
+java.lang.invoke.Transformers$VarargsCollector
+java.lang.invoke.WrongMethodTypeException
java.lang.ref.FinalizerReference
java.lang.ref.FinalizerReference$Sentinel
java.lang.ref.PhantomReference
@@ -6642,27 +6891,40 @@ java.lang.ref.Reference
java.lang.ref.ReferenceQueue
java.lang.ref.SoftReference
java.lang.ref.WeakReference
-java.lang.reflect.AbstractMethod
-java.lang.reflect.AbstractMethod$GenericInfo
java.lang.reflect.AccessibleObject
java.lang.reflect.AnnotatedElement
java.lang.reflect.Array
java.lang.reflect.Constructor
+java.lang.reflect.Executable
+java.lang.reflect.Executable$GenericInfo
java.lang.reflect.Field
java.lang.reflect.GenericArrayType
java.lang.reflect.GenericDeclaration
java.lang.reflect.InvocationHandler
java.lang.reflect.InvocationTargetException
+java.lang.reflect.MalformedParametersException
java.lang.reflect.Member
java.lang.reflect.Method
java.lang.reflect.Method$1
java.lang.reflect.Modifier
+java.lang.reflect.Parameter
java.lang.reflect.ParameterizedType
java.lang.reflect.Proxy
java.lang.reflect.Proxy$1
+java.lang.reflect.Proxy$Key1
+java.lang.reflect.Proxy$Key2
+java.lang.reflect.Proxy$KeyFactory
+java.lang.reflect.Proxy$KeyX
+java.lang.reflect.Proxy$ProxyClassFactory
java.lang.reflect.Type
java.lang.reflect.TypeVariable
java.lang.reflect.UndeclaredThrowableException
+java.lang.reflect.WeakCache
+java.lang.reflect.WeakCache$CacheKey
+java.lang.reflect.WeakCache$CacheValue
+java.lang.reflect.WeakCache$Factory
+java.lang.reflect.WeakCache$LookupValue
+java.lang.reflect.WeakCache$Value
java.lang.reflect.WildcardType
java.math.BigDecimal
java.math.BigInt
@@ -6670,7 +6932,6 @@ java.math.BigInteger
java.math.BitLevel
java.math.Conversion
java.math.Division
-java.math.Logical
java.math.MathContext
java.math.Multiplication
java.math.NativeBN
@@ -6717,6 +6978,7 @@ java.net.IDN
java.net.InMemoryCookieStore
java.net.Inet4Address
java.net.Inet6Address
+java.net.Inet6Address$Inet6AddressHolder
java.net.Inet6AddressImpl
java.net.InetAddress
java.net.InetAddress$1
@@ -6729,7 +6991,6 @@ java.net.JarURLConnection
java.net.MalformedURLException
java.net.MulticastSocket
java.net.NetworkInterface
-java.net.NetworkInterface$1
java.net.NetworkInterface$1checkedAddresses
java.net.NoRouteToHostException
java.net.Parts
@@ -6738,14 +6999,12 @@ java.net.PlainDatagramSocketImpl
java.net.PlainSocketImpl
java.net.PortUnreachableException
java.net.ProtocolException
-java.net.ProtocolFamily
java.net.Proxy
java.net.Proxy$Type
java.net.ProxySelector
java.net.ResponseCache
java.net.ServerSocket
java.net.Socket
-java.net.Socket$1
java.net.Socket$2
java.net.Socket$3
java.net.SocketAddress
@@ -6757,8 +7016,6 @@ java.net.SocketOutputStream
java.net.SocketTimeoutException
java.net.SocksConsts
java.net.SocksSocketImpl
-java.net.SocksSocketImpl$3
-java.net.StandardProtocolFamily
java.net.URI
java.net.URI$Parser
java.net.URISyntaxException
@@ -6804,7 +7061,6 @@ java.nio.channels.ByteChannel
java.nio.channels.CancelledKeyException
java.nio.channels.Channel
java.nio.channels.Channels
-java.nio.channels.Channels$1
java.nio.channels.Channels$ReadableByteChannelImpl
java.nio.channels.ClosedByInterruptException
java.nio.channels.ClosedChannelException
@@ -6814,6 +7070,7 @@ java.nio.channels.FileChannel$MapMode
java.nio.channels.FileLock
java.nio.channels.GatheringByteChannel
java.nio.channels.InterruptibleChannel
+java.nio.channels.MulticastChannel
java.nio.channels.NetworkChannel
java.nio.channels.NonWritableChannelException
java.nio.channels.OverlappingFileLockException
@@ -6821,19 +7078,12 @@ java.nio.channels.ReadableByteChannel
java.nio.channels.ScatteringByteChannel
java.nio.channels.SeekableByteChannel
java.nio.channels.SelectableChannel
-java.nio.channels.SelectionKey
-java.nio.channels.Selector
java.nio.channels.ServerSocketChannel
java.nio.channels.SocketChannel
java.nio.channels.WritableByteChannel
java.nio.channels.spi.AbstractInterruptibleChannel
java.nio.channels.spi.AbstractInterruptibleChannel$1
java.nio.channels.spi.AbstractSelectableChannel
-java.nio.channels.spi.AbstractSelectionKey
-java.nio.channels.spi.AbstractSelector
-java.nio.channels.spi.AbstractSelector$1
-java.nio.channels.spi.SelectorProvider
-java.nio.channels.spi.SelectorProvider$1
java.nio.charset.CharacterCodingException
java.nio.charset.Charset
java.nio.charset.CharsetDecoder
@@ -6849,6 +7099,21 @@ java.nio.charset.CodingErrorAction
java.nio.charset.IllegalCharsetNameException
java.nio.charset.StandardCharsets
java.nio.charset.UnsupportedCharsetException
+java.nio.file.FileAlreadyExistsException
+java.nio.file.FileSystem
+java.nio.file.FileSystemException
+java.nio.file.FileSystems
+java.nio.file.FileSystems$DefaultFileSystemHolder
+java.nio.file.FileSystems$DefaultFileSystemHolder$1
+java.nio.file.Files
+java.nio.file.NoSuchFileException
+java.nio.file.OpenOption
+java.nio.file.Path
+java.nio.file.Watchable
+java.nio.file.attribute.BasicFileAttributes
+java.nio.file.attribute.FileAttribute
+java.nio.file.attribute.PosixFileAttributes
+java.nio.file.spi.FileSystemProvider
java.security.AccessControlContext
java.security.AccessControlException
java.security.AccessController
@@ -6911,6 +7176,7 @@ java.security.UnrecoverableKeyException
java.security.cert.CRL
java.security.cert.CRLException
java.security.cert.CertPath
+java.security.cert.CertPathBuilderException
java.security.cert.CertPathChecker
java.security.cert.CertPathHelperImpl
java.security.cert.CertPathParameters
@@ -6949,7 +7215,6 @@ java.security.interfaces.RSAPrivateKey
java.security.interfaces.RSAPublicKey
java.security.spec.AlgorithmParameterSpec
java.security.spec.ECField
-java.security.spec.ECFieldF2m
java.security.spec.ECFieldFp
java.security.spec.ECGenParameterSpec
java.security.spec.ECParameterSpec
@@ -6963,6 +7228,8 @@ java.security.spec.InvalidParameterSpecException
java.security.spec.KeySpec
java.security.spec.MGF1ParameterSpec
java.security.spec.PKCS8EncodedKeySpec
+java.security.spec.RSAPrivateCrtKeySpec
+java.security.spec.RSAPrivateKeySpec
java.security.spec.RSAPublicKeySpec
java.security.spec.X509EncodedKeySpec
java.sql.Date
@@ -6998,17 +7265,23 @@ java.text.ParsePosition
java.text.RuleBasedCollator
java.text.SimpleDateFormat
java.text.StringCharacterIterator
-java.text.spi.DateFormatProvider
-java.text.spi.DateFormatSymbolsProvider
-java.text.spi.DecimalFormatSymbolsProvider
-java.text.spi.NumberFormatProvider
+java.time.DateTimeException
+java.util.-$Lambda$181$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$182$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$183$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$184$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$267$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$268$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$291$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$292$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$293$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$294$aUGKT4ItCOku5-JSG-x8Aqj2pJw
java.util.AbstractCollection
java.util.AbstractList
java.util.AbstractList$Itr
java.util.AbstractList$ListItr
java.util.AbstractMap
java.util.AbstractMap$1
-java.util.AbstractMap$1$1
java.util.AbstractMap$2
java.util.AbstractMap$2$1
java.util.AbstractMap$SimpleEntry
@@ -7018,14 +7291,31 @@ java.util.AbstractSequentialList
java.util.AbstractSet
java.util.ArrayDeque
java.util.ArrayDeque$DeqIterator
+java.util.ArrayDeque$DescendingIterator
java.util.ArrayList
java.util.ArrayList$ArrayListSpliterator
java.util.ArrayList$Itr
java.util.ArrayList$ListItr
java.util.ArrayList$SubList
java.util.ArrayList$SubList$1
+java.util.ArrayPrefixHelpers$CumulateTask
+java.util.ArrayPrefixHelpers$DoubleCumulateTask
+java.util.ArrayPrefixHelpers$IntCumulateTask
+java.util.ArrayPrefixHelpers$LongCumulateTask
java.util.Arrays
java.util.Arrays$ArrayList
+java.util.Arrays$NaturalOrder
+java.util.ArraysParallelSortHelpers$FJByte$Sorter
+java.util.ArraysParallelSortHelpers$FJChar$Sorter
+java.util.ArraysParallelSortHelpers$FJDouble$Sorter
+java.util.ArraysParallelSortHelpers$FJFloat$Sorter
+java.util.ArraysParallelSortHelpers$FJInt$Sorter
+java.util.ArraysParallelSortHelpers$FJLong$Sorter
+java.util.ArraysParallelSortHelpers$FJObject$Sorter
+java.util.ArraysParallelSortHelpers$FJShort$Sorter
+java.util.Base64
+java.util.Base64$Decoder
+java.util.Base64$Encoder
java.util.BitSet
java.util.Calendar
java.util.Collection
@@ -7037,6 +7327,9 @@ java.util.Collections$AsLIFOQueue
java.util.Collections$CheckedCollection
java.util.Collections$CheckedList
java.util.Collections$CheckedMap
+java.util.Collections$CheckedNavigableMap
+java.util.Collections$CheckedNavigableSet
+java.util.Collections$CheckedQueue
java.util.Collections$CheckedRandomAccessList
java.util.Collections$CheckedSet
java.util.Collections$CheckedSortedMap
@@ -7057,6 +7350,8 @@ java.util.Collections$SingletonSet
java.util.Collections$SynchronizedCollection
java.util.Collections$SynchronizedList
java.util.Collections$SynchronizedMap
+java.util.Collections$SynchronizedNavigableMap
+java.util.Collections$SynchronizedNavigableSet
java.util.Collections$SynchronizedRandomAccessList
java.util.Collections$SynchronizedSet
java.util.Collections$SynchronizedSortedMap
@@ -7069,18 +7364,16 @@ java.util.Collections$UnmodifiableMap
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry
+java.util.Collections$UnmodifiableNavigableMap
+java.util.Collections$UnmodifiableNavigableMap$EmptyNavigableMap
+java.util.Collections$UnmodifiableNavigableSet
+java.util.Collections$UnmodifiableNavigableSet$EmptyNavigableSet
java.util.Collections$UnmodifiableRandomAccessList
java.util.Collections$UnmodifiableSet
java.util.Collections$UnmodifiableSortedMap
java.util.Collections$UnmodifiableSortedSet
java.util.ComparableTimSort
java.util.Comparator
-java.util.Comparator$-java_util_Comparator_comparingDouble_java_util_function_ToDoubleFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparingInt_java_util_function_ToIntFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparingLong_java_util_function_ToLongFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_java_util_Comparator_keyComparator_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_thenComparing_java_util_Comparator_other_LambdaImpl0
java.util.Comparators$NaturalOrderComparator
java.util.Comparators$NullComparator
java.util.ConcurrentModificationException
@@ -7104,8 +7397,6 @@ java.util.EnumSet
java.util.EnumSet$SerializationProxy
java.util.Enumeration
java.util.EventListener
-java.util.EventObject
-java.util.FormatFlagsConversionMismatchException
java.util.Formattable
java.util.Formatter
java.util.Formatter$Conversion
@@ -7120,9 +7411,10 @@ java.util.HashMap
java.util.HashMap$EntryIterator
java.util.HashMap$EntrySet
java.util.HashMap$HashIterator
-java.util.HashMap$HashMapEntry
java.util.HashMap$KeyIterator
java.util.HashMap$KeySet
+java.util.HashMap$Node
+java.util.HashMap$TreeNode
java.util.HashMap$ValueIterator
java.util.HashMap$Values
java.util.HashSet
@@ -7147,11 +7439,14 @@ java.util.Iterator
java.util.JumboEnumSet
java.util.JumboEnumSet$EnumSetIterator
java.util.LinkedHashMap
-java.util.LinkedHashMap$EntryIterator
-java.util.LinkedHashMap$KeyIterator
+java.util.LinkedHashMap$LinkedEntryIterator
+java.util.LinkedHashMap$LinkedEntrySet
java.util.LinkedHashMap$LinkedHashIterator
java.util.LinkedHashMap$LinkedHashMapEntry
-java.util.LinkedHashMap$ValueIterator
+java.util.LinkedHashMap$LinkedKeyIterator
+java.util.LinkedHashMap$LinkedKeySet
+java.util.LinkedHashMap$LinkedValueIterator
+java.util.LinkedHashMap$LinkedValues
java.util.LinkedHashSet
java.util.LinkedList
java.util.LinkedList$DescendingIterator
@@ -7159,10 +7454,13 @@ java.util.LinkedList$ListItr
java.util.LinkedList$Node
java.util.List
java.util.ListIterator
+java.util.ListResourceBundle
java.util.Locale
java.util.Locale$Builder
java.util.Locale$Cache
java.util.Locale$Category
+java.util.Locale$FilteringMode
+java.util.Locale$LanguageRange
java.util.Locale$LocaleKey
java.util.Map
java.util.Map$Entry
@@ -7196,14 +7494,8 @@ java.util.ResourceBundle$Control
java.util.ResourceBundle$Control$1
java.util.ResourceBundle$Control$CandidateListCache
java.util.ResourceBundle$LoaderReference
-java.util.ResourceBundle$RBClassLoader
-java.util.ResourceBundle$RBClassLoader$1
java.util.Scanner
java.util.Scanner$1
-java.util.ServiceConfigurationError
-java.util.ServiceLoader
-java.util.ServiceLoader$1
-java.util.ServiceLoader$LazyIterator
java.util.Set
java.util.SimpleTimeZone
java.util.SortedMap
@@ -7219,6 +7511,7 @@ java.util.Spliterators$EmptySpliterator$OfDouble
java.util.Spliterators$EmptySpliterator$OfInt
java.util.Spliterators$EmptySpliterator$OfLong
java.util.Spliterators$EmptySpliterator$OfRef
+java.util.Spliterators$IteratorSpliterator
java.util.Stack
java.util.StringJoiner
java.util.StringTokenizer
@@ -7263,6 +7556,7 @@ java.util.WeakHashMap$KeyIterator
java.util.WeakHashMap$KeySet
java.util.WeakHashMap$ValueIterator
java.util.WeakHashMap$Values
+java.util.concurrent.-$Lambda$269$xR9BLpu6SifNikvFgr4lEiECBsk
java.util.concurrent.AbstractExecutorService
java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.BlockingDeque
@@ -7278,15 +7572,48 @@ java.util.concurrent.CompletionService
java.util.concurrent.CompletionStage
java.util.concurrent.ConcurrentHashMap
java.util.concurrent.ConcurrentHashMap$BaseIterator
+java.util.concurrent.ConcurrentHashMap$BulkTask
java.util.concurrent.ConcurrentHashMap$CollectionView
java.util.concurrent.ConcurrentHashMap$CounterCell
java.util.concurrent.ConcurrentHashMap$EntryIterator
java.util.concurrent.ConcurrentHashMap$EntrySetView
+java.util.concurrent.ConcurrentHashMap$ForEachEntryTask
+java.util.concurrent.ConcurrentHashMap$ForEachKeyTask
+java.util.concurrent.ConcurrentHashMap$ForEachMappingTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedEntryTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedKeyTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedMappingTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedValueTask
+java.util.concurrent.ConcurrentHashMap$ForEachValueTask
java.util.concurrent.ConcurrentHashMap$ForwardingNode
java.util.concurrent.ConcurrentHashMap$KeyIterator
java.util.concurrent.ConcurrentHashMap$KeySetView
java.util.concurrent.ConcurrentHashMap$MapEntry
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToLongTask
java.util.concurrent.ConcurrentHashMap$Node
+java.util.concurrent.ConcurrentHashMap$ReduceEntriesTask
+java.util.concurrent.ConcurrentHashMap$ReduceKeysTask
+java.util.concurrent.ConcurrentHashMap$ReduceValuesTask
+java.util.concurrent.ConcurrentHashMap$ReservationNode
+java.util.concurrent.ConcurrentHashMap$SearchEntriesTask
+java.util.concurrent.ConcurrentHashMap$SearchKeysTask
+java.util.concurrent.ConcurrentHashMap$SearchMappingsTask
+java.util.concurrent.ConcurrentHashMap$SearchValuesTask
java.util.concurrent.ConcurrentHashMap$Segment
java.util.concurrent.ConcurrentHashMap$Traverser
java.util.concurrent.ConcurrentHashMap$TreeBin
@@ -7305,15 +7632,15 @@ java.util.concurrent.ConcurrentSkipListMap$Iter
java.util.concurrent.ConcurrentSkipListMap$KeyIterator
java.util.concurrent.ConcurrentSkipListMap$KeySet
java.util.concurrent.ConcurrentSkipListMap$Node
-java.util.concurrent.ConcurrentSkipListMap$SubMap
java.util.concurrent.ConcurrentSkipListMap$ValueIterator
java.util.concurrent.ConcurrentSkipListMap$Values
java.util.concurrent.ConcurrentSkipListSet
java.util.concurrent.CopyOnWriteArrayList
-java.util.concurrent.CopyOnWriteArrayList$CowIterator
+java.util.concurrent.CopyOnWriteArrayList$COWIterator
java.util.concurrent.CopyOnWriteArraySet
java.util.concurrent.CountDownLatch
java.util.concurrent.CountDownLatch$Sync
+java.util.concurrent.CountedCompleter
java.util.concurrent.DelayQueue
java.util.concurrent.Delayed
java.util.concurrent.ExecutionException
@@ -7345,6 +7672,8 @@ java.util.concurrent.LinkedBlockingDeque$Node
java.util.concurrent.LinkedBlockingQueue
java.util.concurrent.LinkedBlockingQueue$Itr
java.util.concurrent.LinkedBlockingQueue$Node
+java.util.concurrent.Phaser
+java.util.concurrent.Phaser$QNode
java.util.concurrent.PriorityBlockingQueue
java.util.concurrent.RejectedExecutionException
java.util.concurrent.RejectedExecutionHandler
@@ -7367,6 +7696,7 @@ java.util.concurrent.ThreadLocalRandom
java.util.concurrent.ThreadLocalRandom$1
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.ThreadPoolExecutor$AbortPolicy
+java.util.concurrent.ThreadPoolExecutor$DiscardOldestPolicy
java.util.concurrent.ThreadPoolExecutor$DiscardPolicy
java.util.concurrent.ThreadPoolExecutor$Worker
java.util.concurrent.TimeUnit
@@ -7411,21 +7741,35 @@ java.util.concurrent.locks.ReentrantReadWriteLock$Sync
java.util.concurrent.locks.ReentrantReadWriteLock$Sync$HoldCounter
java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
+java.util.function.-$Lambda$276$1MZdIZ-DL_fjy9l0o8IMJk57T2g
java.util.function.BiConsumer
java.util.function.BiFunction
+java.util.function.BinaryOperator
java.util.function.Consumer
+java.util.function.DoubleBinaryOperator
java.util.function.Function
+java.util.function.IntBinaryOperator
+java.util.function.IntConsumer
+java.util.function.IntFunction
+java.util.function.IntToDoubleFunction
+java.util.function.IntToLongFunction
+java.util.function.IntUnaryOperator
+java.util.function.LongBinaryOperator
+java.util.function.LongUnaryOperator
java.util.function.Predicate
java.util.function.Supplier
+java.util.function.ToDoubleBiFunction
java.util.function.ToDoubleFunction
+java.util.function.ToIntBiFunction
java.util.function.ToIntFunction
+java.util.function.ToLongBiFunction
java.util.function.ToLongFunction
java.util.function.UnaryOperator
java.util.jar.Attributes
java.util.jar.Attributes$Name
java.util.jar.JarEntry
java.util.jar.JarFile
-java.util.jar.JarFile$1
+java.util.jar.JarFile$JarEntryIterator
java.util.jar.JarFile$JarFileEntry
java.util.jar.JarVerifier
java.util.jar.JarVerifier$1
@@ -7433,9 +7777,6 @@ java.util.jar.JarVerifier$VerifierStream
java.util.jar.Manifest
java.util.jar.Manifest$FastInputStream
java.util.logging.ErrorManager
-java.util.logging.FileHandler
-java.util.logging.FileHandler$InitializationErrorManager
-java.util.logging.FileHandler$MeteredStream
java.util.logging.Filter
java.util.logging.Formatter
java.util.logging.Handler
@@ -7444,7 +7785,8 @@ java.util.logging.Level$KnownLevel
java.util.logging.LogManager
java.util.logging.LogManager$1
java.util.logging.LogManager$2
-java.util.logging.LogManager$4
+java.util.logging.LogManager$3
+java.util.logging.LogManager$5
java.util.logging.LogManager$Cleaner
java.util.logging.LogManager$LogNode
java.util.logging.LogManager$LoggerContext
@@ -7455,31 +7797,71 @@ java.util.logging.LogManager$SystemLoggerContext
java.util.logging.LogRecord
java.util.logging.Logger
java.util.logging.Logger$1
+java.util.logging.Logger$LoggerBundle
java.util.logging.LoggingPermission
java.util.logging.LoggingProxyImpl
-java.util.logging.SimpleFormatter
-java.util.logging.StreamHandler
-java.util.logging.XMLFormatter
java.util.prefs.AbstractPreferences
java.util.prefs.FileSystemPreferences
java.util.prefs.Preferences
java.util.regex.MatchResult
java.util.regex.Matcher
+java.util.regex.Matcher$OffsetBasedMatchResult
java.util.regex.Pattern
java.util.regex.PatternSyntaxException
-java.util.spi.LocaleServiceProvider
+java.util.stream.-$Lambda$155$qTstLJg88fs2C3g6LH-R51vCVP0
+java.util.stream.-$Lambda$41$qTstLJg88fs2C3g6LH-R51vCVP0
+java.util.stream.-$Lambda$67$qTstLJg88fs2C3g6LH-R51vCVP0
+java.util.stream.-$Lambda$89$qTstLJg88fs2C3g6LH-R51vCVP0
+java.util.stream.AbstractPipeline
java.util.stream.BaseStream
+java.util.stream.Collector
+java.util.stream.Collector$Characteristics
+java.util.stream.Collectors
+java.util.stream.Collectors$CollectorImpl
+java.util.stream.DoubleStream
+java.util.stream.ForEachOps
+java.util.stream.ForEachOps$ForEachOp
+java.util.stream.ForEachOps$ForEachOp$OfRef
java.util.stream.IntStream
+java.util.stream.LongStream
+java.util.stream.PipelineHelper
+java.util.stream.ReduceOps
+java.util.stream.ReduceOps$3
+java.util.stream.ReduceOps$3ReducingSink
+java.util.stream.ReduceOps$AccumulatingSink
+java.util.stream.ReduceOps$Box
+java.util.stream.ReduceOps$ReduceOp
+java.util.stream.ReferencePipeline
+java.util.stream.ReferencePipeline$2
+java.util.stream.ReferencePipeline$2$1
+java.util.stream.ReferencePipeline$Head
+java.util.stream.ReferencePipeline$StatefulOp
+java.util.stream.ReferencePipeline$StatelessOp
+java.util.stream.Sink
+java.util.stream.Sink$ChainedReference
+java.util.stream.SliceOps
+java.util.stream.SliceOps$1
+java.util.stream.SliceOps$1$1
java.util.stream.Stream
+java.util.stream.StreamOpFlag
+java.util.stream.StreamOpFlag$MaskBuilder
+java.util.stream.StreamOpFlag$Type
+java.util.stream.StreamShape
+java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator
+java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef
java.util.stream.StreamSupport
+java.util.stream.TerminalOp
+java.util.stream.TerminalSink
java.util.zip.Adler32
java.util.zip.CRC32
java.util.zip.CheckedInputStream
+java.util.zip.CheckedOutputStream
java.util.zip.Checksum
java.util.zip.DataFormatException
java.util.zip.Deflater
java.util.zip.DeflaterOutputStream
java.util.zip.GZIPInputStream
+java.util.zip.GZIPInputStream$1
java.util.zip.GZIPOutputStream
java.util.zip.Inflater
java.util.zip.InflaterInputStream
@@ -7487,13 +7869,15 @@ java.util.zip.ZStreamRef
java.util.zip.ZipCoder
java.util.zip.ZipConstants
java.util.zip.ZipEntry
+java.util.zip.ZipError
java.util.zip.ZipException
java.util.zip.ZipFile
-java.util.zip.ZipFile$1
+java.util.zip.ZipFile$ZipEntryIterator
java.util.zip.ZipFile$ZipFileInflaterInputStream
java.util.zip.ZipFile$ZipFileInputStream
java.util.zip.ZipInputStream
java.util.zip.ZipOutputStream
+java.util.zip.ZipUtils
javax.crypto.BadPaddingException
javax.crypto.Cipher
javax.crypto.Cipher$CipherSpiAndProvider
@@ -7505,7 +7889,6 @@ javax.crypto.Cipher$Transform
javax.crypto.CipherInputStream
javax.crypto.CipherOutputStream
javax.crypto.CipherSpi
-javax.crypto.EncryptedPrivateKeyInfo
javax.crypto.IllegalBlockSizeException
javax.crypto.JarVerifier
javax.crypto.JceSecurity
@@ -7517,11 +7900,11 @@ javax.crypto.MacSpi
javax.crypto.NoSuchPaddingException
javax.crypto.NullCipher
javax.crypto.SecretKey
-javax.crypto.SecretKeyFactory
javax.crypto.ShortBufferException
+javax.crypto.interfaces.PBEKey
+javax.crypto.spec.GCMParameterSpec
javax.crypto.spec.IvParameterSpec
javax.crypto.spec.OAEPParameterSpec
-javax.crypto.spec.PBEKeySpec
javax.crypto.spec.PBEParameterSpec
javax.crypto.spec.PSource
javax.crypto.spec.PSource$PSpecified
@@ -7545,6 +7928,7 @@ javax.net.ssl.ExtendedSSLSession
javax.net.ssl.HandshakeCompletedListener
javax.net.ssl.HostnameVerifier
javax.net.ssl.HttpsURLConnection
+javax.net.ssl.HttpsURLConnection$NoPreloadHolder
javax.net.ssl.KeyManager
javax.net.ssl.KeyManagerFactory
javax.net.ssl.KeyManagerFactory$1
@@ -7573,9 +7957,11 @@ javax.net.ssl.X509ExtendedKeyManager
javax.net.ssl.X509ExtendedTrustManager
javax.net.ssl.X509KeyManager
javax.net.ssl.X509TrustManager
+javax.security.auth.Destroyable
javax.security.auth.callback.UnsupportedCallbackException
javax.security.auth.x500.X500Principal
javax.security.cert.Certificate
+javax.security.cert.CertificateEncodingException
javax.security.cert.CertificateException
javax.security.cert.X509Certificate
javax.sip.SipException
@@ -7606,8 +7992,6 @@ libcore.icu.TimeZoneNames$1
libcore.icu.TimeZoneNames$ZoneStringsCache
libcore.internal.StringPool
libcore.io.AsynchronousCloseMonitor
-libcore.io.Base64
-libcore.io.Base64$InvalidBase64ByteException
libcore.io.BlockGuardOs
libcore.io.BufferIterator
libcore.io.ClassPathURLStreamHandler
@@ -7621,6 +8005,8 @@ libcore.io.EventLogger$DefaultReporter
libcore.io.EventLogger$Reporter
libcore.io.ForwardingOs
libcore.io.IoBridge
+libcore.io.IoTracker
+libcore.io.IoTracker$Mode
libcore.io.IoUtils
libcore.io.IoUtils$FileReader
libcore.io.Libcore
@@ -7637,6 +8023,8 @@ libcore.net.NetworkSecurityPolicy$DefaultNetworkSecurityPolicy
libcore.net.UriCodec
libcore.net.event.NetworkEventDispatcher
libcore.net.event.NetworkEventListener
+libcore.net.http.HttpDate
+libcore.net.http.HttpDate$1
libcore.reflect.AnnotatedElements
libcore.reflect.AnnotationFactory
libcore.reflect.AnnotationMember
@@ -7682,21 +8070,16 @@ org.apache.harmony.xml.ExpatParser$CurrentAttributes
org.apache.harmony.xml.ExpatParser$ExpatLocator
org.apache.harmony.xml.ExpatReader
org.apache.harmony.xml.dom.AttrImpl
-org.apache.harmony.xml.dom.CDATASectionImpl
org.apache.harmony.xml.dom.CharacterDataImpl
-org.apache.harmony.xml.dom.CommentImpl
org.apache.harmony.xml.dom.DOMImplementationImpl
org.apache.harmony.xml.dom.DocumentImpl
-org.apache.harmony.xml.dom.DocumentTypeImpl
org.apache.harmony.xml.dom.ElementImpl
org.apache.harmony.xml.dom.ElementImpl$ElementAttrNamedNodeMapImpl
-org.apache.harmony.xml.dom.EntityReferenceImpl
org.apache.harmony.xml.dom.InnerNodeImpl
org.apache.harmony.xml.dom.LeafNodeImpl
org.apache.harmony.xml.dom.NodeImpl
org.apache.harmony.xml.dom.NodeImpl$1
org.apache.harmony.xml.dom.NodeListImpl
-org.apache.harmony.xml.dom.ProcessingInstructionImpl
org.apache.harmony.xml.dom.TextImpl
org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl
org.apache.harmony.xml.parsers.DocumentBuilderImpl
@@ -7735,7 +8118,6 @@ org.apache.http.ProtocolVersion
org.apache.http.ReasonPhraseCatalog
org.apache.http.RequestLine
org.apache.http.StatusLine
-org.apache.http.TokenIterator
org.apache.http.auth.AuthSchemeFactory
org.apache.http.auth.AuthSchemeRegistry
org.apache.http.auth.AuthState
@@ -7773,7 +8155,6 @@ org.apache.http.client.utils.URIUtils
org.apache.http.client.utils.URLEncodedUtils
org.apache.http.conn.BasicManagedEntity
org.apache.http.conn.ClientConnectionManager
-org.apache.http.conn.ClientConnectionManagerFactory
org.apache.http.conn.ClientConnectionOperator
org.apache.http.conn.ClientConnectionRequest
org.apache.http.conn.ConnectTimeoutException
@@ -7828,7 +8209,6 @@ org.apache.http.entity.AbstractHttpEntity
org.apache.http.entity.BasicHttpEntity
org.apache.http.entity.ByteArrayEntity
org.apache.http.entity.ContentLengthStrategy
-org.apache.http.entity.FileEntity
org.apache.http.entity.HttpEntityWrapper
org.apache.http.entity.InputStreamEntity
org.apache.http.entity.StringEntity
@@ -7848,7 +8228,6 @@ org.apache.http.impl.client.AbstractAuthenticationHandler
org.apache.http.impl.client.AbstractHttpClient
org.apache.http.impl.client.BasicCookieStore
org.apache.http.impl.client.BasicCredentialsProvider
-org.apache.http.impl.client.BasicResponseHandler
org.apache.http.impl.client.ClientParamsStack
org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
org.apache.http.impl.client.DefaultHttpClient
@@ -7859,6 +8238,7 @@ org.apache.http.impl.client.DefaultRequestDirector
org.apache.http.impl.client.DefaultTargetAuthenticationHandler
org.apache.http.impl.client.DefaultUserTokenHandler
org.apache.http.impl.client.EntityEnclosingRequestWrapper
+org.apache.http.impl.client.RedirectLocations
org.apache.http.impl.client.RequestWrapper
org.apache.http.impl.client.RoutedRequest
org.apache.http.impl.client.TunnelRefusedException
@@ -7871,10 +8251,6 @@ org.apache.http.impl.conn.DefaultResponseParser
org.apache.http.impl.conn.IdleConnectionHandler
org.apache.http.impl.conn.IdleConnectionHandler$TimeValues
org.apache.http.impl.conn.ProxySelectorRoutePlanner
-org.apache.http.impl.conn.SingleClientConnManager
-org.apache.http.impl.conn.SingleClientConnManager$1
-org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter
-org.apache.http.impl.conn.SingleClientConnManager$PoolEntry
org.apache.http.impl.conn.tsccm.AbstractConnPool
org.apache.http.impl.conn.tsccm.BasicPoolEntry
org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
@@ -7950,7 +8326,6 @@ org.apache.http.message.BasicHeader
org.apache.http.message.BasicHeaderElement
org.apache.http.message.BasicHeaderElementIterator
org.apache.http.message.BasicHeaderValueParser
-org.apache.http.message.BasicHttpEntityEnclosingRequest
org.apache.http.message.BasicHttpRequest
org.apache.http.message.BasicHttpResponse
org.apache.http.message.BasicLineFormatter
@@ -7959,7 +8334,6 @@ org.apache.http.message.BasicListHeaderIterator
org.apache.http.message.BasicNameValuePair
org.apache.http.message.BasicRequestLine
org.apache.http.message.BasicStatusLine
-org.apache.http.message.BasicTokenIterator
org.apache.http.message.BufferedHeader
org.apache.http.message.HeaderGroup
org.apache.http.message.HeaderValueParser
@@ -8001,7 +8375,6 @@ org.apache.http.util.CharArrayBuffer
org.apache.http.util.EncodingUtils
org.apache.http.util.EntityUtils
org.apache.http.util.LangUtils
-org.apache.http.util.VersionInfo
org.ccil.cowan.tagsoup.AttributesImpl
org.ccil.cowan.tagsoup.AutoDetector
org.ccil.cowan.tagsoup.Element
@@ -8026,16 +8399,12 @@ org.kxml2.io.KXmlParser
org.kxml2.io.KXmlParser$ValueContext
org.kxml2.io.KXmlSerializer
org.w3c.dom.Attr
-org.w3c.dom.CDATASection
org.w3c.dom.CharacterData
-org.w3c.dom.Comment
-org.w3c.dom.DOMException
org.w3c.dom.DOMImplementation
org.w3c.dom.Document
org.w3c.dom.DocumentFragment
org.w3c.dom.DocumentType
org.w3c.dom.Element
-org.w3c.dom.EntityReference
org.w3c.dom.NamedNodeMap
org.w3c.dom.Node
org.w3c.dom.NodeList
@@ -8054,9 +8423,6 @@ org.xml.sax.SAXNotRecognizedException
org.xml.sax.SAXNotSupportedException
org.xml.sax.SAXParseException
org.xml.sax.XMLReader
-org.xml.sax.ext.DeclHandler
-org.xml.sax.ext.DefaultHandler2
-org.xml.sax.ext.EntityResolver2
org.xml.sax.ext.LexicalHandler
org.xml.sax.helpers.AttributesImpl
org.xml.sax.helpers.DefaultHandler
@@ -8064,22 +8430,28 @@ org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserException
org.xmlpull.v1.XmlPullParserFactory
org.xmlpull.v1.XmlSerializer
+sun.invoke.util.BytecodeDescriptor
+sun.invoke.util.Wrapper
sun.misc.ASCIICaseInsensitiveComparator
-sun.misc.BASE64Decoder
-sun.misc.CEStreamExhausted
-sun.misc.CharacterDecoder
sun.misc.Cleaner
sun.misc.CompoundEnumeration
-sun.misc.FDBigInt
+sun.misc.FDBigInteger
+sun.misc.FloatingDecimal
+sun.misc.FloatingDecimal$1
+sun.misc.FloatingDecimal$ASCIIToBinaryBuffer
+sun.misc.FloatingDecimal$ASCIIToBinaryConverter
+sun.misc.FloatingDecimal$BinaryToASCIIBuffer
+sun.misc.FloatingDecimal$BinaryToASCIIConverter
+sun.misc.FloatingDecimal$ExceptionalBinaryToASCIIBuffer
+sun.misc.FloatingDecimal$PreparedASCIIToBinaryBuffer
sun.misc.FormattedFloatingDecimal
sun.misc.FormattedFloatingDecimal$1
sun.misc.FormattedFloatingDecimal$Form
-sun.misc.FpUtils
-sun.misc.Hashing
sun.misc.IOUtils
-sun.misc.IoTrace
+sun.misc.JavaIOFileDescriptorAccess
sun.misc.LRUCache
sun.misc.REException
+sun.misc.SharedSecrets
sun.misc.Unsafe
sun.misc.VM
sun.misc.Version
@@ -8096,17 +8468,13 @@ sun.net.util.IPAddressUtil
sun.net.www.ParseUtil
sun.net.www.protocol.file.Handler
sun.net.www.protocol.jar.Handler
-sun.nio.ch.AbstractPollArrayWrapper
-sun.nio.ch.AbstractPollSelectorImpl
-sun.nio.ch.AllocatedNativeObject
sun.nio.ch.ChannelInputStream
sun.nio.ch.DatagramChannelImpl
sun.nio.ch.DatagramDispatcher
-sun.nio.ch.DefaultSelectorProvider
sun.nio.ch.DirectBuffer
+sun.nio.ch.EPollArrayWrapper
sun.nio.ch.FileChannelImpl
sun.nio.ch.FileChannelImpl$Unmapper
-sun.nio.ch.FileDescriptorHolderSocketImpl
sun.nio.ch.FileDispatcher
sun.nio.ch.FileDispatcherImpl
sun.nio.ch.FileKey
@@ -8114,33 +8482,18 @@ sun.nio.ch.FileLockImpl
sun.nio.ch.FileLockTable
sun.nio.ch.IOStatus
sun.nio.ch.IOUtil
-sun.nio.ch.InheritedChannel
sun.nio.ch.Interruptible
sun.nio.ch.NativeDispatcher
-sun.nio.ch.NativeObject
sun.nio.ch.NativeThread
sun.nio.ch.NativeThreadSet
sun.nio.ch.Net
-sun.nio.ch.Net$1
-sun.nio.ch.PollArrayWrapper
-sun.nio.ch.PollSelectorImpl
-sun.nio.ch.PollSelectorProvider
sun.nio.ch.SelChImpl
-sun.nio.ch.SelectionKeyImpl
-sun.nio.ch.SelectorImpl
-sun.nio.ch.SelectorProviderImpl
sun.nio.ch.ServerSocketChannelImpl
sun.nio.ch.SharedFileLockTable
sun.nio.ch.SharedFileLockTable$FileLockReference
-sun.nio.ch.SocketAdaptor
-sun.nio.ch.SocketAdaptor$1
-sun.nio.ch.SocketAdaptor$2
-sun.nio.ch.SocketAdaptor$SocketInputStream
sun.nio.ch.SocketChannelImpl
-sun.nio.ch.SocketDispatcher
sun.nio.ch.Util
sun.nio.ch.Util$1
-sun.nio.ch.Util$2
sun.nio.ch.Util$BufferCache
sun.nio.cs.ArrayDecoder
sun.nio.cs.ArrayEncoder
@@ -8150,15 +8503,30 @@ sun.nio.cs.ThreadLocalCoders
sun.nio.cs.ThreadLocalCoders$1
sun.nio.cs.ThreadLocalCoders$2
sun.nio.cs.ThreadLocalCoders$Cache
-sun.reflect.annotation.AnnotationType
+sun.nio.fs.AbstractFileSystemProvider
+sun.nio.fs.AbstractPath
+sun.nio.fs.DefaultFileSystemProvider
+sun.nio.fs.LinuxFileSystem
+sun.nio.fs.LinuxFileSystemProvider
+sun.nio.fs.NativeBuffer
+sun.nio.fs.NativeBuffer$Deallocator
+sun.nio.fs.NativeBuffers
+sun.nio.fs.UnixChannelFactory
+sun.nio.fs.UnixChannelFactory$Flags
+sun.nio.fs.UnixConstants
+sun.nio.fs.UnixException
+sun.nio.fs.UnixFileAttributes
+sun.nio.fs.UnixFileModeAttribute
+sun.nio.fs.UnixFileStoreAttributes
+sun.nio.fs.UnixFileSystem
+sun.nio.fs.UnixFileSystemProvider
+sun.nio.fs.UnixMountEntry
+sun.nio.fs.UnixNativeDispatcher
+sun.nio.fs.UnixPath
+sun.nio.fs.Util
sun.reflect.misc.ReflectUtil
sun.security.action.GetBooleanAction
sun.security.action.GetPropertyAction
-sun.security.ec.ECKeyFactory
-sun.security.ec.ECKeyFactory$1
-sun.security.ec.ECKeyFactory$2
-sun.security.ec.ECParameters
-sun.security.ec.NamedCurve
sun.security.jca.GetInstance
sun.security.jca.GetInstance$Instance
sun.security.jca.JCAUtil
@@ -8174,8 +8542,9 @@ sun.security.jca.Providers
sun.security.jca.ServiceId
sun.security.pkcs.ContentInfo
sun.security.pkcs.PKCS7
+sun.security.pkcs.PKCS7$VerbatimX509Certificate
+sun.security.pkcs.PKCS7$WrappedX509Certificate
sun.security.pkcs.PKCS9Attribute
-sun.security.pkcs.ParsingException
sun.security.pkcs.SignerInfo
sun.security.provider.CertPathProvider
sun.security.provider.X509Factory
@@ -8191,7 +8560,9 @@ sun.security.provider.certpath.PKIXCertPathValidator
sun.security.provider.certpath.PKIXMasterCertPathValidator
sun.security.provider.certpath.PolicyChecker
sun.security.provider.certpath.PolicyNodeImpl
-sun.security.provider.certpath.UntrustedChecker
+sun.security.util.-$Lambda$179$Kli5xKA4dAwmFO1sy_hpNWmbfH4
+sun.security.util.AbstractAlgorithmConstraints
+sun.security.util.AlgorithmDecomposer
sun.security.util.BitArray
sun.security.util.ByteArrayLexOrder
sun.security.util.ByteArrayTagOrder
@@ -8205,7 +8576,6 @@ sun.security.util.DerInputStream
sun.security.util.DerOutputStream
sun.security.util.DerValue
sun.security.util.DisabledAlgorithmConstraints
-sun.security.util.DisabledAlgorithmConstraints$1
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint$Operator
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraints
@@ -8220,9 +8590,7 @@ sun.security.util.MemoryCache
sun.security.util.MemoryCache$CacheEntry
sun.security.util.MemoryCache$SoftCacheEntry
sun.security.util.ObjectIdentifier
-sun.security.util.SecurityConstants
sun.security.util.SignatureFileVerifier
-sun.security.util.UntrustedCertificates
sun.security.x509.AVA
sun.security.x509.AVAKeyword
sun.security.x509.AccessDescription
@@ -8279,25 +8647,19 @@ sun.security.x509.X509AttributeName
sun.security.x509.X509CertImpl
sun.security.x509.X509CertInfo
sun.security.x509.X509Key
-sun.util.LocaleServiceProviderPool
-sun.util.LocaleServiceProviderPool$1
sun.util.calendar.AbstractCalendar
sun.util.calendar.BaseCalendar
sun.util.calendar.BaseCalendar$Date
sun.util.calendar.CalendarDate
sun.util.calendar.CalendarSystem
sun.util.calendar.CalendarUtils
-sun.util.calendar.Era
sun.util.calendar.Gregorian
sun.util.calendar.Gregorian$Date
-sun.util.calendar.ImmutableGregorianDate
sun.util.calendar.JulianCalendar
-sun.util.calendar.JulianCalendar$Date
sun.util.calendar.LocalGregorianCalendar
sun.util.locale.BaseLocale
sun.util.locale.BaseLocale$Cache
sun.util.locale.BaseLocale$Key
-sun.util.locale.Extension
sun.util.locale.InternalLocaleBuilder
sun.util.locale.InternalLocaleBuilder$CaseInsensitiveChar
sun.util.locale.LanguageTag
@@ -8308,11 +8670,9 @@ sun.util.locale.LocaleSyntaxException
sun.util.locale.LocaleUtils
sun.util.locale.ParseStatus
sun.util.locale.StringTokenIterator
-sun.util.locale.UnicodeLocaleExtension
sun.util.logging.LoggingProxy
sun.util.logging.LoggingSupport
sun.util.logging.LoggingSupport$1
-sun.util.logging.LoggingSupport$2
sun.util.logging.PlatformLogger
sun.util.logging.PlatformLogger$1
sun.util.logging.PlatformLogger$JavaLoggerProxy
diff --git a/core/java/android/accessibilityservice/AccessibilityButtonController.java b/core/java/android/accessibilityservice/AccessibilityButtonController.java
new file mode 100644
index 000000000000..c3a5daba4cfc
--- /dev/null
+++ b/core/java/android/accessibilityservice/AccessibilityButtonController.java
@@ -0,0 +1,223 @@
+/*
+ * 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.accessibilityservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+/**
+ * Controller for the accessibility button within the system's navigation area
+ * <p>
+ * This class may be used to query the accessibility button's state and register
+ * callbacks for interactions with and state changes to the accessibility button when
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class and
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} should not be used as
+ * the sole means for offering functionality to users via an {@link AccessibilityService}.
+ * Some device implementations may choose not to provide a software-rendered system
+ * navigation area, making this affordance permanently unavailable.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> On device implementations where the accessibility button is
+ * supported, it may not be available at all times, such as when a foreground application uses
+ * {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. A user may also choose to assign
+ * this button to another accessibility service or feature. In each of these cases, a
+ * registered {@link AccessibilityButtonCallback}'s
+ * {@link AccessibilityButtonCallback#onAvailabilityChanged(AccessibilityButtonController, boolean)}
+ * method will be invoked to provide notifications of changes in the accessibility button's
+ * availability to the registering service.
+ * </p>
+ */
+public final class AccessibilityButtonController {
+ private static final String LOG_TAG = "A11yButtonController";
+
+ private final IAccessibilityServiceConnection mServiceConnection;
+ private final Object mLock;
+ private ArrayMap<AccessibilityButtonCallback, Handler> mCallbacks;
+
+ AccessibilityButtonController(@NonNull IAccessibilityServiceConnection serviceConnection) {
+ mServiceConnection = serviceConnection;
+ mLock = new Object();
+ }
+
+ /**
+ * Retrieves whether the accessibility button in the system's navigation area is
+ * available to the calling service.
+ * <p>
+ * <strong>Note:</strong> If the service is not yet connected (e.g.
+ * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+ * service has been disconnected, this method will have no effect and return {@code false}.
+ * </p>
+ *
+ * @return {@code true} if the accessibility button in the system's navigation area is
+ * available to the calling service, {@code false} otherwise
+ */
+ public boolean isAccessibilityButtonAvailable() {
+ try {
+ return mServiceConnection.isAccessibilityButtonAvailable();
+ } catch (RemoteException re) {
+ Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
+ re.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
+ /**
+ * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
+ * changes callbacks related to the accessibility button.
+ *
+ * @param callback the callback to add, must be non-null
+ */
+ public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback) {
+ registerAccessibilityButtonCallback(callback, null);
+ }
+
+ /**
+ * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
+ * change callbacks related to the accessibility button. The callback will occur on the
+ * specified {@link Handler}'s thread, or on the services's main thread if the handler is
+ * {@code null}.
+ *
+ * @param callback the callback to add, must be non-null
+ * @param handler the handler on which to callback should execute, or {@code null} to
+ * execute on the service's main thread
+ */
+ public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback,
+ @Nullable Handler handler) {
+ synchronized (mLock) {
+ if (mCallbacks == null) {
+ mCallbacks = new ArrayMap<>();
+ }
+
+ mCallbacks.put(callback, handler);
+ }
+ }
+
+ /**
+ * Unregisters the provided {@link AccessibilityButtonCallback} for interaction and state
+ * change callbacks related to the accessibility button.
+ *
+ * @param callback the callback to remove, must be non-null
+ */
+ public void unregisterAccessibilityButtonCallback(
+ @NonNull AccessibilityButtonCallback callback) {
+ synchronized (mLock) {
+ if (mCallbacks == null) {
+ return;
+ }
+
+ final int keyIndex = mCallbacks.indexOfKey(callback);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mCallbacks.removeAt(keyIndex);
+ }
+ }
+ }
+
+ /**
+ * Dispatches the accessibility button click to any registered callbacks. This should
+ * be called on the service's main thread.
+ */
+ void dispatchAccessibilityButtonClicked() {
+ final ArrayMap<AccessibilityButtonCallback, Handler> entries;
+ synchronized (mLock) {
+ if (mCallbacks == null || mCallbacks.isEmpty()) {
+ Slog.w(LOG_TAG, "Received accessibility button click with no callbacks!");
+ return;
+ }
+
+ // Callbacks may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mCallbacks);
+ }
+
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final AccessibilityButtonCallback callback = entries.keyAt(i);
+ final Handler handler = entries.valueAt(i);
+ if (handler != null) {
+ handler.post(() -> callback.onClicked(this));
+ } else {
+ // We're already on the main thread, just run the callback.
+ callback.onClicked(this);
+ }
+ }
+ }
+
+ /**
+ * Dispatches the accessibility button availability changes to any registered callbacks.
+ * This should be called on the service's main thread.
+ */
+ void dispatchAccessibilityButtonAvailabilityChanged(boolean available) {
+ final ArrayMap<AccessibilityButtonCallback, Handler> entries;
+ synchronized (mLock) {
+ if (mCallbacks == null || mCallbacks.isEmpty()) {
+ Slog.w(LOG_TAG,
+ "Received accessibility button availability change with no callbacks!");
+ return;
+ }
+
+ // Callbacks may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mCallbacks);
+ }
+
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final AccessibilityButtonCallback callback = entries.keyAt(i);
+ final Handler handler = entries.valueAt(i);
+ if (handler != null) {
+ handler.post(() -> callback.onAvailabilityChanged(this, available));
+ } else {
+ // We're already on the main thread, just run the callback.
+ callback.onAvailabilityChanged(this, available);
+ }
+ }
+ }
+
+ /**
+ * Callback for interaction with and changes to state of the accessibility button
+ * within the system's navigation area.
+ */
+ public static abstract class AccessibilityButtonCallback {
+
+ /**
+ * Called when the accessibility button in the system's navigation area is clicked.
+ *
+ * @param controller the controller used to register for this callback
+ */
+ public void onClicked(AccessibilityButtonController controller) {}
+
+ /**
+ * Called when the availability of the accessibility button in the system's
+ * navigation area has changed. The accessibility button may become unavailable
+ * because the device shopped showing the button, the button was assigned to another
+ * service, or for other reasons.
+ *
+ * @param controller the controller used to register for this callback
+ * @param available {@code true} if the accessibility button is available to this
+ * service, {@code false} otherwise
+ */
+ public void onAvailabilityChanged(AccessibilityButtonController controller,
+ boolean available) {
+ }
+ }
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3e5cc54c9fe7..9e486d544195 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -20,11 +20,13 @@ import android.accessibilityservice.GestureDescription.MotionEventGenerator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.Region;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -33,11 +35,9 @@ import android.os.RemoteException;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityEvent;
@@ -362,19 +362,24 @@ public abstract class AccessibilityService extends Service {
private static final String LOG_TAG = "AccessibilityService";
/**
+ * Interface used by IAccessibilityServiceWrapper to call the service from its main thread.
* @hide
*/
public interface Callbacks {
- public void onAccessibilityEvent(AccessibilityEvent event);
- public void onInterrupt();
- public void onServiceConnected();
- public void init(int connectionId, IBinder windowToken);
- public boolean onGesture(int gestureId);
- public boolean onKeyEvent(KeyEvent event);
- public void onMagnificationChanged(@NonNull Region region,
+ void onAccessibilityEvent(AccessibilityEvent event);
+ void onInterrupt();
+ void onServiceConnected();
+ void init(int connectionId, IBinder windowToken);
+ boolean onGesture(int gestureId);
+ boolean onKeyEvent(KeyEvent event);
+ void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY);
- public void onSoftKeyboardShowModeChanged(int showMode);
- public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+ void onSoftKeyboardShowModeChanged(int showMode);
+ void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+ void onFingerprintCapturingGesturesChanged(boolean active);
+ void onFingerprintGesture(int gesture);
+ void onAccessibilityButtonClicked();
+ void onAccessibilityButtonAvailabilityChanged(boolean available);
}
/**
@@ -397,6 +402,7 @@ public abstract class AccessibilityService extends Service {
private MagnificationController mMagnificationController;
private SoftKeyboardController mSoftKeyboardController;
+ private AccessibilityButtonController mAccessibilityButtonController;
private int mGestureStatusCallbackSequence;
@@ -404,6 +410,8 @@ public abstract class AccessibilityService extends Service {
private final Object mLock = new Object();
+ private FingerprintGestureController mFingerprintGestureController;
+
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
*
@@ -426,6 +434,9 @@ public abstract class AccessibilityService extends Service {
if (mMagnificationController != null) {
mMagnificationController.onServiceConnected();
}
+ if (mSoftKeyboardController != null) {
+ mSoftKeyboardController.onServiceConnected();
+ }
// The client gets to handle service connection last, after we've set
// up any state upon which their code may rely.
@@ -598,6 +609,32 @@ public abstract class AccessibilityService extends Service {
}
/**
+ * Get the controller for fingerprint gestures. This feature requires {@link
+ * AccessibilityServiceInfo#CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES}.
+ *
+ *<strong>Note: </strong> The service must be connected before this method is called.
+ *
+ * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable.
+ */
+ @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
+ public final @Nullable FingerprintGestureController getFingerprintGestureController() {
+ if (mFingerprintGestureController == null) {
+ FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
+ if ((fingerprintManager != null) && fingerprintManager.isHardwareDetected()) {
+ AccessibilityServiceInfo info = getServiceInfo();
+ int fingerprintCapabilityMask =
+ AccessibilityServiceInfo.CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
+ if ((info.getCapabilities() & fingerprintCapabilityMask) != 0) {
+ mFingerprintGestureController = new FingerprintGestureController(
+ AccessibilityInteractionClient.getInstance()
+ .getConnection(mConnectionId));
+ }
+ }
+ }
+ return mFingerprintGestureController;
+ }
+
+ /**
* Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
* the user, this service, or another service, will be cancelled.
* <p>
@@ -694,6 +731,22 @@ public abstract class AccessibilityService extends Service {
}
/**
+ * Callback for fingerprint gesture handling
+ * @param active If gesture detection is active
+ */
+ private void onFingerprintCapturingGesturesChanged(boolean active) {
+ getFingerprintGestureController().onGestureDetectionActiveChanged(active);
+ }
+
+ /**
+ * Callback for fingerprint gesture handling
+ * @param gesture The identifier for the gesture performed
+ */
+ private void onFingerprintGesture(int gesture) {
+ getFingerprintGestureController().onGesture(gesture);
+ }
+
+ /**
* Used to control and query the state of display magnification.
*/
public static final class MagnificationController {
@@ -762,12 +815,10 @@ public abstract class AccessibilityService extends Service {
}
/**
- * Removes all instances of the specified change listener from the list
- * of magnification change listeners.
+ * Removes the specified change listener from the list of magnification change listeners.
*
* @param listener the listener to remove, must be non-null
- * @return {@code true} if at least one instance of the listener was
- * removed
+ * @return {@code true} if the listener was removed, {@code false} otherwise
*/
public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
if (mListeners == null) {
@@ -1156,11 +1207,11 @@ public abstract class AccessibilityService extends Service {
}
/**
- * Removes all instances of the specified change listener from the list of magnification
- * change listeners.
+ * Removes the specified change listener from the list of keyboard show mode change
+ * listeners.
*
* @param listener the listener to remove, must be non-null
- * @return {@code true} if at least one instance of the listener was removed
+ * @return {@code true} if the listener was removed, {@code false} otherwise
*/
public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
if (mListeners == null) {
@@ -1205,7 +1256,7 @@ public abstract class AccessibilityService extends Service {
final ArrayMap<OnShowModeChangedListener, Handler> entries;
synchronized (mLock) {
if (mListeners == null || mListeners.isEmpty()) {
- Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+ Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
+ " with no listeners registered!");
setSoftKeyboardCallbackEnabled(false);
return;
@@ -1261,9 +1312,9 @@ public abstract class AccessibilityService extends Service {
* The lastto this method will be honored, regardless of any previous calls (including those
* made by other AccessibilityServices).
* <p>
- * <strong>Note:</strong> If the service is not yet conected (e.g.
+ * <strong>Note:</strong> If the service is not yet connected (e.g.
* {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
- * service has been disconnected, this method will hav no effect and return {@code false}.
+ * service has been disconnected, this method will have no effect and return {@code false}.
*
* @param showMode the new show mode for the soft keyboard
* @return {@code true} on success
@@ -1302,6 +1353,39 @@ public abstract class AccessibilityService extends Service {
}
/**
+ * Returns the controller for the accessibility button within the system's navigation area.
+ * This instance may be used to query the accessibility button's state and register listeners
+ * for interactions with and state changes for the accessibility button when
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
+ * <p>
+ * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
+ * within a navigation area, and as such, use of this class should be considered only as an
+ * optional feature or shortcut on supported device implementations.
+ * </p>
+ *
+ * @return the accessibility button controller for this {@link AccessibilityService}
+ */
+ @NonNull
+ public final AccessibilityButtonController getAccessibilityButtonController() {
+ synchronized (mLock) {
+ if (mAccessibilityButtonController == null) {
+ mAccessibilityButtonController = new AccessibilityButtonController(
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
+ }
+ return mAccessibilityButtonController;
+ }
+ }
+
+ private void onAccessibilityButtonClicked() {
+ getAccessibilityButtonController().dispatchAccessibilityButtonClicked();
+ }
+
+ private void onAccessibilityButtonAvailabilityChanged(boolean available) {
+ getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
+ available);
+ }
+
+ /**
* Performs a global action. Such an action can be performed
* at any moment regardless of the current application or user
* location in that application. For example going back, going
@@ -1486,6 +1570,26 @@ public abstract class AccessibilityService extends Service {
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
}
+
+ @Override
+ public void onFingerprintCapturingGesturesChanged(boolean active) {
+ AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
+ }
+
+ @Override
+ public void onFingerprintGesture(int gesture) {
+ AccessibilityService.this.onFingerprintGesture(gesture);
+ }
+
+ @Override
+ public void onAccessibilityButtonClicked() {
+ AccessibilityService.this.onAccessibilityButtonClicked();
+ }
+
+ @Override
+ public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+ AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
+ }
});
}
@@ -1506,6 +1610,10 @@ public abstract class AccessibilityService extends Service {
private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
private static final int DO_GESTURE_COMPLETE = 9;
+ private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
+ private static final int DO_ON_FINGERPRINT_GESTURE = 11;
+ private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
+ private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
private final HandlerCaller mCaller;
@@ -1577,6 +1685,26 @@ public abstract class AccessibilityService extends Service {
mCaller.sendMessage(message);
}
+ public void onFingerprintCapturingGesturesChanged(boolean active) {
+ mCaller.sendMessage(mCaller.obtainMessageI(
+ DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
+ }
+
+ public void onFingerprintGesture(int gesture) {
+ mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
+ }
+
+ public void onAccessibilityButtonClicked() {
+ final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED);
+ mCaller.sendMessage(message);
+ }
+
+ public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+ final Message message = mCaller.obtainMessageI(
+ DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
+ mCaller.sendMessage(message);
+ }
+
@Override
public void executeMessage(Message message) {
switch (message.what) {
@@ -1675,6 +1803,21 @@ public abstract class AccessibilityService extends Service {
final boolean successfully = message.arg2 == 1;
mCallback.onPerformGestureResult(message.arg1, successfully);
} return;
+ case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
+ mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
+ } return;
+ case DO_ON_FINGERPRINT_GESTURE: {
+ mCallback.onFingerprintGesture(message.arg1);
+ } return;
+
+ case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
+ mCallback.onAccessibilityButtonClicked();
+ } return;
+
+ case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
+ final boolean available = (message.arg1 != 0);
+ mCallback.onAccessibilityButtonAvailabilityChanged(available);
+ } return;
default :
Log.w(LOG_TAG, "Unknown message type " + message.what);
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index b76aeb71101a..e135ffdf9b13 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -25,6 +25,7 @@ import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -116,34 +117,13 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
- private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
- new SparseArray<CapabilityInfo>();
- static {
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
- new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
- R.string.capability_title_canRetrieveWindowContent,
- R.string.capability_desc_canRetrieveWindowContent));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
- new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
- R.string.capability_title_canRequestTouchExploration,
- R.string.capability_desc_canRequestTouchExploration));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- R.string.capability_title_canRequestEnhancedWebAccessibility,
- R.string.capability_desc_canRequestEnhancedWebAccessibility));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
- new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
- R.string.capability_title_canRequestFilterKeyEvents,
- R.string.capability_desc_canRequestFilterKeyEvents));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
- new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
- R.string.capability_title_canControlMagnification,
- R.string.capability_desc_canControlMagnification));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
- new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
- R.string.capability_title_canPerformGestures,
- R.string.capability_desc_canPerformGestures));
- }
+ /**
+ * Capability: This accessibility service can capture gestures from the fingerprint sensor
+ * @see android.R.styleable#AccessibilityService_canCaptureFingerprintGestures
+ */
+ public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 0x00000040;
+
+ private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos;
/**
* Denotes spoken feedback.
@@ -326,6 +306,18 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
+ /**
+ * This flag indicates to the system that the accessibility service requests that an
+ * accessibility button be shown within the system's navigation area, if available.
+ */
+ public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100;
+
+ /**
+ * This flag requests that all fingerprint gestures be sent to the accessibility service.
+ * It is handled in {@link FingerprintGestureController}
+ */
+ public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 0x00000200;
+
/** {@hide} */
public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
@@ -410,6 +402,8 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see #FLAG_REQUEST_FILTER_KEY_EVENTS
* @see #FLAG_REPORT_VIEW_IDS
* @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
+ * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
+ * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
*/
public int flags;
@@ -535,6 +529,10 @@ public class AccessibilityServiceInfo implements Parcelable {
.AccessibilityService_canPerformGestures, false)) {
mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
}
+ if (asAttributes.getBoolean(com.android.internal.R.styleable
+ .AccessibilityService_canCaptureFingerprintGestures, false)) {
+ mCapabilities |= CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
+ }
TypedValue peekedValue = asAttributes.peekValue(
com.android.internal.R.styleable.AccessibilityService_description);
if (peekedValue != null) {
@@ -641,7 +639,7 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
* @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
* @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
- * @see #CAPABILITY_FILTER_KEY_EVENTS
+ * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
* @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
* @see #CAPABILITY_CAN_PERFORM_GESTURES
*/
@@ -658,7 +656,7 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
* @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
* @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
- * @see #CAPABILITY_FILTER_KEY_EVENTS
+ * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
* @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
* @see #CAPABILITY_CAN_PERFORM_GESTURES
*
@@ -946,6 +944,10 @@ public class AccessibilityServiceInfo implements Parcelable {
return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
+ case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
+ return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
+ case FLAG_CAPTURE_FINGERPRINT_GESTURES:
+ return "FLAG_CAPTURE_FINGERPRINT_GESTURES";
default:
return null;
}
@@ -968,11 +970,13 @@ public class AccessibilityServiceInfo implements Parcelable {
case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
- return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
+ return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
case CAPABILITY_CAN_PERFORM_GESTURES:
return "CAPABILITY_CAN_PERFORM_GESTURES";
+ case CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES:
+ return "CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES";
default:
return "UNKNOWN";
}
@@ -981,17 +985,29 @@ public class AccessibilityServiceInfo implements Parcelable {
/**
* @hide
* @return The list of {@link CapabilityInfo} objects.
+ * @deprecated The version that takes a context works better.
*/
public List<CapabilityInfo> getCapabilityInfos() {
+ return getCapabilityInfos(null);
+ }
+
+ /**
+ * @hide
+ * @param context A valid context
+ * @return The list of {@link CapabilityInfo} objects.
+ */
+ public List<CapabilityInfo> getCapabilityInfos(Context context) {
if (mCapabilities == 0) {
return Collections.emptyList();
}
int capabilities = mCapabilities;
List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
+ SparseArray<CapabilityInfo> capabilityInfoSparseArray =
+ getCapabilityInfoSparseArray(context);
while (capabilities != 0) {
final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
capabilities &= ~capabilityBit;
- CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
+ CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
if (capabilityInfo != null) {
capabilityInfos.add(capabilityInfo);
}
@@ -999,6 +1015,44 @@ public class AccessibilityServiceInfo implements Parcelable {
return capabilityInfos;
}
+ private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
+ if (sAvailableCapabilityInfos == null) {
+ sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+ new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+ R.string.capability_title_canRetrieveWindowContent,
+ R.string.capability_desc_canRetrieveWindowContent));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+ R.string.capability_title_canRequestTouchExploration,
+ R.string.capability_desc_canRequestTouchExploration));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+ R.string.capability_title_canRequestEnhancedWebAccessibility,
+ R.string.capability_desc_canRequestEnhancedWebAccessibility));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+ R.string.capability_title_canRequestFilterKeyEvents,
+ R.string.capability_desc_canRequestFilterKeyEvents));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
+ new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
+ R.string.capability_title_canControlMagnification,
+ R.string.capability_desc_canControlMagnification));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
+ new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
+ R.string.capability_title_canPerformGestures,
+ R.string.capability_desc_canPerformGestures));
+ if ((context == null)
+ || context.getSystemService(FingerprintManager.class).isHardwareDetected()) {
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
+ new CapabilityInfo(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
+ R.string.capability_title_canCaptureFingerprintGestures,
+ R.string.capability_desc_canCaptureFingerprintGestures));
+ }
+ }
+ return sAvailableCapabilityInfos;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/accessibilityservice/FingerprintGestureController.java b/core/java/android/accessibilityservice/FingerprintGestureController.java
new file mode 100644
index 000000000000..e203c6de8fb5
--- /dev/null
+++ b/core/java/android/accessibilityservice/FingerprintGestureController.java
@@ -0,0 +1,185 @@
+/*
+ * 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.accessibilityservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * An {@link AccessibilityService} can capture gestures performed on a device's fingerprint
+ * sensor, as long as the device has a sensor capable of detecting gestures.
+ * <p>
+ * This capability must be declared by the service as
+ * {@link AccessibilityServiceInfo#CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES}. It also requires
+ * the permission {@link android.Manifest.permission#USE_FINGERPRINT}.
+ * <p>
+ * Because capturing fingerprint gestures may have side effects, services with the capability only
+ * capture gestures when {@link AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} is set.
+ * <p>
+ * <strong>Note: </strong>The fingerprint sensor is used for authentication in critical use cases,
+ * so services must carefully design their user's experience when performing gestures on the sensor.
+ * When the sensor is in use by an app, for example, when authenticating or enrolling a user,
+ * the sensor will not detect gestures. Services need to ensure that users understand when the
+ * sensor is in-use for authentication to prevent users from authenticating unintentionally when
+ * trying to interact with the service. They can use
+ * {@link FingerprintGestureCallback#onGestureDetectionAvailabilityChanged(boolean)} to learn when
+ * gesture detection becomes unavailable.
+ * <p>
+ * Multiple accessibility services may listen for fingerprint gestures simultaneously, so services
+ * should provide a way for the user to disable the use of this feature so multiple services don't
+ * conflict with each other.
+ * <p>
+ * {@see android.hardware.fingerprint.FingerprintManager#isHardwareDetected}
+ */
+public final class FingerprintGestureController {
+ /** Identifier for a swipe right on the fingerprint sensor */
+ public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 0x00000001;
+
+ /** Identifier for a swipe left on the fingerprint sensor */
+ public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 0x00000002;
+
+ /** Identifier for a swipe up on the fingerprint sensor */
+ public static final int FINGERPRINT_GESTURE_SWIPE_UP = 0x00000004;
+
+ /** Identifier for a swipe down on the fingerprint sensor */
+ public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 0x00000008;
+
+ private static final String LOG_TAG = "FingerprintGestureController";
+ private final Object mLock = new Object();
+ private final IAccessibilityServiceConnection mAccessibilityServiceConnection;
+
+ private final ArrayMap<FingerprintGestureCallback, Handler> mCallbackHandlerMap =
+ new ArrayMap<>(1);
+
+ /**
+ * @param connection The connection to use for system interactions
+ * @hide
+ */
+ @VisibleForTesting
+ public FingerprintGestureController(IAccessibilityServiceConnection connection) {
+ mAccessibilityServiceConnection = connection;
+ }
+
+ /**
+ * Gets if the fingerprint sensor's gesture detection is available.
+ *
+ * @return {@code true} if the sensor's gesture detection is available. {@code false} if it is
+ * not currently detecting gestures (for example, if it is enrolling a finger).
+ */
+ public boolean isGestureDetectionAvailable() {
+ try {
+ return mAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable();
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Failed to check if fingerprint gestures are active", re);
+ re.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
+ /**
+ * Register a callback to be informed of fingerprint sensor gesture events.
+ *
+ * @param callback The listener to be added.
+ * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
+ * on the service's main thread.
+ */
+ public void registerFingerprintGestureCallback(
+ @NonNull FingerprintGestureCallback callback, @Nullable Handler handler) {
+ synchronized (mLock) {
+ mCallbackHandlerMap.put(callback, handler);
+ }
+ }
+
+ /**
+ * Unregister a listener added with {@link #registerFingerprintGestureCallback}.
+ *
+ * @param callback The callback to remove. Removing a callback that was never added has no
+ * effect.
+ */
+ public void unregisterFingerprintGestureCallback(FingerprintGestureCallback callback) {
+ synchronized (mLock) {
+ mCallbackHandlerMap.remove(callback);
+ }
+ }
+
+ /**
+ * Called when gesture detection becomes active or inactive
+ * @hide
+ */
+ public void onGestureDetectionActiveChanged(boolean active) {
+ final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
+ synchronized (mLock) {
+ handlerMap = new ArrayMap<>(mCallbackHandlerMap);
+ }
+ int numListeners = handlerMap.size();
+ for (int i = 0; i < numListeners; i++) {
+ FingerprintGestureCallback callback = handlerMap.keyAt(i);
+ Handler handler = handlerMap.valueAt(i);
+ if (handler != null) {
+ handler.post(() -> callback.onGestureDetectionAvailabilityChanged(active));
+ } else {
+ callback.onGestureDetectionAvailabilityChanged(active);
+ }
+ }
+ }
+
+ /**
+ * Called when gesture is detected.
+ * @hide
+ */
+ public void onGesture(int gesture) {
+ final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
+ synchronized (mLock) {
+ handlerMap = new ArrayMap<>(mCallbackHandlerMap);
+ }
+ int numListeners = handlerMap.size();
+ for (int i = 0; i < numListeners; i++) {
+ FingerprintGestureCallback callback = handlerMap.keyAt(i);
+ Handler handler = handlerMap.valueAt(i);
+ if (handler != null) {
+ handler.post(() -> callback.onGesture(gesture));
+ } else {
+ callback.onGesture(gesture);
+ }
+ }
+ }
+
+ /**
+ * Class that is called back when fingerprint gestures are being used for accessibility.
+ */
+ public abstract static class FingerprintGestureCallback {
+ /**
+ * Called when the fingerprint sensor's gesture detection becomes available or unavailable.
+ *
+ * @param available Whether or not the sensor's gesture detection is now available.
+ */
+ public void onGestureDetectionAvailabilityChanged(boolean available) {}
+
+ /**
+ * Called when the fingerprint sensor detects gestures.
+ *
+ * @param gesture The id of the gesture that was detected. For example,
+ * {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
+ */
+ public void onGesture(int gesture) {}
+ }
+}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index da16a65558a7..4e96b8f11628 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -46,4 +46,12 @@ import android.view.KeyEvent;
void onSoftKeyboardShowModeChanged(int showMode);
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+
+ void onFingerprintCapturingGesturesChanged(boolean capturing);
+
+ void onFingerprintGesture(int gesture);
+
+ void onAccessibilityButtonClicked();
+
+ void onAccessibilityButtonAvailabilityChanged(boolean available);
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 81cddbac3f53..7a1931718888 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -37,7 +37,8 @@ interface IAccessibilityServiceConnection {
boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, long threadId);
+ IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
+ in Bundle arguments);
boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
@@ -88,5 +89,9 @@ interface IAccessibilityServiceConnection {
void setSoftKeyboardCallbackEnabled(boolean enabled);
+ boolean isAccessibilityButtonAvailable();
+
void sendGesture(int sequence, in ParceledListSlice gestureSteps);
+
+ boolean isFingerprintGestureDetectionAvailable();
}
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index c9e09e4e9485..87e512c31bfa 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -707,7 +707,7 @@ public abstract class AbstractAccountAuthenticator {
* @param account the account to clone, will never be null
* @return a Bundle result or null if the result is to be returned via the response.
* @throws NetworkErrorException
- * @see {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}
+ * @see #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)
*/
public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
final Account account) throws NetworkErrorException {
@@ -732,7 +732,7 @@ public abstract class AbstractAccountAuthenticator {
* provided by {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}.
* @return a Bundle result or null if the result is to be returned via the response.
* @throws NetworkErrorException
- * @see {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}
+ * @see #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)
*/
public Bundle addAccountFromCredentials(final AccountAuthenticatorResponse response,
Account account,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index b27fa242e935..02636819781a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -53,9 +53,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.SuppressWarnings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@@ -335,21 +338,24 @@ public class AccountManager {
"android.accounts.LOGIN_ACCOUNTS_CHANGED";
/**
- * Uid key to set default visibility for applications targeting API level
+ * Key to set default visibility for applications targeting API level
* {@link android.os.Build.VERSION_CODES#O} or above and don't have the same signature as
* authenticator See {@link #getAccountVisibility}. If the value was not set by authenticator
- * USER_MANAGED_NOT_VISIBLE is used.
+ * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
*/
- public static final int UID_KEY_DEFAULT_VISIBILITY = -2;
+ public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
+ "android.accounts.key_legacy_visible";
/**
- * Uid key to set visibility for applications targeting API level below
- * {@link android.os.Build.VERSION_CODES#O} with GET_ACCOUNS permission, or applications with
- * any targeting API level with the same signature as authenticator. See
- * {@link #getAccountVisibility}. If the value was not set by authenticator USER_MANAGED_VISIBLE
- * is used.
+ * Key to set visibility for applications targeting API level below
+ * {@link android.os.Build.VERSION_CODES#O} with
+ * {@link android.Manifest.permission#GET_ACCOUNTS} permission, or applications with any
+ * targeting API level with the same signature as authenticator. See
+ * {@link #getAccountVisibility}. If the value was not set by authenticator
+ * {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used.
*/
- public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3;
+ public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE =
+ "android.accounts.key_legacy_not_visible";
/**
* @hide
@@ -562,12 +568,14 @@ public class AccountManager {
}
/**
- * Returns the accounts visible to the specified package, in an environment where some apps
- * are not authorized to view all accounts. This method can only be called by system apps.
+ * Returns the accounts visible to the specified package, in an environment where some apps are
+ * not authorized to view all accounts. This method can only be called by system apps and
+ * authenticators managing the type
+ *
* @param type The type of accounts to return, null to retrieve all accounts
* @param packageName The package name of the app for which the accounts are to be returned
- * @return An array of {@link Account}, one per matching account. Empty
- * (never null) if no accounts of the specified type have been added.
+ * @return An array of {@link Account}, one per matching account. Empty (never null) if no
+ * accounts of the specified type have been added.
*/
@NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -606,7 +614,8 @@ public class AccountManager {
*
* <p>
* <b>NOTE:</b> If targeting your app to work on API level
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before,
+ * {@link android.Manifest.permission#GET_ACCOUNTS} permission is
* needed for those platforms, irrespective of uid or signature match. See docs for this
* function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
*
@@ -747,7 +756,8 @@ public class AccountManager {
* accounts managed by AbstractAccountAuthenticators whose signature matches the client.
* <p>
* <b>NOTE:</b> If targeting your app to work on API level
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before,
+ * {@link android.Manifest.permission#GET_ACCOUNTS} permission is
* needed for those platforms, irrespective of uid or signature match. See docs for this
* function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
*
@@ -819,9 +829,8 @@ public class AccountManager {
}
/**
- * Adds an account directly to the AccountManager. Additionally this makes the Account visible
- * to desired UIDs of applications on the device, and sends directed broadcasts to these
- * individual applications.
+ * Adds an account directly to the AccountManager. Additionally it specifies Account visiblity
+ * for given list of packages.
* <p>
* Normally used by sign-up wizards associated with authenticators, not directly by
* applications.
@@ -838,14 +847,14 @@ public class AccountManager {
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
* @param extras String values to use for the account's userdata, null for none
- * @param visibility Map from uid to visibility values which will be set before account is
- * added. See getAccountVisibility for possilbe values.
+ * @param visibility Map from packageName to visibility values which will be set before account
+ * is added. See {@link #getAccountVisibility} for possible values.
*
* @return True if the account was successfully added, false if the account already exists, the
* account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle extras,
- Map<Integer, Integer> visibility) {
+ Map<String, Integer> visibility) {
if (account == null)
throw new IllegalArgumentException("account is null");
try {
@@ -857,18 +866,26 @@ public class AccountManager {
}
/**
- * Returns UIDs of applications for which visibility of given account was explicitly set.
+ * Returns package names and visibility which were explicitly set for given account.
* <p>
* This method requires the caller to have a signature match with the authenticator that owns
* the specified account.
*
* @param account The account for which visibility data should be returned.
*
- * @return Map from uid to visibility for given account
+ * @return Map from package names to visibility for given account.
*/
- public Map<Integer, Integer> getUidsAndVisibilityForAccount(Account account) {
- // TODO implement.
- return null;
+ public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
+ try {
+ if (account == null)
+ throw new IllegalArgumentException("account is null");
+ @SuppressWarnings("unchecked")
+ Map<String, Integer> result = (Map<String, Integer>) mService
+ .getPackagesAndVisibilityForAccount(account);
+ return result;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
@@ -898,30 +915,34 @@ public class AccountManager {
}
/**
- * Set visibility value of given account to certain UID.
+ * Set visibility value of given account to certain packageName.
+ * Package name must match installed application, or be equal to
+ * {@link #PACKAGE_NAME_KEY_LEGACY_VISIBLE} or {@link #PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE}.
* <p>
* See {@link #getAccountVisibility} for possible values.
* <p>
* This method requires the caller to have a signature match with the authenticator that owns
* the specified account.
*
- * @param account Account to make visible.
- * @param uid The UID of the application to modify account visibility.
+ * @param account Account to update visibility
+ * @param packageName Package name of the application to modify account visibility.
* @param visibility - new visibility value.
*
* @return True if visibility value was succesfully updated.
*/
- public boolean setAccountVisibility(Account account, int uid,
+ public boolean setAccountVisibility(Account account, String packageName,
@AccountVisibility int visibility) {
+ if (account == null)
+ throw new IllegalArgumentException("account is null");
try {
- return mService.setAccountVisibility(account, uid, visibility);
+ return mService.setAccountVisibility(account, packageName, visibility);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
- * Gets visibility of certain account for given UID. Possible returned values are:
+ * Get visibility of certain account for given application. Possible returned values are:
* <ul>
* <li>{@link #VISIBILITY_UNDEFINED}</li>
* <li>{@link #VISIBILITY_VISIBLE}</li>
@@ -935,13 +956,15 @@ public class AccountManager {
* the specified account.
*
* @param account Account to get visibility.
- * @param uid The UID of the application to get account visibility.
+ * @param packageName Package name of the application to get account visibility
*
- * @return int Visibility for given account and uid.
+ * @return int Visibility for given account and package.
*/
- public @AccountVisibility int getAccountVisibility(Account account, int uid) {
+ public @AccountVisibility int getAccountVisibility(Account account, String packageName) {
+ if (account == null)
+ throw new IllegalArgumentException("account is null");
try {
- return mService.getAccountVisibility(account, uid);
+ return mService.getAccountVisibility(account, packageName);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -2110,10 +2133,23 @@ public class AccountManager {
synchronized (mAccountsUpdatedListeners) {
try {
if (mAccountsUpdatedListeners.containsKey(listener)) {
- listener.onAccountsUpdated(accountsCopy);
+ Set<String> types = mAccountsUpdatedListenersTypes.get(listener);
+ if (types != null) {
+ // filter by account type;
+ ArrayList<Account> filtered = new ArrayList<>();
+ for (Account account : accountsCopy) {
+ if (types.contains(account.type)) {
+ filtered.add(account);
+ }
+ }
+ listener.onAccountsUpdated(
+ filtered.toArray(new Account[filtered.size()]));
+ } else {
+ listener.onAccountsUpdated(accountsCopy);
+ }
}
} catch (SQLException e) {
- // Better luck next time. If the problem was disk-full,
+ // Better luck next time. If the problem was disk-full,
// the STORAGE_OK intent will re-trigger the update.
Log.e(TAG, "Can't update accounts", e);
}
@@ -2759,6 +2795,9 @@ public class AccountManager {
private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
Maps.newHashMap();
+ private final HashMap<OnAccountsUpdateListener, Set<String> > mAccountsUpdatedListenersTypes =
+ Maps.newHashMap();
+
/**
* BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
* so that it can read the updated list of accounts and send them to the listener
@@ -2784,7 +2823,7 @@ public class AccountManager {
* accounts of any type related to the caller. This method is equivalent to
* addOnAccountsUpdatedListener(listener, handler, updateImmediately, null)
*
- * @see #addOnAccountsUpdatedListener(OnAccountsUpdateListener, Handler, boolean, Handler,
+ * @see #addOnAccountsUpdatedListener(OnAccountsUpdateListener, Handler, boolean,
* String[])
*/
public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
@@ -2828,7 +2867,10 @@ public class AccountManager {
final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
mAccountsUpdatedListeners.put(listener, handler);
-
+ if (accountTypes != null) {
+ mAccountsUpdatedListenersTypes.put(listener,
+ new HashSet<String>(Arrays.asList(accountTypes)));
+ }
if (wasEmpty) {
// Register a broadcast receiver to monitor account changes
@@ -2870,6 +2912,7 @@ public class AccountManager {
return;
}
mAccountsUpdatedListeners.remove(listener);
+ mAccountsUpdatedListenersTypes.remove(listener);
if (mAccountsUpdatedListeners.isEmpty()) {
mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 242b3ea3306e..16a45ba6d5fe 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -52,7 +52,9 @@ public class ChooseAccountActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+ // TODO This activity is only used by getAuthTokenByFeatures and can not see
+ // VISIBILITY_USER_MANAGED_NOT_VISIBLE accounts. It should be moved to account managed
+ // service.
mAccounts = getIntent().getParcelableArrayExtra(AccountManager.KEY_ACCOUNTS);
mAccountManagerResponse =
getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE);
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 8c71f50d3f02..35011b5f3ec3 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -40,7 +40,9 @@ import com.android.internal.R;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
@@ -110,7 +112,7 @@ public class ChooseTypeAndAccountActivity extends Activity
private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
- private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList";
+ private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountAndVisibilityList";
private static final int SELECTED_ITEM_NONE = -1;
@@ -120,7 +122,11 @@ public class ChooseTypeAndAccountActivity extends Activity
private boolean mSelectedAddNewAccount = false;
private String mDescriptionOverride;
- private ArrayList<Account> mAccounts;
+ private Map<Account, Integer> mAccounts;
+ // TODO Redesign flow to show NOT_VISIBLE accounts
+ // and display a warning if they are selected.
+ // Currently NOT_VISBILE accounts are not shown at all.
+ private ArrayList<Account> mPossiblyVisibleAccounts;
private int mPendingRequest = REQUEST_NULL;
private Parcelable[] mExistingAccounts = null;
private int mSelectedItemIndex;
@@ -164,12 +170,12 @@ public class ChooseTypeAndAccountActivity extends Activity
savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
// Makes sure that any user selection is preserved across orientation changes.
- mSelectedAccountName = savedInstanceState.getString(
- KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
-
- mSelectedAddNewAccount = savedInstanceState.getBoolean(
- KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
- mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
+ mSelectedAccountName =
+ savedInstanceState.getString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
+ mSelectedAddNewAccount =
+ savedInstanceState.getBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+ mAccounts = (Map<Account, Integer>) savedInstanceState
+ .getSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST);
} else {
mPendingRequest = REQUEST_NULL;
mExistingAccounts = null;
@@ -220,9 +226,15 @@ public class ChooseTypeAndAccountActivity extends Activity
}
}
- String[] listItems = getListOfDisplayableOptions(mAccounts);
- mSelectedItemIndex = getItemIndexToSelect(
- mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
+ mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
+ for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
+ if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
+ mPossiblyVisibleAccounts.add(entry.getKey());
+ }
+ }
+ String[] listItems = getListOfDisplayableOptions(mPossiblyVisibleAccounts);
+ mSelectedItemIndex = getItemIndexToSelect(mPossiblyVisibleAccounts, mSelectedAccountName,
+ mSelectedAddNewAccount);
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_type_and_account);
@@ -250,15 +262,18 @@ public class ChooseTypeAndAccountActivity extends Activity
outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
}
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
- if (mSelectedItemIndex == mAccounts.size()) {
+ if (mSelectedItemIndex == mPossiblyVisibleAccounts.size()) {
outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
} else {
outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
- mAccounts.get(mSelectedItemIndex).name);
+ mPossiblyVisibleAccounts.get(mSelectedItemIndex).name);
}
}
- outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
+ // should be HashMap by default.
+ HashMap<Account, Integer> accountsHashMap = (mAccounts instanceof HashMap)
+ ? (HashMap) mAccounts : new HashMap<Account, Integer>(mAccounts);
+ outState.putSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST, accountsHashMap);
}
public void onCancelButtonClicked(View view) {
@@ -266,11 +281,11 @@ public class ChooseTypeAndAccountActivity extends Activity
}
public void onOkButtonClicked(View view) {
- if (mSelectedItemIndex == mAccounts.size()) {
+ if (mSelectedItemIndex == mPossiblyVisibleAccounts.size()) {
// Selected "Add New Account" option
startChooseAccountTypeActivity();
} else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
- onAccountSelected(mAccounts.get(mSelectedItemIndex));
+ onAccountSelected(mPossiblyVisibleAccounts.get(mSelectedItemIndex));
}
}
@@ -321,6 +336,7 @@ public class ChooseTypeAndAccountActivity extends Activity
}
if (accountName == null || accountType == null) {
+ // new account was added.
Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
mCallingPackage, mCallingUid);
Set<Account> preExistingAccounts = new HashSet<Account>();
@@ -328,6 +344,7 @@ public class ChooseTypeAndAccountActivity extends Activity
preExistingAccounts.add((Account) accountParcel);
}
for (Account account : currentAccounts) {
+ // New account is visible to the app - return it.
if (!preExistingAccounts.contains(account)) {
accountName = account.name;
accountType = account.type;
@@ -409,13 +426,27 @@ public class ChooseTypeAndAccountActivity extends Activity
}
private void setResultAndFinish(final String accountName, final String accountType) {
+ // Mark account as visible since user chose it.
+ Account account = new Account(accountName, accountType);
+ Integer oldVisibility = mAccounts.get(account);
+ // oldVisibility is null if new account was added
+ if (oldVisibility == null) {
+ Map<Account, Integer> accountsAndVisibility = AccountManager.get(this)
+ .getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
+ oldVisibility = accountsAndVisibility.get(account);
+ }
+ if (oldVisibility != null
+ && oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) {
+ AccountManager.get(this).setAccountVisibility(account, mCallingPackage,
+ AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+ }
Bundle bundle = new Bundle();
bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
- + "selected account " + accountName + ", " + accountType);
+ Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: selected account "
+ + accountName + ", " + accountType);
}
finish();
}
@@ -474,25 +505,28 @@ public class ChooseTypeAndAccountActivity extends Activity
}
/**
- * Create a list of Account objects for each account that is acceptable. Filter out
- * accounts that don't match the allowable types, if provided, or that don't match the
- * allowable accounts, if provided.
+ * Create a list of Account objects for each account that is acceptable. Filter out accounts
+ * that don't match the allowable types, if provided, or that don't match the allowable
+ * accounts, if provided.
*/
- private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
- final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
- mCallingUid);
- ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
- for (Account account : accounts) {
- if (mSetOfAllowableAccounts != null && !mSetOfAllowableAccounts.contains(account)) {
- continue;
- }
- if (mSetOfRelevantAccountTypes != null
- && !mSetOfRelevantAccountTypes.contains(account.type)) {
- continue;
- }
- accountsToPopulate.add(account);
- }
- return accountsToPopulate;
+ private Map<Account, Integer> getAcceptableAccountChoices(AccountManager accountManager) {
+ Map<Account, Integer> accountsAndVisibility =
+ accountManager.getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
+
+ Map<Account, Integer> accountsToPopulate =
+ new HashMap<Account, Integer>(accountsAndVisibility.size());
+ for (Map.Entry<Account, Integer> entry : accountsAndVisibility.entrySet()) {
+ if (mSetOfAllowableAccounts != null
+ && !mSetOfAllowableAccounts.contains(entry.getKey())) {
+ continue;
+ }
+ if (mSetOfRelevantAccountTypes != null
+ && !mSetOfRelevantAccountTypes.contains(entry.getKey().type)) {
+ continue;
+ }
+ accountsToPopulate.put(entry.getKey(), entry.getValue());
+ }
+ return accountsToPopulate;
}
/**
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 66c3ca31afdb..e0fdac146f68 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -108,16 +108,13 @@ interface IAccountManager {
void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
String statusToken);
- /* Allows Authenticator to get UIDs of packages which registered to receive updates about given account type.*/
- int[] getRequestingUidsForType(String accountType);
-
+ /* Returns Map<String, Integer> from package name to visibility with all values stored for given account */
+ Map getPackagesAndVisibilityForAccount(in Account account);
boolean addAccountExplicitlyWithVisibility(in Account account, String password, in Bundle extras,
in Map visibility);
-
- boolean setAccountVisibility(in Account a, int uid, int newVisibility);
- int getAccountVisibility(in Account a, int uid);
-
- /* Type may be null returns Map <Account, Integer>*/
+ boolean setAccountVisibility(in Account a, in String packageName, int newVisibility);
+ int getAccountVisibility(in Account a, in String packageName);
+ /* Type may be null returns Map <Account, Integer>*/
Map getAccountsAndVisibilityForPackage(in String packageName, in String accountType);
/* Check if the package in a user can access an account */
diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java
index 95262ab46a9e..e2e5a8f66288 100644
--- a/core/java/android/animation/AnimationHandler.java
+++ b/core/java/android/animation/AnimationHandler.java
@@ -276,8 +276,9 @@ public class AnimationHandler {
* Run animation based on the frame time.
* @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
* base.
+ * @return if the animation has finished.
*/
- void doAnimationFrame(long frameTime);
+ boolean doAnimationFrame(long frameTime);
/**
* This notifies the callback of frame commit time. Frame commit time is the time after
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index c51725a2caac..4ebcc446e5a2 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -464,12 +464,94 @@ public abstract class Animator implements Cloneable {
throw new IllegalStateException("Reverse is not supported");
}
+ // Pulse an animation frame into the animation.
+ boolean pulseAnimationFrame(long frameTime) {
+ // TODO: Need to find a better signal than this. There's a bug in SystemUI that's preventing
+ // returning !isStarted() from working.
+ return false;
+ }
+
+ /**
+ * Internal use only.
+ * This call starts the animation in regular or reverse direction without requiring them to
+ * register frame callbacks. The caller will be responsible for all the subsequent animation
+ * pulses. Specifically, the caller needs to call doAnimationFrame(...) for the animation on
+ * every frame.
+ *
+ * @param inReverse whether the animation should play in reverse direction
+ */
+ void startWithoutPulsing(boolean inReverse) {
+ if (inReverse) {
+ reverse();
+ } else {
+ start();
+ }
+ }
+
+ /**
+ * Internal use only.
+ * Skips the animation value to end/start, depending on whether the play direction is forward
+ * or backward.
+ *
+ * @param inReverse whether the end value is based on a reverse direction. If yes, this is
+ * equivalent to skip to start value in a forward playing direction.
+ */
+ void skipToEndValue(boolean inReverse) {}
+
+
+ /**
+ * Internal use only.
+ *
+ * Returns whether the animation has start/end values setup. For most of the animations, this
+ * should always be true. For ObjectAnimators, the start values are setup in the initialization
+ * of the animation.
+ */
+ boolean isInitialized() {
+ return true;
+ }
+
+ /**
+ * Internal use only.
+ */
+ void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {}
+
/**
* <p>An animation listener receives notifications from an animation.
* Notifications indicate animation related events, such as the end or the
* repetition of the animation.</p>
*/
public static interface AnimatorListener {
+
+ /**
+ * <p>Notifies the start of the animation as well as the animation's overall play direction.
+ * This method's default behavior is to call {@link #onAnimationStart(Animator)}. This
+ * method can be overridden, though not required, to get the additional play direction info
+ * when an animation starts. Skipping calling super when overriding this method results in
+ * {@link #onAnimationStart(Animator)} not getting called.
+ *
+ * @param animation The started animation.
+ * @param isReverse Whether the animation is playing in reverse.
+ */
+ default void onAnimationStart(Animator animation, boolean isReverse) {
+ onAnimationStart(animation);
+ }
+
+ /**
+ * <p>Notifies the end of the animation. This callback is not invoked
+ * for animations with repeat count set to INFINITE.</p>
+ *
+ * <p>This method's default behavior is to call {@link #onAnimationEnd(Animator)}. This
+ * method can be overridden, though not required, to get the additional play direction info
+ * when an animation ends. Skipping calling super when overriding this method results in
+ * {@link #onAnimationEnd(Animator)} not getting called.
+ *
+ * @param animation The animation which reached its end.
+ * @param isReverse Whether the animation is playing in reverse.
+ */
+ default void onAnimationEnd(Animator animation, boolean isReverse) {
+ onAnimationEnd(animation);
+ }
+
/**
* <p>Notifies the start of the animation.</p>
*
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index a904f9d5447b..4e3b7d0739a9 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -19,11 +19,15 @@ package android.animation;
import android.app.ActivityThread;
import android.app.Application;
import android.os.Build;
+import android.os.Looper;
+import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
+import android.view.animation.Animation;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
/**
@@ -52,7 +56,7 @@ import java.util.List;
* Animation</a> developer guide.</p>
* </div>
*/
-public final class AnimatorSet extends Animator {
+public final class AnimatorSet extends Animator implements AnimationHandler.AnimationFrameCallback {
private static final String TAG = "AnimatorSet";
/**
@@ -66,7 +70,7 @@ public final class AnimatorSet extends Animator {
* Tracks animations currently being played, so that we know what to
* cancel or end when cancel() or end() is called on this AnimatorSet
*/
- private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
+ private ArrayList<Node> mPlayingSet = new ArrayList<Node>();
/**
* Contains all nodes, mapped to their respective Animators. When new
@@ -77,6 +81,11 @@ public final class AnimatorSet extends Animator {
private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>();
/**
+ * Contains the start and end events of all the nodes. All these events are sorted in this list.
+ */
+ private ArrayList<AnimationEvent> mEvents = new ArrayList<>();
+
+ /**
* Set of all nodes created for this AnimatorSet. This list is used upon
* starting the set, and the nodes are placed in sorted order into the
* sortedNodes collection.
@@ -84,21 +93,6 @@ public final class AnimatorSet extends Animator {
private ArrayList<Node> mNodes = new ArrayList<Node>();
/**
- * Animator Listener that tracks the lifecycle of each Animator in the set. It will be added
- * to each Animator before they start and removed after they end.
- */
- private AnimatorSetListener mSetListener = new AnimatorSetListener(this);
-
- /**
- * Flag indicating that the AnimatorSet has been manually
- * terminated (by calling cancel() or end()).
- * This flag is used to avoid starting other animations when currently-playing
- * child animations of this AnimatorSet end. It also determines whether cancel/end
- * notifications are sent out via the normal AnimatorSetListener mechanism.
- */
- private boolean mTerminated = false;
-
- /**
* Tracks whether any change has been made to the AnimatorSet, which is then used to
* determine whether the dependency graph should be re-constructed.
*/
@@ -131,8 +125,6 @@ public final class AnimatorSet extends Animator {
// was set on this AnimatorSet, so it should not be passed down to the children.
private TimeInterpolator mInterpolator = null;
- // Whether the AnimatorSet can be reversed.
- private boolean mReversible = true;
// The total duration of finishing all the Animators in the set.
private long mTotalDuration = 0;
@@ -142,6 +134,59 @@ public final class AnimatorSet extends Animator {
// the animator set and immediately end it for N and forward.
private final boolean mShouldIgnoreEndWithoutStart;
+ // In pre-O releases, calling start() doesn't reset all the animators values to start values.
+ // As a result, the start of the animation is inconsistent with what setCurrentPlayTime(0) would
+ // look like on O. Also it is inconsistent with what reverse() does on O, as reverse would
+ // advance all the animations to the right beginning values for before starting to reverse.
+ // From O and forward, we will add an additional step of resetting the animation values (unless
+ // the animation was previously seeked and therefore doesn't start from the beginning).
+ private final boolean mShouldResetValuesAtStart;
+
+ // The time, in milliseconds, when last frame of the animation came in. -1 when the animation is
+ // not running.
+ private long mLastFrameTime = -1;
+
+ // The time, in milliseconds, when the first frame of the animation came in.
+ // -1 when the animation is not running.
+ private long mFirstFrame = -1;
+
+ // The time, in milliseconds, when the first frame of the animation came in.
+ // -1 when the animation is not running.
+ private int mLastEventId = -1;
+
+ // Indicates whether the animation is reversing.
+ private boolean mReversing = false;
+
+ // Indicates whether the animation should register frame callbacks. If false, the animation will
+ // passively wait for an AnimatorSet to pulse it.
+ private boolean mSelfPulse = true;
+
+ // SeekState stores the last seeked play time as well as seek direction.
+ private SeekState mSeekState = new SeekState();
+
+ // Indicates where children animators are all initialized with their start values captured.
+ private boolean mChildrenInitialized = false;
+
+ /**
+ * Set on the next frame after pause() is called, used to calculate a new startTime
+ * or delayStartTime which allows the animator set to continue from the point at which
+ * it was paused. If negative, has not yet been set.
+ */
+ private long mPauseTime = -1;
+
+ // This is to work around a bug in b/34736819. This needs to be removed once app team
+ // fixes their side.
+ private AnimatorListenerAdapter mDummyListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mNodeMap.get(animation) == null) {
+ throw new AndroidRuntimeException("Error: animation ended is not in the node map");
+ }
+ mNodeMap.get(animation).mEnded = true;
+
+ }
+ };
+
public AnimatorSet() {
super();
mNodeMap.put(mDelayAnim, mRootNode);
@@ -150,10 +195,19 @@ public final class AnimatorSet extends Animator {
Application app = ActivityThread.currentApplication();
if (app == null || app.getApplicationInfo() == null) {
mShouldIgnoreEndWithoutStart = true;
- } else if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
- mShouldIgnoreEndWithoutStart = true;
+ mShouldResetValuesAtStart = false;
} else {
- mShouldIgnoreEndWithoutStart = false;
+ if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ mShouldIgnoreEndWithoutStart = true;
+ } else {
+ mShouldIgnoreEndWithoutStart = false;
+ }
+
+ if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) {
+ mShouldResetValuesAtStart = false;
+ } else {
+ mShouldResetValuesAtStart = true;
+ }
}
}
@@ -206,7 +260,6 @@ public final class AnimatorSet extends Animator {
if (items.length == 1) {
play(items[0]);
} else {
- mReversible = false;
for (int i = 0; i < items.length - 1; ++i) {
play(items[i]).before(items[i + 1]);
}
@@ -225,7 +278,6 @@ public final class AnimatorSet extends Animator {
if (items.size() == 1) {
play(items.get(0));
} else {
- mReversible = false;
for (int i = 0; i < items.size() - 1; ++i) {
play(items.get(i)).before(items.get(i + 1));
}
@@ -350,7 +402,9 @@ public final class AnimatorSet extends Animator {
@SuppressWarnings("unchecked")
@Override
public void cancel() {
- mTerminated = true;
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+ }
if (isStarted()) {
ArrayList<AnimatorListener> tmpListeners = null;
if (mListeners != null) {
@@ -360,18 +414,13 @@ public final class AnimatorSet extends Animator {
tmpListeners.get(i).onAnimationCancel(this);
}
}
- ArrayList<Animator> playingSet = new ArrayList<>(mPlayingSet);
+ ArrayList<Node> playingSet = new ArrayList<>(mPlayingSet);
int setSize = playingSet.size();
for (int i = 0; i < setSize; i++) {
- playingSet.get(i).cancel();
- }
- if (tmpListeners != null) {
- int size = tmpListeners.size();
- for (int i = 0; i < size; i++) {
- tmpListeners.get(i).onAnimationEnd(this);
- }
+ playingSet.get(i).mAnimation.cancel();
}
- mStarted = false;
+ mPlayingSet.clear();
+ endAnimation();
}
}
@@ -383,50 +432,40 @@ public final class AnimatorSet extends Animator {
*/
@Override
public void end() {
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+ }
if (mShouldIgnoreEndWithoutStart && !isStarted()) {
return;
}
- mTerminated = true;
if (isStarted()) {
- endRemainingAnimations();
- }
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (int i = 0; i < tmpListeners.size(); i++) {
- tmpListeners.get(i).onAnimationEnd(this);
- }
- }
- mStarted = false;
- }
-
- /**
- * Iterate the animations that haven't finished or haven't started, and end them.
- */
- private void endRemainingAnimations() {
- ArrayList<Animator> remainingList = new ArrayList<Animator>(mNodes.size());
- remainingList.addAll(mPlayingSet);
-
- int index = 0;
- while (index < remainingList.size()) {
- Animator anim = remainingList.get(index);
- anim.end();
- index++;
- Node node = mNodeMap.get(anim);
- if (node.mChildNodes != null) {
- int childSize = node.mChildNodes.size();
- for (int i = 0; i < childSize; i++) {
- Node child = node.mChildNodes.get(i);
- if (child.mLatestParent != node) {
- continue;
+ // Iterate the animations that haven't finished or haven't started, and end them.
+ if (mReversing) {
+ // Between start() and first frame, mLastEventId would be unset (i.e. -1)
+ mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId;
+ for (int j = mLastEventId - 1; j >= 0; j--) {
+ AnimationEvent event = mEvents.get(j);
+ if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ event.mNode.mAnimation.reverse();
+ } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ event.mNode.mAnimation.end();
+ }
+ }
+ } else {
+ for (int j = mLastEventId + 1; j < mEvents.size(); j++) {
+ AnimationEvent event = mEvents.get(j);
+ if (event.mEvent == AnimationEvent.ANIMATION_START) {
+ event.mNode.mAnimation.start();
+ } else if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ event.mNode.mAnimation.end();
}
- remainingList.add(child.mAnimation);
}
}
+ mPlayingSet.clear();
}
+ endAnimation();
}
-
/**
* Returns true if any of the child animations of this AnimatorSet have been started and have
* not yet ended. Child animations will not be started until the AnimatorSet has gone past
@@ -437,14 +476,12 @@ public final class AnimatorSet extends Animator {
*/
@Override
public boolean isRunning() {
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- if (node != mRootNode && node.mAnimation.isStarted()) {
- return true;
- }
+ if (mStartDelay > 0) {
+ return mStarted && !mDelayAnim.isRunning();
+ } else {
+ // No start delay, animation should start right away
+ return mStarted;
}
- return false;
}
@Override
@@ -482,9 +519,6 @@ public final class AnimatorSet extends Animator {
return;
}
mStartDelay = startDelay;
- if (mStartDelay > 0) {
- mReversible = false;
- }
if (!mDependencyDirty) {
// Dependency graph already constructed, update all the nodes' start/end time
int size = mNodes.size();
@@ -562,40 +596,26 @@ public final class AnimatorSet extends Animator {
@Override
public void pause() {
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+ }
boolean previouslyPaused = mPaused;
super.pause();
if (!previouslyPaused && mPaused) {
- if (mDelayAnim.isStarted()) {
- // If delay hasn't passed, pause the start delay animator.
- mDelayAnim.pause();
- } else {
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- if (node != mRootNode) {
- node.mAnimation.pause();
- }
- }
- }
+ mPauseTime = -1;
}
}
@Override
public void resume() {
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+ }
boolean previouslyPaused = mPaused;
super.resume();
if (previouslyPaused && !mPaused) {
- if (mDelayAnim.isStarted()) {
- // If start delay hasn't passed, resume the previously paused start delay animator
- mDelayAnim.resume();
- } else {
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- if (node != mRootNode) {
- node.mAnimation.resume();
- }
- }
+ if (mPauseTime >= 0) {
+ addAnimationCallback(0);
}
}
}
@@ -610,9 +630,33 @@ public final class AnimatorSet extends Animator {
@SuppressWarnings("unchecked")
@Override
public void start() {
- mTerminated = false;
+ start(false, true);
+ }
+
+ @Override
+ void startWithoutPulsing(boolean inReverse) {
+ start(inReverse, false);
+ }
+
+ private void initAnimation() {
+ if (mInterpolator != null) {
+ for (int i = 0; i < mNodes.size(); i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.setInterpolator(mInterpolator);
+ }
+ }
+ updateAnimatorsDuration();
+ createDependencyGraph();
+ }
+
+ private void start(boolean inReverse, boolean selfPulse) {
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+ }
mStarted = true;
+ mSelfPulse = selfPulse;
mPaused = false;
+ mPauseTime = -1;
int size = mNodes.size();
for (int i = 0; i < size; i++) {
@@ -621,26 +665,17 @@ public final class AnimatorSet extends Animator {
node.mAnimation.setAllowRunningAsynchronously(false);
}
- if (mInterpolator != null) {
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- node.mAnimation.setInterpolator(mInterpolator);
- }
+ initAnimation();
+ if (inReverse && !canReverse()) {
+ throw new UnsupportedOperationException("Cannot reverse infinite AnimatorSet");
}
- updateAnimatorsDuration();
- createDependencyGraph();
+ mReversing = inReverse;
// Now that all dependencies are set up, start the animations that should be started.
- boolean setIsEmpty = false;
- if (mStartDelay > 0) {
- start(mRootNode);
- } else if (isEmptySet(this)) {
- // Set is empty or contains only empty animator sets. Skip to end in this case.
- setIsEmpty = true;
- } else {
- // No delay, but there are other animators in the set
- onChildAnimatorEnded(mDelayAnim);
+ boolean setIsEmpty = isEmptySet(this);
+ if (!setIsEmpty) {
+ startAnimation();
}
if (mListeners != null) {
@@ -648,12 +683,12 @@ public final class AnimatorSet extends Animator {
(ArrayList<AnimatorListener>) mListeners.clone();
int numListeners = tmpListeners.size();
for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationStart(this);
+ tmpListeners.get(i).onAnimationStart(this, inReverse);
}
}
if (setIsEmpty) {
// In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away.
- onChildAnimatorEnded(mDelayAnim);
+ end();
}
}
@@ -690,11 +725,454 @@ public final class AnimatorSet extends Animator {
mDelayAnim.setDuration(mStartDelay);
}
- void start(final Node node) {
- final Animator anim = node.mAnimation;
- mPlayingSet.add(anim);
- anim.addListener(mSetListener);
- anim.start();
+ @Override
+ void skipToEndValue(boolean inReverse) {
+ if (!isInitialized()) {
+ throw new UnsupportedOperationException("Children must be initialized.");
+ }
+
+ // This makes sure the animation events are sorted an up to date.
+ initAnimation();
+
+ // Calling skip to the end in the sequence that they would be called in a forward/reverse
+ // run, such that the sequential animations modifying the same property would have
+ // the right value in the end.
+ if (inReverse) {
+ for (int i = mEvents.size() - 1; i >= 0; i--) {
+ if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ mEvents.get(i).mNode.mAnimation.skipToEndValue(true);
+ }
+ }
+ } else {
+ for (int i = 0; i < mEvents.size(); i++) {
+ if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_END) {
+ mEvents.get(i).mNode.mAnimation.skipToEndValue(false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Internal only.
+ *
+ * This method sets the animation values based on the play time. It also fast forward or
+ * backward all the child animations progress accordingly.
+ *
+ * This method is also responsible for calling
+ * {@link android.view.animation.Animation.AnimationListener#onAnimationRepeat(Animation)},
+ * as needed, based on the last play time and current play time.
+ */
+ @Override
+ void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {
+ if (currentPlayTime < 0 || lastPlayTime < 0) {
+ throw new UnsupportedOperationException("Error: Play time should never be negative.");
+ }
+ // TODO: take into account repeat counts and repeat callback when repeat is implemented.
+ // Clamp currentPlayTime and lastPlayTime
+
+ // TODO: Make this more efficient
+
+ // Convert the play times to the forward direction.
+ if (inReverse) {
+ if (getTotalDuration() == DURATION_INFINITE) {
+ throw new UnsupportedOperationException("Cannot reverse AnimatorSet with infinite"
+ + " duration");
+ }
+ long duration = getTotalDuration() - mStartDelay;
+ currentPlayTime = Math.min(currentPlayTime, duration);
+ currentPlayTime = duration - currentPlayTime;
+ lastPlayTime = duration - lastPlayTime;
+ inReverse = false;
+ }
+ // Skip all values to start, and iterate mEvents to get animations to the right fraction.
+ skipToStartValue(false);
+
+ ArrayList<Node> unfinishedNodes = new ArrayList<>();
+ // Assumes forward playing from here on.
+ for (int i = 0; i < mEvents.size(); i++) {
+ AnimationEvent event = mEvents.get(i);
+ if (event.getTime() > currentPlayTime) {
+ break;
+ }
+
+ // This animation started prior to the current play time, and won't finish before the
+ // play time, add to the unfinished list.
+ if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ if (event.mNode.mEndTime == DURATION_INFINITE
+ || event.mNode.mEndTime > currentPlayTime) {
+ unfinishedNodes.add(event.mNode);
+ }
+ }
+ // For animations that do finish before the play time, end them in the sequence that
+ // they would in a normal run.
+ if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ // Skip to the end of the animation.
+ event.mNode.mAnimation.skipToEndValue(false);
+ }
+ }
+
+ // Seek unfinished animation to the right time.
+ for (int i = 0; i < unfinishedNodes.size(); i++) {
+ Node node = unfinishedNodes.get(i);
+ long playTime = getPlayTimeForNode(currentPlayTime, node, inReverse);
+ node.mAnimation.animateBasedOnPlayTime(playTime, lastPlayTime, inReverse);
+ }
+ }
+
+ @Override
+ boolean isInitialized() {
+ if (mChildrenInitialized) {
+ return true;
+ }
+
+ boolean allInitialized = true;
+ for (int i = 0; i < mNodes.size(); i++) {
+ if (!mNodes.get(i).mAnimation.isInitialized()) {
+ allInitialized = false;
+ break;
+ }
+ }
+ mChildrenInitialized = allInitialized;
+ return mChildrenInitialized;
+ }
+
+ private void skipToStartValue(boolean inReverse) {
+ skipToEndValue(!inReverse);
+ }
+
+ /**
+ * Sets the position of the animation to the specified point in time. This time should
+ * be between 0 and the total duration of the animation, including any repetition. If
+ * the animation has not yet been started, then it will not advance forward after it is
+ * set to this time; it will simply set the time to this value and perform any appropriate
+ * actions based on that time. If the animation is already running, then setCurrentPlayTime()
+ * will set the current playing time to this value and continue playing from that point.
+ *
+ * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
+ * Unless the animation is reversing, the playtime is considered the time since
+ * the end of the start delay of the AnimatorSet in a forward playing direction.
+ *
+ */
+ public void setCurrentPlayTime(long playTime) {
+ if (mReversing && getTotalDuration() == DURATION_INFINITE) {
+ // Should never get here
+ throw new UnsupportedOperationException("Error: Cannot seek in reverse in an infinite"
+ + " AnimatorSet");
+ }
+
+ if ((getTotalDuration() != DURATION_INFINITE && playTime > getTotalDuration() - mStartDelay)
+ || playTime < 0) {
+ throw new UnsupportedOperationException("Error: Play time should always be in between"
+ + "0 and duration.");
+ }
+
+ initAnimation();
+
+ if (!isStarted()) {
+ if (mReversing) {
+ throw new UnsupportedOperationException("Error: Something went wrong. mReversing"
+ + " should not be set when AnimatorSet is not started.");
+ }
+ if (!mSeekState.isActive()) {
+ findLatestEventIdForTime(0);
+ // Set all the values to start values.
+ initChildren();
+ skipToStartValue(mReversing);
+ mSeekState.setPlayTime(0, mReversing);
+ }
+ animateBasedOnPlayTime(playTime, 0, mReversing);
+ mSeekState.setPlayTime(playTime, mReversing);
+ } else {
+ // If the animation is running, just set the seek time and wait until the next frame
+ // (i.e. doAnimationFrame(...)) to advance the animation.
+ mSeekState.setPlayTime(playTime, mReversing);
+ }
+ }
+
+ private void initChildren() {
+ if (!isInitialized()) {
+ mChildrenInitialized = true;
+ // Forcefully initialize all children based on their end time, so that if the start
+ // value of a child is dependent on a previous animation, the animation will be
+ // initialized after the the previous animations have been advanced to the end.
+ skipToEndValue(false);
+ }
+ }
+
+ /**
+ * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
+ * base.
+ * @return
+ * @hide
+ */
+ @Override
+ public boolean doAnimationFrame(long frameTime) {
+ if (mLastFrameTime < 0) {
+ mFirstFrame = mLastFrameTime = frameTime;
+ }
+
+ // Handle pause/resume
+ if (mPaused) {
+ // Note: Child animations don't receive pause events. Since it's never a contract that
+ // the child animators will be paused when set is paused, this is unlikely to be an
+ // issue.
+ mPauseTime = frameTime;
+ removeAnimationCallback();
+ return false;
+ } else if (mPauseTime > 0) {
+ // Offset by the duration that the animation was paused
+ mFirstFrame += (frameTime - mPauseTime);
+ mPauseTime = -1;
+ }
+
+ // Continue at seeked position
+ if (mSeekState.isActive()) {
+ mSeekState.updateSeekDirection(mReversing);
+ mFirstFrame = frameTime - mSeekState.getPlayTime() - mStartDelay;
+ mSeekState.reset();
+ }
+
+ // This playTime includes the start delay.
+ long playTime = frameTime - mFirstFrame;
+
+ // 1. Pulse the animators that will start or end in this frame
+ // 2. Pulse the animators that will finish in a later frame
+ int latestId = findLatestEventIdForTime(playTime);
+ int startId = mLastEventId;
+
+ handleAnimationEvents(startId, latestId, playTime);
+
+ mLastEventId = latestId;
+
+ // Pump a frame to the on-going animators
+ for (int i = 0; i < mPlayingSet.size(); i++) {
+ Node node = mPlayingSet.get(i);
+ if (!node.mEnded) {
+ node.mEnded = node.mAnimation.pulseAnimationFrame(
+ getPlayTimeForNode(playTime, node));
+ }
+ }
+
+ // Remove all the finished anims
+ for (int i = mPlayingSet.size() - 1; i >= 0; i--) {
+ if (mPlayingSet.get(i).mEnded) {
+ mPlayingSet.remove(i);
+ }
+ }
+
+ mLastFrameTime = frameTime;
+ if (mPlayingSet.isEmpty()) {
+ boolean finished;
+ if (mReversing) {
+ // Make sure there's no more END event before current event id and after start delay
+ finished = mLastEventId <= 3;
+ } else {
+ // Make sure there's no more START event before current event id:
+ finished = (mLastEventId == mEvents.size() - 1);
+ }
+ if (finished) {
+ endAnimation();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void commitAnimationFrame(long frameTime) {
+ // No op.
+ }
+
+ @Override
+ boolean pulseAnimationFrame(long frameTime) {
+ return doAnimationFrame(frameTime);
+ }
+
+ /**
+ * When playing forward, we call start() at the animation's scheduled start time, and make sure
+ * to pump a frame at the animation's scheduled end time.
+ *
+ * When playing in reverse, we should reverse the animation when we hit animation's end event,
+ * and expect the animation to end at the its delay ended event, rather than start event.
+ */
+ private void handleAnimationEvents(int startId, int latestId, long playTime) {
+ if (mReversing) {
+ startId = startId == -1 ? mEvents.size() : startId;
+ for (int i = startId - 1; i >= latestId; i--) {
+ AnimationEvent event = mEvents.get(i);
+ Node node = event.mNode;
+ if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ mPlayingSet.add(event.mNode);
+ node.mAnimation.startWithoutPulsing(true);
+ pulseFrame(node, 0);
+ } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED && !node.mEnded) {
+ // end event:
+ pulseFrame(node, getPlayTimeForNode(playTime, node));
+ }
+ }
+ } else {
+ for (int i = startId + 1; i <= latestId; i++) {
+ AnimationEvent event = mEvents.get(i);
+ Node node = event.mNode;
+ if (event.mEvent == AnimationEvent.ANIMATION_START) {
+ mPlayingSet.add(event.mNode);
+ node.mAnimation.startWithoutPulsing(false);
+ pulseFrame(node, 0);
+ } else if (event.mEvent == AnimationEvent.ANIMATION_END && !node.mEnded) {
+ // start event:
+ pulseFrame(node, getPlayTimeForNode(playTime, node));
+ }
+ }
+ }
+ }
+
+ private void pulseFrame(Node node, long frameTime) {
+ if (!node.mEnded) {
+ node.mEnded = node.mAnimation.pulseAnimationFrame(frameTime);
+ }
+ }
+
+ private long getPlayTimeForNode(long overallPlayTime, Node node) {
+ return getPlayTimeForNode(overallPlayTime, node, mReversing);
+ }
+
+ private long getPlayTimeForNode(long overallPlayTime, Node node, boolean inReverse) {
+ if (inReverse) {
+ overallPlayTime = getTotalDuration() - overallPlayTime;
+ return node.mEndTime - overallPlayTime;
+ } else {
+ return overallPlayTime - node.mStartTime;
+ }
+ }
+
+ private void startAnimation() {
+ addDummyListener();
+
+ // Register animation callback
+ addAnimationCallback(mStartDelay);
+
+ if (mSeekState.getPlayTimeNormalized() == 0 && mReversing) {
+ // Maintain old behavior, if seeked to 0 then call reverse, we'll treat the case
+ // the same as no seeking at all.
+ mSeekState.reset();
+ }
+ // Set the child animators to the right end:
+ if (mShouldResetValuesAtStart) {
+ if (mReversing || isInitialized()) {
+ skipToEndValue(!mReversing);
+ } else {
+ // If not all children are initialized and play direction is forward
+ for (int i = mEvents.size() - 1; i >= 0; i--) {
+ if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ Animator anim = mEvents.get(i).mNode.mAnimation;
+ // Only reset the animations that have been initialized to start value,
+ // so that if they are defined without a start value, they will get the
+ // values set at the right time (i.e. the next animation run)
+ if (anim.isInitialized()) {
+ anim.skipToEndValue(true);
+ }
+ }
+ }
+ }
+ }
+
+ if (mReversing || mStartDelay == 0 || mSeekState.isActive()) {
+ long playTime;
+ // If no delay, we need to call start on the first animations to be consistent with old
+ // behavior.
+ if (mSeekState.isActive()) {
+ mSeekState.updateSeekDirection(mReversing);
+ playTime = mSeekState.getPlayTime();
+ } else {
+ playTime = 0;
+ }
+ int toId = findLatestEventIdForTime(playTime);
+ handleAnimationEvents(-1, toId, playTime);
+ mLastEventId = toId;
+ }
+ }
+
+ // This is to work around the issue in b/34736819, as the old behavior in AnimatorSet had
+ // masked a real bug in play movies. TODO: remove this and below once the root cause is fixed.
+ private void addDummyListener() {
+ for (int i = 1; i < mNodes.size(); i++) {
+ mNodes.get(i).mAnimation.addListener(mDummyListener);
+ }
+ }
+
+ private void removeDummyListener() {
+ for (int i = 1; i < mNodes.size(); i++) {
+ mNodes.get(i).mAnimation.removeListener(mDummyListener);
+ }
+ }
+
+ private int findLatestEventIdForTime(long currentPlayTime) {
+ int size = mEvents.size();
+ int latestId = mLastEventId;
+ // Call start on the first animations now to be consistent with the old behavior
+ if (mReversing) {
+ currentPlayTime = getTotalDuration() - currentPlayTime;
+ mLastEventId = mLastEventId == -1 ? size : mLastEventId;
+ for (int j = mLastEventId - 1; j >= 0; j--) {
+ AnimationEvent event = mEvents.get(j);
+ if (event.getTime() >= currentPlayTime) {
+ latestId = j;
+ }
+ }
+ } else {
+ for (int i = mLastEventId + 1; i < size; i++) {
+ AnimationEvent event = mEvents.get(i);
+ if (event.getTime() <= currentPlayTime) {
+ latestId = i;
+ }
+ }
+ }
+ return latestId;
+ }
+
+ private void endAnimation() {
+ mStarted = false;
+ mLastFrameTime = -1;
+ mFirstFrame = -1;
+ mLastEventId = -1;
+ mPaused = false;
+ mPauseTime = -1;
+ mSeekState.reset();
+ mPlayingSet.clear();
+
+ // No longer receive callbacks
+ removeAnimationCallback();
+ // Call end listener
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onAnimationEnd(this, mReversing);
+ }
+ }
+ removeDummyListener();
+ mSelfPulse = true;
+ mReversing = false;
+ }
+
+ private void removeAnimationCallback() {
+ if (!mSelfPulse) {
+ return;
+ }
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.removeCallback(this);
+ }
+
+ private void addAnimationCallback(long delay) {
+ if (!mSelfPulse) {
+ return;
+ }
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.addAnimationFrameCallback(this, delay);
}
@Override
@@ -709,13 +1187,31 @@ public final class AnimatorSet extends Animator {
* and will populate any appropriate lists, when it is started.
*/
final int nodeCount = mNodes.size();
- anim.mTerminated = false;
anim.mStarted = false;
- anim.mPlayingSet = new ArrayList<Animator>();
+ anim.mLastFrameTime = -1;
+ anim.mFirstFrame = -1;
+ anim.mLastEventId = -1;
+ anim.mPaused = false;
+ anim.mPauseTime = -1;
+ anim.mSeekState = new SeekState();
+ anim.mSelfPulse = true;
+ anim.mPlayingSet = new ArrayList<Node>();
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
- anim.mReversible = mReversible;
- anim.mSetListener = new AnimatorSetListener(anim);
+ anim.mEvents = new ArrayList<AnimationEvent>();
+ anim.mDummyListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (anim.mNodeMap.get(animation) == null) {
+ throw new AndroidRuntimeException("Error: animation ended is not in the node"
+ + " map");
+ }
+ anim.mNodeMap.get(animation).mEnded = true;
+
+ }
+ };
+ anim.mReversing = false;
+ anim.mDependencyDirty = true;
// Walk through the old nodes list, cloning each node and adding it to the new nodemap.
// One problem is that the old node dependencies point to nodes in the old AnimatorSet.
@@ -727,17 +1223,6 @@ public final class AnimatorSet extends Animator {
node.mTmpClone = nodeClone;
anim.mNodes.add(nodeClone);
anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
-
- // clear out any listeners that were set up by the AnimatorSet
- final ArrayList<AnimatorListener> cloneListeners = nodeClone.mAnimation.getListeners();
- if (cloneListeners != null) {
- for (int i = cloneListeners.size() - 1; i >= 0; i--) {
- final AnimatorListener listener = cloneListeners.get(i);
- if (listener instanceof AnimatorSetListener) {
- cloneListeners.remove(i);
- }
- }
- }
}
anim.mRootNode = mRootNode.mTmpClone;
@@ -771,89 +1256,6 @@ public final class AnimatorSet extends Animator {
}
- private static class AnimatorSetListener implements AnimatorListener {
-
- private AnimatorSet mAnimatorSet;
-
- AnimatorSetListener(AnimatorSet animatorSet) {
- mAnimatorSet = animatorSet;
- }
-
- public void onAnimationCancel(Animator animation) {
-
- if (!mAnimatorSet.mTerminated) {
- // Listeners are already notified of the AnimatorSet canceling in cancel().
- // The logic below only kicks in when animations end normally
- if (mAnimatorSet.mPlayingSet.size() == 0) {
- ArrayList<AnimatorListener> listeners = mAnimatorSet.mListeners;
- if (listeners != null) {
- int numListeners = listeners.size();
- for (int i = 0; i < numListeners; ++i) {
- listeners.get(i).onAnimationCancel(mAnimatorSet);
- }
- }
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- public void onAnimationEnd(Animator animation) {
- animation.removeListener(this);
- mAnimatorSet.mPlayingSet.remove(animation);
- mAnimatorSet.onChildAnimatorEnded(animation);
- }
-
- // Nothing to do
- public void onAnimationRepeat(Animator animation) {
- }
-
- // Nothing to do
- public void onAnimationStart(Animator animation) {
- }
-
- }
-
- private void onChildAnimatorEnded(Animator animation) {
- Node animNode = mNodeMap.get(animation);
- animNode.mEnded = true;
-
- if (!mTerminated) {
- List<Node> children = animNode.mChildNodes;
- // Start children animations, if any.
- int childrenSize = children == null ? 0 : children.size();
- for (int i = 0; i < childrenSize; i++) {
- if (children.get(i).mLatestParent == animNode) {
- start(children.get(i));
- }
- }
- // Listeners are already notified of the AnimatorSet ending in cancel() or
- // end(); the logic below only kicks in when animations end normally
- boolean allDone = true;
- // Traverse the tree and find if there's any unfinished node
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- if (!mNodes.get(i).mEnded) {
- allDone = false;
- break;
- }
- }
- if (allDone) {
- mStarted = false;
- mPaused = false;
- // If this was the last child animation to end, then notify listeners that this
- // AnimatorSet has ended
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(this);
- }
- }
- }
- }
- }
-
/**
* AnimatorSet is only reversible when the set contains no sequential animation, and no child
* animators have a start delay.
@@ -861,32 +1263,21 @@ public final class AnimatorSet extends Animator {
*/
@Override
public boolean canReverse() {
- if (!mReversible) {
- return false;
- }
- // Loop to make sure all the Nodes can reverse.
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- if (!node.mAnimation.canReverse() || node.mAnimation.getStartDelay() > 0) {
- return false;
- }
- }
- return true;
+ return getTotalDuration() != DURATION_INFINITE;
}
/**
- * @hide
+ * Plays the AnimatorSet in reverse. If the animation has been seeked to a specific play time
+ * using {@link #setCurrentPlayTime(long)}, it will play backwards from the point seeked when
+ * reverse was called. Otherwise, then it will start from the end and play backwards. This
+ * behavior is only set for the current animation; future playing of the animation will use the
+ * default behavior of playing forward.
+ * <p>
+ * Note: reverse is not supported for infinite AnimatorSet.
*/
@Override
public void reverse() {
- if (canReverse()) {
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- node.mAnimation.reverse();
- }
- }
+ start(true, true);
}
@Override
@@ -993,18 +1384,124 @@ public final class AnimatorSet extends Animator {
mRootNode.mEndTime = mDelayAnim.getDuration();
updatePlayTime(mRootNode, visited);
- long maxEndTime = 0;
- for (int i = 0; i < size; i++) {
+ sortAnimationEvents();
+ mTotalDuration = mEvents.get(mEvents.size() - 1).getTime();
+ }
+
+ private void sortAnimationEvents() {
+ // Sort the list of events in ascending order of their time
+ // Create the list including the delay animation.
+ mEvents.clear();
+ for (int i = 1; i < mNodes.size(); i++) {
Node node = mNodes.get(i);
- node.mTotalDuration = node.mAnimation.getTotalDuration();
- if (node.mEndTime == DURATION_INFINITE) {
- maxEndTime = DURATION_INFINITE;
- break;
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_START));
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_DELAY_ENDED));
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_END));
+ }
+ mEvents.sort(new Comparator<AnimationEvent>() {
+ @Override
+ public int compare(AnimationEvent e1, AnimationEvent e2) {
+ long t1 = e1.getTime();
+ long t2 = e2.getTime();
+ if (t1 == t2) {
+ // For events that happen at the same time, we need them to be in the sequence
+ // (end, start, start delay ended)
+ if (e2.mEvent + e1.mEvent == AnimationEvent.ANIMATION_START
+ + AnimationEvent.ANIMATION_DELAY_ENDED) {
+ // Ensure start delay happens after start
+ return e1.mEvent - e2.mEvent;
+ } else {
+ return e2.mEvent - e1.mEvent;
+ }
+ }
+ if (t2 == DURATION_INFINITE) {
+ return -1;
+ }
+ if (t1 == DURATION_INFINITE) {
+ return 1;
+ }
+ // When neither event happens at INFINITE time:
+ return (int) (t1 - t2);
+ }
+ });
+
+ int eventSize = mEvents.size();
+ // For the same animation, start event has to happen before end.
+ for (int i = 0; i < eventSize;) {
+ AnimationEvent event = mEvents.get(i);
+ if (event.mEvent == AnimationEvent.ANIMATION_END) {
+ boolean needToSwapStart;
+ if (event.mNode.mStartTime == event.mNode.mEndTime) {
+ needToSwapStart = true;
+ } else if (event.mNode.mEndTime == event.mNode.mStartTime
+ + event.mNode.mAnimation.getStartDelay()) {
+ // Swapping start delay
+ needToSwapStart = false;
+ } else {
+ i++;
+ continue;
+ }
+
+ int startEventId = eventSize;
+ int startDelayEndId = eventSize;
+ for (int j = i + 1; j < eventSize; j++) {
+ if (startEventId < eventSize && startDelayEndId < eventSize) {
+ break;
+ }
+ if (mEvents.get(j).mNode == event.mNode) {
+ if (mEvents.get(j).mEvent == AnimationEvent.ANIMATION_START) {
+ // Found start event
+ startEventId = j;
+ } else if (mEvents.get(j).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ startDelayEndId = j;
+ }
+ }
+
+ }
+ if (needToSwapStart && startEventId == mEvents.size()) {
+ throw new UnsupportedOperationException("Something went wrong, no start is"
+ + "found after stop for an animation that has the same start and end"
+ + "time.");
+
+ }
+ if (startDelayEndId == mEvents.size()) {
+ throw new UnsupportedOperationException("Something went wrong, no start"
+ + "delay end is found after stop for an animation");
+
+ }
+
+ // We need to make sure start is inserted before start delay ended event,
+ // because otherwise inserting start delay ended events first would change
+ // the start event index.
+ if (needToSwapStart) {
+ AnimationEvent startEvent = mEvents.remove(startEventId);
+ mEvents.add(i, startEvent);
+ i++;
+ }
+
+ AnimationEvent startDelayEndEvent = mEvents.remove(startDelayEndId);
+ mEvents.add(i, startDelayEndEvent);
+ i += 2;
} else {
- maxEndTime = node.mEndTime > maxEndTime ? node.mEndTime : maxEndTime;
+ i++;
}
}
- mTotalDuration = maxEndTime;
+
+ if (!mEvents.isEmpty() && mEvents.get(0).mEvent != AnimationEvent.ANIMATION_START) {
+ throw new UnsupportedOperationException(
+ "Sorting went bad, the start event should always be at index 0");
+ }
+
+ // Add AnimatorSet's start delay node to the beginning
+ mEvents.add(0, new AnimationEvent(mRootNode, AnimationEvent.ANIMATION_START));
+ mEvents.add(1, new AnimationEvent(mRootNode, AnimationEvent.ANIMATION_DELAY_ENDED));
+ mEvents.add(2, new AnimationEvent(mRootNode, AnimationEvent.ANIMATION_END));
+
+ if (mEvents.get(mEvents.size() - 1).mEvent == AnimationEvent.ANIMATION_START
+ || mEvents.get(mEvents.size() - 1).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ throw new UnsupportedOperationException(
+ "Something went wrong, the last event is not an end event");
+ }
}
/**
@@ -1235,6 +1732,95 @@ public final class AnimatorSet extends Animator {
}
/**
+ * This class is a wrapper around a node and an event for the animation corresponding to the
+ * node. The 3 types of events represent the start of an animation, the end of a start delay of
+ * an animation, and the end of an animation. When playing forward (i.e. in the non-reverse
+ * direction), start event marks when start() should be called, and end event corresponds to
+ * when the animation should finish. When playing in reverse, start delay will not be a part
+ * of the animation. Therefore, reverse() is called at the end event, and animation should end
+ * at the delay ended event.
+ */
+ private static class AnimationEvent {
+ static final int ANIMATION_START = 0;
+ static final int ANIMATION_DELAY_ENDED = 1;
+ static final int ANIMATION_END = 2;
+ final Node mNode;
+ final int mEvent;
+
+ AnimationEvent(Node node, int event) {
+ mNode = node;
+ mEvent = event;
+ }
+
+ long getTime() {
+ if (mEvent == ANIMATION_START) {
+ return mNode.mStartTime;
+ } else if (mEvent == ANIMATION_DELAY_ENDED) {
+ return mNode.mStartTime + mNode.mAnimation.getStartDelay();
+ } else {
+ return mNode.mEndTime;
+ }
+ }
+
+ public String toString() {
+ String eventStr = mEvent == ANIMATION_START ? "start" : (
+ mEvent == ANIMATION_DELAY_ENDED ? "delay ended" : "end");
+ return eventStr + " " + mNode.mAnimation.toString();
+ }
+ }
+
+ private class SeekState {
+ private long mPlayTime = -1;
+ private boolean mSeekingInReverse = false;
+ void reset() {
+ mPlayTime = -1;
+ mSeekingInReverse = false;
+ }
+
+ void setPlayTime(long playTime, boolean inReverse) {
+ // TODO: This can be simplified.
+
+ // Clamp the play time
+ if (getTotalDuration() != DURATION_INFINITE) {
+ mPlayTime = Math.min(playTime, getTotalDuration() - mStartDelay);
+ }
+ mPlayTime = Math.max(0, mPlayTime);
+ mSeekingInReverse = inReverse;
+ }
+
+ void updateSeekDirection(boolean inReverse) {
+ // Change seek direction without changing the overall fraction
+ if (inReverse && getTotalDuration() == DURATION_INFINITE) {
+ throw new UnsupportedOperationException("Error: Cannot reverse infinite animator"
+ + " set");
+ }
+ if (mPlayTime >= 0) {
+ if (inReverse != mSeekingInReverse) {
+ mPlayTime = getTotalDuration() - mStartDelay - mPlayTime;
+ }
+ }
+ }
+
+ long getPlayTime() {
+ return mPlayTime;
+ }
+
+ /**
+ * Returns the playtime assuming the animation is forward playing
+ */
+ long getPlayTimeNormalized() {
+ if (mReversing) {
+ return getTotalDuration() - mStartDelay - mPlayTime;
+ }
+ return mPlayTime;
+ }
+
+ boolean isActive() {
+ return mPlayTime != -1;
+ }
+ }
+
+ /**
* The <code>Builder</code> object is a utility class to facilitate adding animations to a
* <code>AnimatorSet</code> along with the relationships between the various animations. The
* intention of the <code>Builder</code> methods, along with the {@link
@@ -1328,7 +1914,6 @@ public final class AnimatorSet extends Animator {
* {@link AnimatorSet#play(Animator)} method ends.
*/
public Builder before(Animator anim) {
- mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addChild(node);
return this;
@@ -1343,7 +1928,6 @@ public final class AnimatorSet extends Animator {
* {@link AnimatorSet#play(Animator)} method to play.
*/
public Builder after(Animator anim) {
- mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addParent(node);
return this;
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 4707bed3ee14..1e1f1554d3a2 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -992,6 +992,11 @@ public final class ObjectAnimator extends ValueAnimator {
}
@Override
+ boolean isInitialized() {
+ return mInitialized;
+ }
+
+ @Override
public ObjectAnimator clone() {
final ObjectAnimator anim = (ObjectAnimator) super.clone();
return anim;
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f0fc8af9d504..558fdc6e52fb 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -24,6 +24,7 @@ import android.os.Trace;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
@@ -90,7 +91,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
*
* Whenever mStartTime is set, you must also update mStartTimeCommitted.
*/
- long mStartTime;
+ long mStartTime = -1;
/**
* When true, the start time has been firmly committed as a chosen reference point in
@@ -152,7 +153,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* Tracks the time (in milliseconds) when the last frame arrived.
*/
- private long mLastFrameTime = 0;
+ private long mLastFrameTime = -1;
+
+ /**
+ * Tracks the time (in milliseconds) when the first frame arrived. Note the frame may arrive
+ * during the start delay.
+ */
+ private long mFirstFrameTime = -1;
/**
* Additional playing state to indicate whether an animator has been start()'d. There is
@@ -212,6 +219,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
private int mRepeatMode = RESTART;
/**
+ * Whether or not the animator should register for its own animation callback to receive
+ * animation pulse.
+ */
+ private boolean mSelfPulse = true;
+
+ /**
+ * Whether or not the animator has been requested to start without pulsing. This flag gets set
+ * in startWithoutPulsing(), and reset in start().
+ */
+ private boolean mSuppressSelfPulseRequested = false;
+
+ /**
* The time interpolator to be used. The elapsed fraction of the animation will be passed
* through this interpolator to calculate the interpolated fraction, which is then used to
* calculate the animated values.
@@ -618,17 +637,20 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
public void setCurrentFraction(float fraction) {
initAnimation();
fraction = clampFraction(fraction);
- long seekTime = (long) (getScaledDuration() * fraction);
- long currentTime = AnimationUtils.currentAnimationTimeMillis();
- mStartTime = currentTime - seekTime;
mStartTimeCommitted = true; // do not allow start time to be compensated for jank
- if (!isPulsingInternal()) {
- // If the animation loop hasn't started, the startTime will be adjusted in the first
- // frame based on seek fraction.
+ if (isPulsingInternal()) {
+ long seekTime = (long) (getScaledDuration() * fraction);
+ long currentTime = AnimationUtils.currentAnimationTimeMillis();
+ // Only modify the start time when the animation is running. Seek fraction will ensure
+ // non-running animations skip to the correct start time.
+ mStartTime = currentTime - seekTime;
+ } else {
+ // If the animation loop hasn't started, or during start delay, the startTime will be
+ // adjusted once the delay has passed based on seek fraction.
mSeekFraction = fraction;
}
mOverallFraction = fraction;
- final float currentIterationFraction = getCurrentIterationFraction(fraction);
+ final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
animateValue(currentIterationFraction);
}
@@ -654,11 +676,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* should be played backwards. E.g. When the animation is played backwards in an iteration,
* the fraction for that iteration will go from 1f to 0f.
*/
- private float getCurrentIterationFraction(float fraction) {
+ private float getCurrentIterationFraction(float fraction, boolean inReverse) {
fraction = clampFraction(fraction);
int iteration = getCurrentIteration(fraction);
float currentFraction = fraction - iteration;
- return shouldPlayBackward(iteration) ? 1f - currentFraction : currentFraction;
+ return shouldPlayBackward(iteration, inReverse) ? 1f - currentFraction : currentFraction;
}
/**
@@ -682,18 +704,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* whether the entire animation is being reversed, 2) repeat mode applied to the current
* iteration.
*/
- private boolean shouldPlayBackward(int iteration) {
+ private boolean shouldPlayBackward(int iteration, boolean inReverse) {
if (iteration > 0 && mRepeatMode == REVERSE &&
(iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
// if we were seeked to some other iteration in a reversing animator,
// figure out the correct direction to start playing based on the iteration
- if (mReversing) {
+ if (inReverse) {
return (iteration % 2) == 0;
} else {
return (iteration % 2) != 0;
}
} else {
- return mReversing;
+ return inReverse;
}
}
@@ -965,7 +987,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
(ArrayList<AnimatorListener>) mListeners.clone();
int numListeners = tmpListeners.size();
for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationStart(this);
+ tmpListeners.get(i).onAnimationStart(this, mReversing);
}
}
mStartListenersCalled = true;
@@ -989,6 +1011,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
+ mSelfPulse = !mSuppressSelfPulseRequested;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
if (mRepeatCount == INFINITE) {
@@ -1006,11 +1029,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
// Resets mLastFrameTime when start() is called, so that if the animation was running,
// calling start() would put the animation in the
// started-but-not-yet-reached-the-first-frame phase.
- mLastFrameTime = 0;
- AnimationHandler animationHandler = AnimationHandler.getInstance();
- animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
+ mLastFrameTime = -1;
+ mFirstFrameTime = -1;
+ addAnimationCallback(0);
- if (mStartDelay == 0 || mSeekFraction >= 0) {
+ if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// If there's no start delay, init the animation and notify start listeners right away
// to be consistent with the previous behavior. Otherwise, postpone this until the first
// frame after the start delay.
@@ -1026,6 +1049,16 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
}
}
+ void startWithoutPulsing(boolean inReverse) {
+ mSuppressSelfPulseRequested = true;
+ if (inReverse) {
+ reverse();
+ } else {
+ start();
+ }
+ mSuppressSelfPulseRequested = false;
+ }
+
@Override
public void start() {
start(false);
@@ -1073,7 +1106,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
} else if (!mInitialized) {
initAnimation();
}
- animateValue(shouldPlayBackward(mRepeatCount) ? 0f : 1f);
+ animateValue(shouldPlayBackward(mRepeatCount, mReversing) ? 0f : 1f);
endAnimation();
}
@@ -1086,8 +1119,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (mPaused && !mResumed) {
mResumed = true;
if (mPauseTime > 0) {
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.addAnimationFrameCallback(this, 0);
+ addAnimationCallback(0);
}
}
super.resume();
@@ -1153,8 +1185,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (mAnimationEndRequested) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.removeCallback(this);
+ removeAnimationCallback();
mAnimationEndRequested = true;
mPaused = false;
@@ -1166,16 +1197,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mRunning = false;
mStarted = false;
mStartListenersCalled = false;
+ mLastFrameTime = -1;
+ mFirstFrameTime = -1;
mReversing = false;
- mLastFrameTime = 0;
if (notify && mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
int numListeners = tmpListeners.size();
for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(this);
+ tmpListeners.get(i).onAnimationEnd(this, mReversing);
}
}
+ mReversing = false;
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
System.identityHashCode(this));
@@ -1211,7 +1244,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* is called (or after start delay if any), which may be before the animation loop starts.
*/
private boolean isPulsingInternal() {
- return mLastFrameTime > 0;
+ return mLastFrameTime >= 0;
}
/**
@@ -1276,24 +1309,121 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
done = true;
}
mOverallFraction = clampFraction(fraction);
- float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
+ float currentIterationFraction = getCurrentIterationFraction(
+ mOverallFraction, mReversing);
animateValue(currentIterationFraction);
}
return done;
}
/**
+ * Internal use only.
+ *
+ * This method does not modify any fields of the animation. It should be called when seeking
+ * in an AnimatorSet. When the last play time and current play time are of different repeat
+ * iterations,
+ * {@link android.view.animation.Animation.AnimationListener#onAnimationRepeat(Animation)}
+ * will be called.
+ */
+ @Override
+ void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {
+ if (currentPlayTime < 0 || lastPlayTime < 0) {
+ throw new UnsupportedOperationException("Error: Play time should never be negative.");
+ }
+
+ initAnimation();
+ // Check whether repeat callback is needed only when repeat count is non-zero
+ if (mRepeatCount > 0) {
+ int iteration = (int) (currentPlayTime / mDuration);
+ int lastIteration = (int) (lastPlayTime / mDuration);
+
+ // Clamp iteration to [0, mRepeatCount]
+ iteration = Math.min(iteration, mRepeatCount);
+ lastIteration = Math.min(lastIteration, mRepeatCount);
+
+ if (iteration != lastIteration) {
+ if (mListeners != null) {
+ int numListeners = mListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ mListeners.get(i).onAnimationRepeat(this);
+ }
+ }
+ }
+ }
+
+ if (mRepeatCount != INFINITE && currentPlayTime >= (mRepeatCount + 1) * mDuration) {
+ skipToEndValue(inReverse);
+ } else {
+ // Find the current fraction:
+ float fraction = currentPlayTime / (float) mDuration;
+ fraction = getCurrentIterationFraction(fraction, inReverse);
+ animateValue(fraction);
+ }
+ }
+
+ /**
+ * Internal use only.
+ * Skips the animation value to end/start, depending on whether the play direction is forward
+ * or backward.
+ *
+ * @param inReverse whether the end value is based on a reverse direction. If yes, this is
+ * equivalent to skip to start value in a forward playing direction.
+ */
+ void skipToEndValue(boolean inReverse) {
+ initAnimation();
+ float endFraction = inReverse ? 0f : 1f;
+ if (mRepeatCount % 2 == 1 && mRepeatMode == REVERSE) {
+ // This would end on fraction = 0
+ endFraction = 0f;
+ }
+ animateValue(endFraction);
+ }
+
+ @Override
+ boolean isInitialized() {
+ return mInitialized;
+ }
+
+ /**
* Processes a frame of the animation, adjusting the start time if needed.
*
* @param frameTime The frame time.
* @return true if the animation has ended.
* @hide
*/
- public final void doAnimationFrame(long frameTime) {
- AnimationHandler handler = AnimationHandler.getInstance();
- if (mLastFrameTime == 0) {
+ public final boolean doAnimationFrame(long frameTime) {
+ if (!mRunning && mStartTime < 0) {
+ // First frame during delay
+ mStartTime = frameTime + mStartDelay;
+ }
+
+ // Handle pause/resume
+ if (mPaused) {
+ mPauseTime = frameTime;
+ removeAnimationCallback();
+ return false;
+ } else if (mResumed) {
+ mResumed = false;
+ if (mPauseTime > 0) {
+ // Offset by the duration that the animation was paused
+ mStartTime += (frameTime - mPauseTime);
+ }
+ }
+
+ if (!mRunning) {
+ // If not running, that means the animation is in the start delay phase. In the case of
+ // reversing, we want to run start delay in the end.
+ if (mStartTime > frameTime) {
+ // During start delay
+ return false;
+ } else {
+ // Start delay has passed.
+ mRunning = true;
+ }
+ }
+
+ if (mLastFrameTime < 0) {
// First frame
- handler.addOneShotCommitCallback(this);
if (mStartDelay > 0) {
startAnimation();
}
@@ -1307,19 +1437,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mStartTimeCommitted = false; // allow start time to be compensated for jank
}
mLastFrameTime = frameTime;
- if (mPaused) {
- mPauseTime = frameTime;
- handler.removeCallback(this);
- return;
- } else if (mResumed) {
- mResumed = false;
- if (mPauseTime > 0) {
- // Offset by the duration that the animation was paused
- mStartTime += (frameTime - mPauseTime);
- mStartTimeCommitted = false; // allow start time to be compensated for jank
- }
- handler.addOneShotCommitCallback(this);
- }
// The frame time might be before the start time during the first frame of
// an animation. The "current time" must always be on or after the start
// time to avoid animating frames at negative time intervals. In practice, this
@@ -1330,6 +1447,45 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (finished) {
endAnimation();
}
+ return finished;
+ }
+
+ @Override
+ boolean pulseAnimationFrame(long frameTime) {
+ if (mSelfPulse) {
+ // Pulse animation frame will *always* be after calling start(). If mSelfPulse isn't
+ // set to false at this point, that means child animators did not call super's start().
+ // This can happen when the Animator is just a non-animating wrapper around a real
+ // functional animation. In this case, we can't really pulse a frame into the animation,
+ // because the animation cannot necessarily be properly initialized (i.e. no start/end
+ // values set).
+ return false;
+ }
+ return doAnimationFrame(frameTime);
+ }
+
+ private void addOneShotCommitCallback() {
+ if (!mSelfPulse) {
+ return;
+ }
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.addOneShotCommitCallback(this);
+ }
+
+ private void removeAnimationCallback() {
+ if (!mSelfPulse) {
+ return;
+ }
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.removeCallback(this);
+ }
+
+ private void addAnimationCallback(long delay) {
+ if (!mSelfPulse) {
+ return;
+ }
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.addAnimationFrameCallback(this, delay);
}
/**
@@ -1384,13 +1540,16 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
anim.mPaused = false;
anim.mResumed = false;
anim.mStartListenersCalled = false;
- anim.mStartTime = 0;
+ anim.mStartTime = -1;
anim.mStartTimeCommitted = false;
anim.mAnimationEndRequested = false;
- anim.mPauseTime = 0;
- anim.mLastFrameTime = 0;
+ anim.mPauseTime = -1;
+ anim.mLastFrameTime = -1;
+ anim.mFirstFrameTime = -1;
anim.mOverallFraction = 0;
anim.mCurrentFraction = 0;
+ anim.mSelfPulse = true;
+ anim.mSuppressSelfPulseRequested = false;
PropertyValuesHolder[] oldValues = mValues;
if (oldValues != null) {
diff --git a/core/java/android/annotation/FontRes.java b/core/java/android/annotation/FontRes.java
new file mode 100644
index 000000000000..dbacb5876dce
--- /dev/null
+++ b/core/java/android/annotation/FontRes.java
@@ -0,0 +1,37 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that an integer parameter, field or method return value is expected
+ * to be a Font resource reference (e.g. R.font.myfont).
+ *
+ * @hide
+ */
+@Documented
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface FontRes {
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a9d1cf6e490f..6a1e74e053e2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -49,7 +49,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -74,8 +73,6 @@ import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillAppCallback;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -116,10 +113,8 @@ import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
-import android.view.autofill.AutoFillId;
-import android.view.autofill.Dataset;
-import android.view.autofill.DatasetField;
-import android.view.autofill.VirtualViewDelegate;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillSession;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -128,7 +123,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -848,10 +842,7 @@ public class Activity extends ContextThemeWrapper
private boolean mHasCurrentPermissionsRequest;
@GuardedBy("this")
- private WeakReference<IAutoFillAppCallback> mAutoFillCallback;
-
- @GuardedBy("this")
- private VirtualViewDelegate.Callback mAutoFillDelegateCallback;
+ private AutoFillSession mAutoFillSession;
private static native String getDlWarning();
@@ -1704,76 +1695,22 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Lazily sets the {@link #mAutoFillDelegateCallback}.
- */
- private void setAutoFillDelegateCallback() {
- synchronized (this) {
- if (mAutoFillDelegateCallback == null) {
- mAutoFillDelegateCallback = new VirtualViewDelegate.Callback() {
- // TODO(b/33197203): implement
- };
- }
- }
- }
-
- /**
- * Lazily gets the {@link IAutoFillAppCallback} for this activitity.
- *
- * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields.
+ * Lazily attachs the activity to the current {@link AutoFillSession} (if any).
*/
- WeakReference<IAutoFillAppCallback> getAutoFillCallback() {
+ void attachToAutoFillSession() {
synchronized (this) {
- if (mAutoFillCallback == null) {
- final IAutoFillAppCallback cb = new IAutoFillAppCallback.Stub() {
- @Override
- public void autoFill(Dataset dataset) throws RemoteException {
- // TODO(b/33197203): must keep the dataset so subsequent calls pass the same
- // dataset.extras to service
- runOnUiThread(() -> {
- final View root = getWindow().getDecorView().getRootView();
- for (DatasetField field : dataset.getFields()) {
- final AutoFillId id = field.getId();
- if (id == null) {
- Log.w(TAG, "autoFill(): null id on " + field);
- continue;
- }
- final int viewId = id.getViewId();
- final View view = root.findViewByAccessibilityIdTraversal(viewId);
- if (view == null) {
- Log.w(TAG, "autoFill(): no View with id " + viewId);
- continue;
- }
-
- // TODO(b/33197203): handle protected value (like credit card)
- if (id.isVirtual()) {
- // Delegate virtual fields to provider.
- setAutoFillDelegateCallback();
- final VirtualViewDelegate mgr = view
- .getAutoFillVirtualViewDelegate(
- mAutoFillDelegateCallback);
- if (mgr == null) {
- Log.w(TAG, "autoFill(): cannot fill virtual " + id
- + "; no auto-fill provider for view "
- + view.getClass());
- continue;
- }
- if (DEBUG_AUTO_FILL) {
- Log.d(TAG, "autoFill(): delegating " + id
- + " to virtual manager " + mgr);
- }
- mgr.autoFill(id.getVirtualChildId(), field.getValue());
- } else {
- // Handle non-virtual fields itself.
- view.autoFill(field.getValue());
- }
- }
- });
+ if (mAutoFillSession == null) {
+ final AutoFillManager afm = getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ mAutoFillSession = afm.getSession();
+ if (mAutoFillSession != null) {
+ mAutoFillSession.attachActivity(this);
+ } else {
+ Log.w(TAG, "attachToAutoFillSession(): not in a session");
}
- };
- mAutoFillCallback = new WeakReference<IAutoFillAppCallback>(cb);
+ }
}
}
- return mAutoFillCallback;
}
/**
@@ -1861,6 +1798,10 @@ public class Activity extends ContextThemeWrapper
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
mCalled = true;
+ if (mAutoFillSession != null && isFinishing()) {
+ mAutoFillSession.finishSession();
+ mAutoFillSession = null;
+ }
}
/**
@@ -3108,7 +3049,7 @@ public class Activity extends ContextThemeWrapper
*/
@Override
public void enterPictureInPictureModeIfPossible() {
- if (mActivityInfo.resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE) {
+ if (mActivityInfo.supportsPictureInPicture()) {
enterPictureInPictureMode();
}
}
@@ -4330,7 +4271,7 @@ public class Activity extends ContextThemeWrapper
* @param requestCode If >= 0, this code will be returned in
* onActivityResult() when the activity exits.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws android.content.ActivityNotFoundException
@@ -4389,6 +4330,18 @@ public class Activity extends ContextThemeWrapper
}
}
+ /**
+ * Returns whether there are any activity transitions currently running on this
+ * activity. A return value of {@code true} can mean that either an enter or
+ * exit transition is running, including whether the background of the activity
+ * is animating as a part of that transition.
+ *
+ * @return true if a transition is currently running on this activity, false otherwise.
+ */
+ public boolean isActivityTransitionRunning() {
+ return mActivityTransitionState.isTransitionRunning();
+ }
+
private Bundle transferSpringboardActivityOptions(Bundle options) {
if (options == null && (mWindow != null && !mWindow.isActive())) {
final ActivityOptions activityOptions = getActivityOptions();
@@ -4539,7 +4492,7 @@ public class Activity extends ContextThemeWrapper
* <var>flagsMask</var>
* @param extraFlags Always set to 0.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details. If options
* have also been supplied by the IntentSender, options given here will
* override any that conflict with those given by the IntentSender.
@@ -4624,7 +4577,7 @@ public class Activity extends ContextThemeWrapper
*
* @param intent The intent to start.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws android.content.ActivityNotFoundException
@@ -4673,7 +4626,7 @@ public class Activity extends ContextThemeWrapper
*
* @param intents The intents to start.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws android.content.ActivityNotFoundException
@@ -4722,7 +4675,7 @@ public class Activity extends ContextThemeWrapper
* <var>flagsMask</var>
* @param extraFlags Always set to 0.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details. If options
* have also been supplied by the IntentSender, options given here will
* override any that conflict with those given by the IntentSender.
@@ -4782,7 +4735,7 @@ public class Activity extends ContextThemeWrapper
* onActivityResult() when the activity exits, as described in
* {@link #startActivityForResult}.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @return If a new activity was launched then true is returned; otherwise
@@ -4859,7 +4812,7 @@ public class Activity extends ContextThemeWrapper
* your own activity; the only changes you can make are to the extras
* inside of it.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @return Returns a boolean indicating whether there was another Activity
@@ -4914,7 +4867,7 @@ public class Activity extends ContextThemeWrapper
* @param intent The intent to start.
* @param requestCode Reply request code. < 0 if reply is not requested.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws android.content.ActivityNotFoundException
@@ -4967,7 +4920,7 @@ public class Activity extends ContextThemeWrapper
* @param intent The intent to start.
* @param requestCode Reply request code. < 0 if reply is not requested.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws android.content.ActivityNotFoundException
@@ -6067,9 +6020,9 @@ public class Activity extends ContextThemeWrapper
getWindow().peekDecorView().getViewRootImpl().dump(prefix, fd, writer, args);
}
- if (mAutoFillCallback != null) {
- writer.print(prefix); writer.print("mAutoFillCallback: " );
- writer.println(mAutoFillCallback.get());
+ if (mAutoFillSession!= null) {
+ writer.print(prefix); writer.print("mAutoFillSession: " );
+ writer.println(mAutoFillSession);
}
mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
@@ -6792,6 +6745,8 @@ public class Activity extends ContextThemeWrapper
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
+
+ mWindow.setColorMode(info.colorMode);
}
/** @hide */
@@ -7159,7 +7114,7 @@ public class Activity extends ContextThemeWrapper
*
* @return True if caption is displayed on content, false if it pushes the content down.
*
- * @see {@link #setOverlayWithDecorCaptionEnabled(boolean)}
+ * @see #setOverlayWithDecorCaptionEnabled(boolean)
*/
public boolean isOverlayWithDecorCaptionEnabled() {
return mWindow.isOverlayWithDecorCaptionEnabled();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c1a888d28428..5b05d581c4e0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -133,7 +133,7 @@ public class ActivityManager {
public final static boolean ENABLE_TASK_SNAPSHOTS;
static {
- ENABLE_TASK_SNAPSHOTS = SystemProperties.getBoolean("persist.enable_task_snapshots", false);
+ ENABLE_TASK_SNAPSHOTS = SystemProperties.getBoolean("persist.enable_task_snapshots", true);
}
static final class UidObserver extends IUidObserver.Stub {
@@ -505,9 +505,6 @@ public class ActivityManager {
/** @hide requestType for assist context: generate full AssistStructure for auto-fill. */
public static final int ASSIST_CONTEXT_AUTO_FILL = 2;
- /** @hide requestType for assist context: generate full AssistStructure for auto-fill save. */
- public static final int ASSIST_CONTEXT_AUTO_FILL_SAVE = 3;
-
/** @hide Flag for registerUidObserver: report changes in process state. */
public static final int UID_OBSERVER_PROCSTATE = 1<<0;
@@ -698,6 +695,13 @@ public class ActivityManager {
}
/**
+ * Returns true if the input stack is affected by drag resizing.
+ */
+ public static boolean isStackAffectedByDragResizing(int stackId) {
+ return isStaticStack(stackId) && stackId != PINNED_STACK_ID;
+ }
+
+ /**
* Returns true if the windows of tasks being moved to the target stack from the source
* stack should be replaced, meaning that window manager will keep the old window around
* until the new is ready.
@@ -1482,7 +1486,7 @@ public class ActivityManager {
* True if the task can go in the docked stack.
* @hide
*/
- public boolean isDockable;
+ public boolean supportsSplitScreenMultiWindow;
/**
* The resize mode of the task. See {@link ActivityInfo#resizeMode}.
@@ -1533,7 +1537,7 @@ public class ActivityManager {
} else {
dest.writeInt(0);
}
- dest.writeInt(isDockable ? 1 : 0);
+ dest.writeInt(supportsSplitScreenMultiWindow ? 1 : 0);
dest.writeInt(resizeMode);
}
@@ -1557,7 +1561,7 @@ public class ActivityManager {
numActivities = source.readInt();
bounds = source.readInt() > 0 ?
Rect.CREATOR.createFromParcel(source) : null;
- isDockable = source.readInt() == 1;
+ supportsSplitScreenMultiWindow = source.readInt() == 1;
resizeMode = source.readInt();
}
@@ -1745,7 +1749,7 @@ public class ActivityManager {
* True if the task can go in the docked stack.
* @hide
*/
- public boolean isDockable;
+ public boolean supportsSplitScreenMultiWindow;
/**
* The resize mode of the task. See {@link ActivityInfo#resizeMode}.
@@ -1775,7 +1779,7 @@ public class ActivityManager {
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
dest.writeInt(numActivities);
dest.writeInt(numRunning);
- dest.writeInt(isDockable ? 1 : 0);
+ dest.writeInt(supportsSplitScreenMultiWindow ? 1 : 0);
dest.writeInt(resizeMode);
}
@@ -1792,7 +1796,7 @@ public class ActivityManager {
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
numActivities = source.readInt();
numRunning = source.readInt();
- isDockable = source.readInt() != 0;
+ supportsSplitScreenMultiWindow = source.readInt() != 0;
resizeMode = source.readInt();
}
@@ -2333,13 +2337,13 @@ public class ActivityManager {
public static final int FLAG_FOREGROUND = 1<<1;
/**
- * Bit for {@link #flags): set if the service is running in a
+ * Bit for {@link #flags}: set if the service is running in a
* core system process.
*/
public static final int FLAG_SYSTEM_PROCESS = 1<<2;
/**
- * Bit for {@link #flags): set if the service is running in a
+ * Bit for {@link #flags}: set if the service is running in a
* persistent process.
*/
public static final int FLAG_PERSISTENT_PROCESS = 1<<3;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 04510da81e4a..0b9479d8b52e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -33,6 +33,7 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.util.Pair;
import android.util.Slog;
@@ -1342,7 +1343,7 @@ public class ActivityOptions {
+ mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
}
- private static class HideWindowListener extends Transition.TransitionListenerAdapter
+ private static class HideWindowListener extends TransitionListenerAdapter
implements ExitTransitionCoordinator.HideSharedElementsCallback {
private final Window mWindow;
private final ExitTransitionCoordinator mExit;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d814ddcc7f27..dffd81fbbcab 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -91,7 +91,6 @@ import android.security.NetworkSecurityPolicy;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.service.autofill.AutoFillService;
import android.service.autofill.IAutoFillAppCallback;
-import android.service.voice.VoiceInteractionSession;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -541,6 +540,7 @@ public final class ActivityThread {
ParcelFileDescriptor profileFd;
int samplingInterval;
boolean autoStopProfiler;
+ boolean streamingOutput;
boolean profiling;
boolean handlingProfiling;
public void setProfiler(ProfilerInfo profilerInfo) {
@@ -566,6 +566,7 @@ public final class ActivityThread {
profileFd = fd;
samplingInterval = profilerInfo.samplingInterval;
autoStopProfiler = profilerInfo.autoStopProfiler;
+ streamingOutput = profilerInfo.streamingOutput;
}
public void startProfiling() {
if (profileFd == null || profiling) {
@@ -574,7 +575,8 @@ public final class ActivityThread {
try {
int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8);
VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(),
- bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval);
+ bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval,
+ streamingOutput);
profiling = true;
} catch (RuntimeException e) {
Slog.w(TAG, "Profiling failed on path " + profileFile);
@@ -638,7 +640,6 @@ public final class ActivityThread {
IBinder requestToken;
int requestType;
int sessionId;
- int flags;
}
static final class ActivityConfigChangeData {
@@ -1246,13 +1247,12 @@ public final class ActivityThread {
@Override
public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId, int flags) {
+ int requestType, int sessionId) {
RequestAssistContextExtras cmd = new RequestAssistContextExtras();
cmd.activityToken = activityToken;
cmd.requestToken = requestToken;
cmd.requestType = requestType;
cmd.sessionId = sessionId;
- cmd.flags = flags;
sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
}
@@ -2616,9 +2616,10 @@ public final class ActivityThread {
r.activityInfo.targetActivity);
}
+ ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
- java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
+ java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
@@ -2647,7 +2648,6 @@ public final class ActivityThread {
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
- Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
@@ -2661,6 +2661,7 @@ public final class ActivityThread {
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
+ appContext.setOuterContext(activity);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
@@ -2736,8 +2737,8 @@ public final class ActivityThread {
return activity;
}
- private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
- int displayId = Display.DEFAULT_DISPLAY;
+ private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
+ final int displayId;
try {
displayId = ActivityManager.getService().getActivityDisplayId(r.token);
} catch (RemoteException e) {
@@ -2745,9 +2746,7 @@ public final class ActivityThread {
}
ContextImpl appContext = ContextImpl.createActivityContext(
- this, r.packageInfo, r.token, displayId, r.overrideConfig);
- appContext.setOuterContext(activity);
- Context baseContext = appContext;
+ this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
@@ -2760,12 +2759,12 @@ public final class ActivityThread {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
- baseContext = appContext.createDisplayContext(display);
+ appContext = (ContextImpl) appContext.createDisplayContext(display);
break;
}
}
}
- return baseContext;
+ return appContext;
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
@@ -2903,9 +2902,7 @@ public final class ActivityThread {
// - it does not need an AssistContent
// - it does not call onProvideAssistData()
// - it needs an IAutoFillCallback
- // - it sets the flags so views can provide autofill-specific data (such as passwords)
- boolean forAutoFill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL
- || cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
+ boolean forAutoFill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL;
// TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
if (mLastSessionId != cmd.sessionId) {
@@ -2932,12 +2929,9 @@ public final class ActivityThread {
referrer = r.activity.onProvideReferrer();
}
if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
- structure = new AssistStructure(r.activity, cmd.flags);
+ structure = new AssistStructure(r.activity, forAutoFill);
Intent activityIntent = r.activity.getIntent();
- if (forAutoFill) {
- data.putInt(VoiceInteractionSession.KEY_FLAGS, cmd.flags);
- }
- boolean addAutoFillCallback = false;
+ boolean attachToSession = false;
// TODO(b/33197203): re-evaluate conditions below for auto-fill. In particular,
// FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
boolean notSecure = r.window == null ||
@@ -2945,7 +2939,7 @@ public final class ActivityThread {
& WindowManager.LayoutParams.FLAG_SECURE) == 0;
if (activityIntent != null && notSecure) {
if (forAutoFill) {
- addAutoFillCallback = true;
+ attachToSession = true;
} else {
Intent intent = new Intent(activityIntent);
intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -2959,24 +2953,20 @@ public final class ActivityThread {
} else {
// activityIntent is unlikely to be null, but if it is, we should still
// set the auto-fill callback.
- addAutoFillCallback = notSecure;
+ attachToSession = notSecure;
}
}
if (!forAutoFill) {
r.activity.onProvideAssistContent(content);
- } else if (addAutoFillCallback) {
- IAutoFillAppCallback cb = r.activity.getAutoFillCallback().get();
- if (cb != null) {
- data.putBinder(AutoFillService.KEY_CALLBACK, cb.asBinder());
- } else {
- Slog.w(TAG, "handleRequestAssistContextExtras(): callback was GCed");
- }
+ } else if (attachToSession) {
+ r.activity.attachToAutoFillSession();
}
}
}
if (structure == null) {
structure = new AssistStructure();
}
+
// TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
mLastAssistStructures.add(new WeakReference<>(structure));
IActivityManager mgr = ActivityManager.getService();
@@ -3119,9 +3109,16 @@ public final class ActivityThread {
IActivityManager mgr = ActivityManager.getService();
+ Application app;
BroadcastReceiver receiver;
+ ContextImpl context;
try {
- java.lang.ClassLoader cl = packageInfo.getClassLoader();
+ app = packageInfo.makeApplication(false, mInstrumentation);
+ context = (ContextImpl) app.getBaseContext();
+ if (data.info.splitName != null) {
+ context = (ContextImpl) context.createContextForSplit(data.info.splitName);
+ }
+ java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
@@ -3136,8 +3133,6 @@ public final class ActivityThread {
}
try {
- Application app = packageInfo.makeApplication(false, mInstrumentation);
-
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
@@ -3146,7 +3141,6 @@ public final class ActivityThread {
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
- ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
receiver.onReceive(context.getReceiverRestrictedContext(),
@@ -5026,7 +5020,9 @@ public final class ActivityThread {
* @hide
*/
public void stopProfiling() {
- mProfiler.stopProfiling();
+ if (mProfiler != null) {
+ mProfiler.stopProfiling();
+ }
}
static final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
@@ -5272,6 +5268,7 @@ public final class ActivityThread {
mProfiler.profileFd = data.initProfilerInfo.profileFd;
mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
+ mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
}
// send up app name; do this *before* waiting for debugger
@@ -6031,6 +6028,15 @@ public final class ActivityThread {
info.name);
return null;
}
+
+ if (info.splitName != null) {
+ try {
+ c = c.createContextForSplit(info.splitName);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index af41db01418e..a5123504a4a1 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.Parcelable;
import android.os.ResultReceiver;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionSet;
import android.transition.Visibility;
import android.util.ArrayMap;
@@ -208,6 +209,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
private ArrayList<Matrix> mSharedElementParentMatrices;
private boolean mSharedElementTransitionComplete;
private boolean mViewsTransitionComplete;
+ private boolean mBackgroundAnimatorComplete;
private ArrayList<View> mStrippedTransitioningViews = new ArrayList<>();
public ActivityTransitionCoordinator(Window window,
@@ -884,6 +886,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
startInputWhenTransitionsComplete();
}
+ protected void backgroundAnimatorComplete() {
+ mBackgroundAnimatorComplete = true;
+ }
+
protected void sharedElementTransitionComplete() {
mSharedElementTransitionComplete = true;
startInputWhenTransitionsComplete();
@@ -911,7 +917,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
protected void onTransitionsComplete() {}
- protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
+ protected class ContinueTransitionListener extends TransitionListenerAdapter {
@Override
public void onTransitionStart(Transition transition) {
mIsStartingTransition = false;
@@ -966,6 +972,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
}
+ public boolean isTransitionRunning() {
+ return !(mViewsTransitionComplete && mSharedElementTransitionComplete &&
+ mBackgroundAnimatorComplete);
+ }
+
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index f2616ffa2465..b8f5a8e94283 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -336,6 +336,26 @@ class ActivityTransitionState {
}
}
+ public boolean isTransitionRunning() {
+ // Note that *only* enter *or* exit will be running at any given time
+ if (mEnterTransitionCoordinator != null) {
+ if (mEnterTransitionCoordinator.isTransitionRunning()) {
+ return true;
+ }
+ }
+ if (mCalledExitCoordinator != null) {
+ if (mCalledExitCoordinator.isTransitionRunning()) {
+ return true;
+ }
+ }
+ if (mReturnExitCoordinator != null) {
+ if (mReturnExitCoordinator.isTransitionRunning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void startExitOutTransition(Activity activity, Bundle options) {
mEnterTransitionCoordinator = null;
if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
diff --git a/core/java/android/app/AppImportanceMonitor.java b/core/java/android/app/AppImportanceMonitor.java
deleted file mode 100644
index b5cbeeb0d729..000000000000
--- a/core/java/android/app/AppImportanceMonitor.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.SparseArray;
-import java.util.List;
-
-/**
- * Helper for monitoring the current importance of applications.
- * @hide
- */
-public class AppImportanceMonitor {
- final Context mContext;
-
- final SparseArray<AppEntry> mApps = new SparseArray<>();
-
- static class AppEntry {
- final int uid;
- final SparseArray<Integer> procs = new SparseArray<>(1);
- int importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
-
- AppEntry(int _uid) {
- uid = _uid;
- }
- }
-
- final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
- @Override
- public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
- }
-
- @Override
- public void onProcessStateChanged(int pid, int uid, int procState) {
- synchronized (mApps) {
- updateImportanceLocked(pid, uid,
- ActivityManager.RunningAppProcessInfo.procStateToImportance(procState),
- true);
- }
- }
-
- @Override
- public void onProcessDied(int pid, int uid) {
- synchronized (mApps) {
- updateImportanceLocked(pid, uid,
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, true);
- }
- }
- };
-
- static final int MSG_UPDATE = 1;
-
- final Handler mHandler;
-
- public AppImportanceMonitor(Context context, Looper looper) {
- mContext = context;
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE:
- onImportanceChanged(msg.arg1, msg.arg2&0xffff, msg.arg2>>16);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- };
- ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
- try {
- ActivityManager.getService().registerProcessObserver(mProcessObserver);
- } catch (RemoteException e) {
- }
- List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses();
- if (apps != null) {
- for (int i=0; i<apps.size(); i++) {
- ActivityManager.RunningAppProcessInfo app = apps.get(i);
- updateImportanceLocked(app.uid, app.pid, app.importance, false);
- }
- }
- }
-
- public int getImportance(int uid) {
- AppEntry ent = mApps.get(uid);
- if (ent == null) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
- }
- return ent.importance;
- }
-
- /**
- * Report when an app's importance changed. Called on looper given to constructor.
- */
- public void onImportanceChanged(int uid, int importance, int oldImportance) {
- }
-
- void updateImportanceLocked(int uid, int pid, int importance, boolean repChange) {
- AppEntry ent = mApps.get(uid);
- if (ent == null) {
- ent = new AppEntry(uid);
- mApps.put(uid, ent);
- }
- if (importance >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) {
- ent.procs.remove(pid);
- } else {
- ent.procs.put(pid, importance);
- }
- updateImportanceLocked(ent, repChange);
- }
-
- void updateImportanceLocked(AppEntry ent, boolean repChange) {
- int appImp = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
- for (int i=0; i<ent.procs.size(); i++) {
- int procImp = ent.procs.valueAt(i);
- if (procImp < appImp) {
- appImp = procImp;
- }
- }
- if (appImp != ent.importance) {
- int impCode = appImp | (ent.importance<<16);
- ent.importance = appImp;
- if (appImp >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) {
- mApps.remove(ent.uid);
- }
- if (repChange) {
- mHandler.obtainMessage(MSG_UPDATE, ent.uid, impCode).sendToTarget();
- }
- }
- }
-}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f790542c6847..0c6c4ba33ee3 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -17,7 +17,6 @@
package android.app;
import android.annotation.DrawableRes;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
@@ -31,7 +30,7 @@ import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
-import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
@@ -310,6 +309,12 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public boolean isPermissionReviewModeEnabled() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_permissionReviewRequired);
+ }
+
+ @Override
public PermissionGroupInfo getPermissionGroupInfo(String name,
int flags) throws NameNotFoundException {
try {
@@ -760,10 +765,10 @@ public class ApplicationPackageManager extends PackageManager {
/** @hide */
@SuppressWarnings("unchecked")
@Override
- public List<EphemeralApplicationInfo> getEphemeralApplications() {
+ public List<InstantAppInfo> getInstantApps() {
try {
- ParceledListSlice<EphemeralApplicationInfo> slice =
- mPM.getEphemeralApplications(mContext.getUserId());
+ ParceledListSlice<InstantAppInfo> slice =
+ mPM.getInstantApps(mContext.getUserId());
if (slice != null) {
return slice.getList();
}
@@ -775,9 +780,9 @@ public class ApplicationPackageManager extends PackageManager {
/** @hide */
@Override
- public Drawable getEphemeralApplicationIcon(String packageName) {
+ public Drawable getInstantAppIcon(String packageName) {
try {
- Bitmap bitmap = mPM.getEphemeralApplicationIcon(
+ Bitmap bitmap = mPM.getInstantAppIcon(
packageName, mContext.getUserId());
if (bitmap != null) {
return new BitmapDrawable(null, bitmap);
@@ -789,26 +794,26 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public boolean isEphemeralApplication() {
+ public boolean isInstantApp() {
try {
- return mPM.isEphemeralApplication(
- mContext.getPackageName(), mContext.getUserId());
+ return mPM.isInstantApp(mContext.getPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
- public int getEphemeralCookieMaxSizeBytes() {
+ public int getInstantAppCookieMaxSize() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
}
@Override
- public @NonNull byte[] getEphemeralCookie() {
+ public @NonNull byte[] getInstantAppCookie() {
try {
- final byte[] cookie = mPM.getEphemeralApplicationCookie(
+ final byte[] cookie = mPM.getInstantAppCookie(
mContext.getPackageName(), mContext.getUserId());
if (cookie != null) {
return cookie;
@@ -821,10 +826,10 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public boolean setEphemeralCookie(@NonNull byte[] cookie) {
+ public boolean setInstantAppCookie(@NonNull byte[] cookie) {
try {
- return mPM.setEphemeralApplicationCookie(
- mContext.getPackageName(), cookie, mContext.getUserId());
+ return mPM.setInstantAppCookie(mContext.getPackageName(),
+ cookie, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2580,4 +2585,13 @@ public class ApplicationPackageManager extends PackageManager {
return false;
}
}
+
+ @Override
+ public boolean canRequestPackageInstalls() {
+ try {
+ return mPM.canRequestPackageInstalls(mContext.getPackageName(), mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 20a9a93b74f9..66b2355dcb6e 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -186,6 +186,8 @@ final class BackStackRecord extends FragmentTransaction implements
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
+ static final int OP_SET_PRIMARY_NAV = 8;
+ static final int OP_UNSET_PRIMARY_NAV = 9;
static final class Op {
int cmd;
@@ -194,6 +196,14 @@ final class BackStackRecord extends FragmentTransaction implements
int exitAnim;
int popEnterAnim;
int popExitAnim;
+
+ Op() {
+ }
+
+ Op(int cmd, Fragment fragment) {
+ this.cmd = cmd;
+ this.fragment = fragment;
+ }
}
ArrayList<Op> mOps = new ArrayList<>();
@@ -210,6 +220,8 @@ final class BackStackRecord extends FragmentTransaction implements
int mIndex = -1;
boolean mAllowOptimization;
+ ArrayList<Runnable> mCommitRunnables;
+
int mBreadCrumbTitleRes;
CharSequence mBreadCrumbTitleText;
int mBreadCrumbShortTitleRes;
@@ -318,6 +330,13 @@ final class BackStackRecord extends FragmentTransaction implements
case OP_ATTACH:
cmdStr = "ATTACH";
break;
+ case OP_SET_PRIMARY_NAV:
+ cmdStr="SET_PRIMARY_NAV";
+ break;
+ case OP_UNSET_PRIMARY_NAV:
+ cmdStr="UNSET_PRIMARY_NAV";
+ break;
+
default:
cmdStr = "cmd=" + op.cmd;
break;
@@ -438,10 +457,7 @@ final class BackStackRecord extends FragmentTransaction implements
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
- Op op = new Op();
- op.cmd = opcmd;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(opcmd, fragment));
}
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
@@ -458,46 +474,37 @@ final class BackStackRecord extends FragmentTransaction implements
}
public FragmentTransaction remove(Fragment fragment) {
- Op op = new Op();
- op.cmd = OP_REMOVE;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(OP_REMOVE, fragment));
return this;
}
public FragmentTransaction hide(Fragment fragment) {
- Op op = new Op();
- op.cmd = OP_HIDE;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(OP_HIDE, fragment));
return this;
}
public FragmentTransaction show(Fragment fragment) {
- Op op = new Op();
- op.cmd = OP_SHOW;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(OP_SHOW, fragment));
return this;
}
public FragmentTransaction detach(Fragment fragment) {
- Op op = new Op();
- op.cmd = OP_DETACH;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(OP_DETACH, fragment));
return this;
}
public FragmentTransaction attach(Fragment fragment) {
- Op op = new Op();
- op.cmd = OP_ATTACH;
- op.fragment = fragment;
- addOp(op);
+ addOp(new Op(OP_ATTACH, fragment));
+
+ return this;
+ }
+
+ public FragmentTransaction setPrimaryNavigationFragment(Fragment fragment) {
+ addOp(new Op(OP_SET_PRIMARY_NAV, fragment));
return this;
}
@@ -615,6 +622,28 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
+ @Override
+ public FragmentTransaction postOnCommit(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable cannot be null");
+ }
+ disallowAddToBackStack();
+ if (mCommitRunnables == null) {
+ mCommitRunnables = new ArrayList<>();
+ }
+ mCommitRunnables.add(runnable);
+ return this;
+ }
+
+ public void runOnCommitRunnables() {
+ if (mCommitRunnables != null) {
+ for (int i = 0, N = mCommitRunnables.size(); i < N; i++) {
+ mCommitRunnables.get(i).run();
+ }
+ mCommitRunnables = null;
+ }
+ }
+
public int commit() {
return commitInternal(false);
}
@@ -689,7 +718,8 @@ final class BackStackRecord extends FragmentTransaction implements
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
- if (op.fragment.mContainerId == containerId) {
+ final int fragContainer = op.fragment != null ? op.fragment.mContainerId : 0;
+ if (fragContainer != 0 && fragContainer == containerId) {
return true;
}
}
@@ -704,7 +734,7 @@ final class BackStackRecord extends FragmentTransaction implements
int lastContainer = -1;
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
- final int container = op.fragment.mContainerId;
+ final int container = op.fragment != null ? op.fragment.mContainerId : 0;
if (container != 0 && container != lastContainer) {
lastContainer = container;
for (int i = startIndex; i < endIndex; i++) {
@@ -712,7 +742,9 @@ final class BackStackRecord extends FragmentTransaction implements
final int numThoseOps = record.mOps.size();
for (int thoseOpIndex = 0; thoseOpIndex < numThoseOps; thoseOpIndex++) {
final Op thatOp = record.mOps.get(thoseOpIndex);
- if (thatOp.fragment.mContainerId == container) {
+ final int thatContainer = thatOp.fragment != null
+ ? thatOp.fragment.mContainerId : 0;
+ if (thatContainer == container) {
return true;
}
}
@@ -731,7 +763,9 @@ final class BackStackRecord extends FragmentTransaction implements
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
- f.setNextTransition(mTransition, mTransitionStyle);
+ if (f != null) {
+ f.setNextTransition(mTransition, mTransitionStyle);
+ }
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.enterAnim);
@@ -757,10 +791,16 @@ final class BackStackRecord extends FragmentTransaction implements
f.setNextAnim(op.enterAnim);
mManager.attachFragment(f);
break;
+ case OP_SET_PRIMARY_NAV:
+ mManager.setPrimaryNavigationFragment(f);
+ break;
+ case OP_UNSET_PRIMARY_NAV:
+ mManager.setPrimaryNavigationFragment(null);
+ break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
- if (!mAllowOptimization && op.cmd != OP_ADD) {
+ if (!mAllowOptimization && op.cmd != OP_ADD && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
@@ -778,7 +818,10 @@ final class BackStackRecord extends FragmentTransaction implements
for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
final Op op = mOps.get(opNum);
Fragment f = op.fragment;
- f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+ if (f != null) {
+ f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
+ mTransitionStyle);
+ }
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.popExitAnim);
@@ -804,10 +847,16 @@ final class BackStackRecord extends FragmentTransaction implements
f.setNextAnim(op.popExitAnim);
mManager.detachFragment(f);
break;
+ case OP_SET_PRIMARY_NAV:
+ mManager.setPrimaryNavigationFragment(null);
+ break;
+ case OP_UNSET_PRIMARY_NAV:
+ mManager.setPrimaryNavigationFragment(f);
+ break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
- if (!mAllowOptimization && op.cmd != OP_REMOVE) {
+ if (!mAllowOptimization && op.cmd != OP_REMOVE && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
@@ -817,15 +866,28 @@ final class BackStackRecord extends FragmentTransaction implements
}
/**
- * Removes all OP_REPLACE ops and replaces them with the proper add and remove
- * operations that are equivalent to the replace. This must be called prior to
- * {@link #executeOps()} or any other call that operations on mOps.
+ * Expands all meta-ops into their more primitive equivalents. This must be called prior to
+ * {@link #executeOps()} or any other call that operations on mOps for forward navigation.
+ * It should not be called for pop/reverse navigation operations.
+ *
+ * <p>Removes all OP_REPLACE ops and replaces them with the proper add and remove
+ * operations that are equivalent to the replace.</p>
+ *
+ * <p>Adds OP_UNSET_PRIMARY_NAV ops to match OP_SET_PRIMARY_NAV, OP_REMOVE and OP_DETACH
+ * ops so that we can restore the old primary nav fragment later. Since callers call this
+ * method in a loop before running ops from several transactions at once, the caller should
+ * pass the return value from this method as the oldPrimaryNav parameter for the next call.
+ * The first call in such a loop should pass the value of
+ * {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
*
* @param added Initialized to the fragments that are in the mManager.mAdded, this
* will be modified to contain the fragments that will be in mAdded
* after the execution ({@link #executeOps()}.
+ * @param oldPrimaryNav The tracked primary navigation fragment as of the beginning of
+ * this set of ops
+ * @return the new oldPrimaryNav fragment after this record's ops would be run
*/
- void expandReplaceOps(ArrayList<Fragment> added) {
+ Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
@@ -834,22 +896,33 @@ final class BackStackRecord extends FragmentTransaction implements
added.add(op.fragment);
break;
case OP_REMOVE:
- case OP_DETACH:
+ case OP_DETACH: {
added.remove(op.fragment);
- break;
+ if (op.fragment == oldPrimaryNav) {
+ mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
+ opNum++;
+ oldPrimaryNav = null;
+ }
+ }
+ break;
case OP_REPLACE: {
- Fragment f = op.fragment;
- int containerId = f.mContainerId;
+ final Fragment f = op.fragment;
+ final int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
- Fragment old = added.get(i);
+ final Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
- Op removeOp = new Op();
- removeOp.cmd = OP_REMOVE;
- removeOp.fragment = old;
+ // This is duplicated from above since we only make
+ // a single pass for expanding ops. Unset any outgoing primary nav.
+ if (old == oldPrimaryNav) {
+ mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
+ opNum++;
+ oldPrimaryNav = null;
+ }
+ final Op removeOp = new Op(OP_REMOVE, old);
removeOp.enterAnim = op.enterAnim;
removeOp.popEnterAnim = op.popEnterAnim;
removeOp.exitAnim = op.exitAnim;
@@ -869,8 +942,18 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
break;
+ case OP_SET_PRIMARY_NAV: {
+ // It's ok if this is null, that means we will restore to no active
+ // primary navigation fragment on a pop.
+ mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
+ opNum++;
+ // Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
+ oldPrimaryNav = op.fragment;
+ }
+ break;
}
}
+ return oldPrimaryNav;
}
/**
@@ -917,8 +1000,8 @@ final class BackStackRecord extends FragmentTransaction implements
private static boolean isFragmentPostponed(Op op) {
final Fragment fragment = op.fragment;
- return (fragment.mAdded && fragment.mView != null && !fragment.mDetached &&
- !fragment.mHidden && fragment.isPostponed());
+ return fragment != null && fragment.mAdded && fragment.mView != null && !fragment.mDetached
+ && !fragment.mHidden && fragment.isPostponed();
}
public String getName() {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d37888d76802..16989c060bc4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -32,6 +32,7 @@ import android.content.IntentSender;
import android.content.ReceiverCallNotAllowedException;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -58,21 +59,27 @@ import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.IStorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.DisplayAdjustments;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import dalvik.system.PathClassLoader;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -80,6 +87,8 @@ import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
class ReceiverRestrictedContext extends ContextWrapper {
@@ -147,6 +156,7 @@ class ContextImpl extends Context {
final ActivityThread mMainThread;
final LoadedApk mPackageInfo;
+ private ClassLoader mClassLoader;
private final IBinder mActivityToken;
@@ -272,8 +282,7 @@ class ContextImpl extends Context {
@Override
public ClassLoader getClassLoader() {
- return mPackageInfo != null ?
- mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
+ return mClassLoader != null ? mClassLoader : (mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader());
}
@Override
@@ -1901,7 +1910,8 @@ class ContextImpl extends Context {
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
- new UserHandle(UserHandle.getUserId(application.uid)), flags);
+ new UserHandle(UserHandle.getUserId(application.uid)), flags,
+ null);
final int displayId = mDisplay != null
? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
@@ -1930,13 +1940,15 @@ class ContextImpl extends Context {
if (packageName.equals("system") || packageName.equals("android")) {
// The system resources are loaded in every application, so we can safely copy
// the context without reloading Resources.
- return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, user, flags);
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, user, flags,
+ null);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
- ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, user, flags);
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, user, flags,
+ null);
final int displayId = mDisplay != null
? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
@@ -1954,13 +1966,42 @@ class ContextImpl extends Context {
}
@Override
+ public Context createContextForSplit(String splitName) throws NameNotFoundException {
+ if (!mPackageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
+ // All Splits are always loaded.
+ return this;
+ }
+
+ final ClassLoader classLoader = mPackageInfo.getSplitClassLoader(splitName);
+ final String[] paths = mPackageInfo.getSplitPaths(splitName);
+
+ final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
+ mActivityToken, mUser, mFlags, classLoader);
+
+ final int displayId = mDisplay != null
+ ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+
+ context.mResources = ResourcesManager.getInstance().getResources(
+ mActivityToken,
+ mPackageInfo.getResDir(),
+ paths,
+ mPackageInfo.getOverlayDirs(),
+ mPackageInfo.getApplicationInfo().sharedLibraryFiles,
+ displayId,
+ null,
+ mPackageInfo.getCompatibilityInfo(),
+ classLoader);
+ return context;
+ }
+
+ @Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
if (overrideConfiguration == null) {
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- mUser, mFlags);
+ mUser, mFlags, mClassLoader);
final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
context.mResources = createResources(mActivityToken, mPackageInfo, displayId,
@@ -1975,7 +2016,7 @@ class ContextImpl extends Context {
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- mUser, mFlags);
+ mUser, mFlags, mClassLoader);
final int displayId = display.getDisplayId();
context.mResources = createResources(mActivityToken, mPackageInfo, displayId, null,
@@ -1988,14 +2029,16 @@ class ContextImpl extends Context {
public Context createDeviceProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
| Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags);
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags,
+ mClassLoader);
}
@Override
public Context createCredentialProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
| Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags);
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags,
+ mClassLoader);
}
@Override
@@ -2082,8 +2125,9 @@ class ContextImpl extends Context {
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0);
- context.mResources = packageInfo.getResources(mainThread);
+ ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
+ null);
+ context.mResources = packageInfo.getResources();
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
@@ -2091,18 +2135,35 @@ class ContextImpl extends Context {
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0);
- context.mResources = packageInfo.getResources(mainThread);
+ ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
+ null);
+ context.mResources = packageInfo.getResources();
return context;
}
static ContextImpl createActivityContext(ActivityThread mainThread,
- LoadedApk packageInfo, IBinder activityToken, int displayId,
+ LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
+ String[] splitDirs = packageInfo.getSplitResDirs();
+ ClassLoader classLoader = packageInfo.getClassLoader();
+
+ if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
+ try {
+ classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
+ splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
+ } catch (NameNotFoundException e) {
+ // Nothing above us can handle a NameNotFoundException, better crash.
+ throw new RuntimeException(e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ }
+ }
+
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityToken, null,
- 0);
+ 0, classLoader);
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -2117,20 +2178,21 @@ class ContextImpl extends Context {
// will be rebased upon.
context.mResources = resourcesManager.createBaseActivityResources(activityToken,
packageInfo.getResDir(),
- packageInfo.getSplitResDirs(),
+ splitDirs,
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
- packageInfo.getClassLoader());
+ classLoader);
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
context.mResources.getDisplayAdjustments());
return context;
}
private ContextImpl(ContextImpl container, ActivityThread mainThread,
- LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags) {
+ LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
+ ClassLoader classLoader) {
mOuterContext = this;
// If creator didn't specify which storage to use, use the default
@@ -2155,6 +2217,7 @@ class ContextImpl extends Context {
mUser = user;
mPackageInfo = packageInfo;
+ mClassLoader = classLoader;
mResourcesManager = ResourcesManager.getInstance();
if (container != null) {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index b569b798eea2..445b6871ddac 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.view.View;
@@ -491,7 +492,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
sharedElementTransitionStarted();
sharedElementTransitionComplete();
} else {
- sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+ sharedElementTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionStart(Transition transition) {
sharedElementTransitionStarted();
@@ -587,20 +588,25 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
public void onAnimationEnd(Animator animation) {
makeOpaque();
+ backgroundAnimatorComplete();
}
});
mBackgroundAnimator.start();
} else if (transition != null) {
- transition.addListener(new Transition.TransitionListenerAdapter() {
+ transition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
makeOpaque();
}
});
+ backgroundAnimatorComplete();
} else {
makeOpaque();
+ backgroundAnimatorComplete();
}
+ } else {
+ backgroundAnimatorComplete();
}
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 26727988e785..29e10d81c95d 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -31,6 +31,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.ResultReceiver;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.view.View;
import android.view.ViewGroup;
@@ -161,7 +162,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private void startSharedElementExit(final ViewGroup decorView) {
Transition transition = getSharedElementExitTransition();
- transition.addListener(new Transition.TransitionListenerAdapter() {
+ transition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
@@ -201,6 +202,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
public void startExit() {
if (!mIsExitStarted) {
+ backgroundAnimatorComplete();
mIsExitStarted = true;
pauseInput();
ViewGroup decorView = getDecor();
@@ -303,11 +305,13 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
mIsBackgroundReady = true;
notifyComplete();
}
+ backgroundAnimatorComplete();
}
});
mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.start();
} else {
+ backgroundAnimatorComplete();
mIsBackgroundReady = true;
}
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 62d68981d23c..eff77b56068e 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -714,14 +714,20 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Supply the construction arguments for this fragment. This can only
- * be called before the fragment has been attached to its activity; that
- * is, you should call it immediately after constructing the fragment. The
- * arguments supplied here will be retained across fragment destroy and
+ * Supply the construction arguments for this fragment.
+ * The arguments supplied here will be retained across fragment destroy and
* creation.
+ *
+ * <p>This method cannot be called if the fragment is added to a FragmentManager and
+ * if {@link #isStateSaved()} would return true. Prior to {@link Build.VERSION_CODES#O},
+ * this method may only be called if the fragment has not yet been added to a FragmentManager.
+ * </p>
*/
public void setArguments(Bundle args) {
- if (mIndex >= 0) {
+ // The isStateSaved requirement below was only added in Android O and is compatible
+ // because it loosens previous requirements rather than making them more strict.
+ // See method javadoc.
+ if (mIndex >= 0 && isStateSaved()) {
throw new IllegalStateException("Fragment already active");
}
mArguments = args;
@@ -735,6 +741,21 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
+ * Returns true if this fragment is added and its state has already been saved
+ * by its host. Any operations that would change saved state should not be performed
+ * if this method returns true, and some operations such as {@link #setArguments(Bundle)}
+ * will fail.
+ *
+ * @return true if this fragment's state has already been saved by its host
+ */
+ public final boolean isStateSaved() {
+ if (mFragmentManager == null) {
+ return false;
+ }
+ return mFragmentManager.isStateSaved();
+ }
+
+ /**
* Set the initial saved state that this Fragment should restore itself
* from when first being constructed, as returned by
* {@link FragmentManager#saveFragmentInstanceState(Fragment)
@@ -762,6 +783,24 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* are going to call back with {@link #onActivityResult(int, int, Intent)}.
*/
public void setTargetFragment(Fragment fragment, int requestCode) {
+ // Don't allow a caller to set a target fragment in another FragmentManager,
+ // but there's a snag: people do set target fragments before fragments get added.
+ // We'll have the FragmentManager check that for validity when we move
+ // the fragments to a valid state.
+ final FragmentManager mine = getFragmentManager();
+ final FragmentManager theirs = fragment != null ? fragment.getFragmentManager() : null;
+ if (mine != null && theirs != null && mine != theirs) {
+ throw new IllegalArgumentException("Fragment " + fragment
+ + " must share the same FragmentManager to be set as a target fragment");
+ }
+
+ // Don't let someone create a cycle.
+ for (Fragment check = fragment; check != null; check = check.getTargetFragment()) {
+ if (check == this) {
+ throw new IllegalArgumentException("Setting " + fragment + " as the target of "
+ + this + " would create a target cycle");
+ }
+ }
mTarget = fragment;
mTargetRequestCode = requestCode;
}
@@ -1114,7 +1153,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*
* @param intent The intent to start.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*/
public void startActivity(Intent intent, Bundle options) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 44f1322f4b40..b7c0737487ca 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -360,6 +360,18 @@ public abstract class FragmentManager {
public abstract void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb);
/**
+ * Return the currently active primary navigation fragment for this FragmentManager.
+ *
+ * <p>The primary navigation fragment's
+ * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
+ * to process delegated navigation actions such as {@link #popBackStack()} if no ID
+ * or transaction name is provided to pop to.</p>
+ *
+ * @return the fragment designated as the primary navigation fragment
+ */
+ public abstract Fragment getPrimaryNavigationFragment();
+
+ /**
* Print the FragmentManager's state into the given stream.
*
* @param prefix Text to print at the front of each line.
@@ -524,6 +536,7 @@ final class FragmentManagerState implements Parcelable {
FragmentState[] mActive;
int[] mAdded;
BackStackState[] mBackStack;
+ int mPrimaryNavActiveIndex = -1;
public FragmentManagerState() {
}
@@ -532,6 +545,7 @@ final class FragmentManagerState implements Parcelable {
mActive = in.createTypedArray(FragmentState.CREATOR);
mAdded = in.createIntArray();
mBackStack = in.createTypedArray(BackStackState.CREATOR);
+ mPrimaryNavActiveIndex = in.readInt();
}
public int describeContents() {
@@ -542,6 +556,7 @@ final class FragmentManagerState implements Parcelable {
dest.writeTypedArray(mActive, flags);
dest.writeIntArray(mAdded);
dest.writeTypedArray(mBackStack, flags);
+ dest.writeInt(mPrimaryNavActiveIndex);
}
public static final Parcelable.Creator<FragmentManagerState> CREATOR
@@ -626,6 +641,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
FragmentHostCallback<?> mHost;
FragmentContainer mContainer;
Fragment mParent;
+ Fragment mPrimaryNav;
boolean mNeedMenuInvalidate;
boolean mStateSaved;
@@ -783,6 +799,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
execPendingActions();
ensureExecReady(true);
+ if (mPrimaryNav != null // We have a primary nav fragment
+ && id < 0 // No valid id (since they're local)
+ && name == null) { // no name to pop to (since they're local)
+ final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
+ if (childManager != null && childManager.popBackStackImmediate()) {
+ // We did something, just not to this specific FragmentManager. Return true.
+ return true;
+ }
+ }
+
boolean executePop = popBackStackState(mTmpRecords, mTmpIsPop, name, id, flags);
if (executePop) {
mExecutingActions = true;
@@ -1110,10 +1136,25 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
}
}
}
+
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
+
+ // If we have a target fragment, push it along to at least CREATED
+ // so that this one can rely on it as an initialized dependency.
+ if (f.mTarget != null) {
+ if (!mActive.contains(f.mTarget)) {
+ throw new IllegalStateException("Fragment " + f
+ + " declared target fragment " + f.mTarget
+ + " that does not belong to this FragmentManager!");
+ }
+ if (f.mTarget.mState < Fragment.CREATED) {
+ moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
+ }
+ }
+
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext());
@@ -1746,6 +1787,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
}
}
+ public boolean isStateSaved() {
+ return mStateSaved;
+ }
+
/**
* Adds an action to the queue of pending actions.
*
@@ -2023,16 +2068,15 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
if (mAdded != null) {
mTmpAddedFragments.addAll(mAdded);
}
+ Fragment oldPrimaryNav = getPrimaryNavigationFragment();
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
final BackStackRecord record = records.get(recordNum);
final boolean isPop = isRecordPop.get(recordNum);
if (!isPop) {
- record.expandReplaceOps(mTmpAddedFragments);
+ oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
} else {
record.trackAddedFragmentsInPop(mTmpAddedFragments);
}
- final int bumpAmount = isPop ? -1 : 1;
- record.bumpBackStackNesting(bumpAmount);
addToBackStack = addToBackStack || record.mAddToBackStack;
}
mTmpAddedFragments.clear();
@@ -2066,6 +2110,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
freeBackStackIndex(record.mIndex);
record.mIndex = -1;
}
+ record.runOnCommitRunnables();
}
if (addToBackStack) {
@@ -2234,8 +2279,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
final BackStackRecord record = records.get(i);
final boolean isPop = isRecordPop.get(i);
if (isPop) {
+ record.bumpBackStackNesting(-1);
record.executePopOps();
} else {
+ record.bumpBackStackNesting(1);
record.executeOps();
}
}
@@ -2303,20 +2350,20 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
*/
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
- int numActions;
+ boolean didSomething = false;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
- numActions = mPendingActions.size();
+ final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
- mPendingActions.get(i).generateOps(records, isPop);
+ didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
- return numActions > 0;
+ return didSomething;
}
void doPendingDeferredStart() {
@@ -2603,6 +2650,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
+ if (mPrimaryNav != null) {
+ fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
+ }
return fms;
}
@@ -2729,6 +2779,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
} else {
mBackStack = null;
}
+
+ if (fms.mPrimaryNavActiveIndex >= 0) {
+ mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
+ }
}
public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
@@ -2927,6 +2981,19 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
}
}
+ public void setPrimaryNavigationFragment(Fragment f) {
+ if (f != null && (f.getFragmentManager() != this || f.mIndex >= mActive.size()
+ || mActive.get(f.mIndex) != f)) {
+ throw new IllegalArgumentException("Fragment " + f
+ + " is not an active fragment of FragmentManager " + this);
+ }
+ mPrimaryNav = f;
+ }
+
+ public Fragment getPrimaryNavigationFragment() {
+ return mPrimaryNav;
+ }
+
public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
boolean recursive) {
if (mLifecycleCallbacks == null) {
@@ -3371,6 +3438,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
@Override
public boolean generateOps(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
+ if (mPrimaryNav != null // We have a primary nav fragment
+ && mId < 0 // No valid id (since they're local)
+ && mName == null) { // no name to pop to (since they're local)
+ final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
+ if (childManager != null && childManager.popBackStackImmediate()) {
+ // We didn't add any operations for this FragmentManager even though
+ // a child did do work.
+ return false;
+ }
+ }
return popBackStackState(records, isRecordPop, mName, mId, mFlags);
}
}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 25a7839fa1ed..c938aa607e10 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -132,6 +132,24 @@ public abstract class FragmentTransaction {
public abstract FragmentTransaction attach(Fragment fragment);
/**
+ * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
+ *
+ * <p>The primary navigation fragment's
+ * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
+ * to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
+ * if no ID or transaction name is provided to pop to. Navigation operations outside of the
+ * fragment system may choose to delegate those actions to the primary navigation fragment
+ * as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
+ *
+ * <p>The fragment provided must currently be added to the FragmentManager to be set as
+ * a primary navigation fragment, or previously added as part of this transaction.</p>
+ *
+ * @param fragment the fragment to set as the primary navigation fragment
+ * @return the same FragmentTransaction instance
+ */
+ public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);
+
+ /**
* @return <code>true</code> if this transaction contains no operations,
* <code>false</code> otherwise.
*/
@@ -286,6 +304,22 @@ public abstract class FragmentTransaction {
public abstract FragmentTransaction setAllowOptimization(boolean allowOptimization);
/**
+ * Add a Runnable to this transaction that will be run after this transaction has
+ * been committed. If fragment transactions are {@link #setAllowOptimization(boolean) optimized}
+ * this may be after other subsequent fragment operations have also taken place, or operations
+ * in this transaction may have been optimized out due to the presence of a subsequent
+ * fragment transaction in the batch.
+ *
+ * <p><code>postOnCommit</code> may not be used with transactions
+ * {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
+ * with back stack state.</p>
+ *
+ * @param runnable Runnable to add
+ * @return this FragmentTransaction
+ */
+ public abstract FragmentTransaction postOnCommit(Runnable runnable);
+
+ /**
* Schedules a commit of this transaction. The commit does
* not happen immediately; it will be scheduled as work on the main thread
* to be done the next time that thread is ready.
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 80a5aacbd9dd..f62ab8d76c3c 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -18,6 +18,7 @@ package android.app;
import android.graphics.Rect;
import android.os.Build;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.ArrayMap;
@@ -43,14 +44,16 @@ class FragmentTransition {
* REPLACE operations have already been replaced by add/remove operations.
*/
private static final int[] INVERSE_OPS = {
- BackStackRecord.OP_NULL, // inverse of OP_NULL (error)
- BackStackRecord.OP_REMOVE, // inverse of OP_ADD
- BackStackRecord.OP_NULL, // inverse of OP_REPLACE (error)
- BackStackRecord.OP_ADD, // inverse of OP_REMOVE
- BackStackRecord.OP_SHOW, // inverse of OP_HIDE
- BackStackRecord.OP_HIDE, // inverse of OP_SHOW
- BackStackRecord.OP_ATTACH, // inverse of OP_DETACH
- BackStackRecord.OP_DETACH, // inverse of OP_ATTACH
+ BackStackRecord.OP_NULL, // inverse of OP_NULL (error)
+ BackStackRecord.OP_REMOVE, // inverse of OP_ADD
+ BackStackRecord.OP_NULL, // inverse of OP_REPLACE (error)
+ BackStackRecord.OP_ADD, // inverse of OP_REMOVE
+ BackStackRecord.OP_SHOW, // inverse of OP_HIDE
+ BackStackRecord.OP_HIDE, // inverse of OP_SHOW
+ BackStackRecord.OP_ATTACH, // inverse of OP_DETACH
+ BackStackRecord.OP_DETACH, // inverse of OP_ATTACH
+ BackStackRecord.OP_UNSET_PRIMARY_NAV, // inverse of OP_SET_PRIMARY_NAV
+ BackStackRecord.OP_SET_PRIMARY_NAV, // inverse of OP_UNSET_PRIMARY_NAV
};
/**
@@ -330,7 +333,7 @@ class FragmentTransition {
OneShotPreDrawListener.add(exitingFragment.mContainer, () -> {
setViewVisibility(exitingViews, View.INVISIBLE);
});
- exitTransition.addListener(new Transition.TransitionListenerAdapter() {
+ exitTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
@@ -993,7 +996,7 @@ class FragmentTransition {
final Transition enterTransition, final ArrayList<View> enteringViews,
final Transition exitTransition, final ArrayList<View> exitingViews,
final TransitionSet sharedElementTransition, final ArrayList<View> sharedElementsIn) {
- overalTransition.addListener(new Transition.TransitionListenerAdapter() {
+ overalTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionStart(Transition transition) {
if (enterTransition != null) {
@@ -1232,6 +1235,9 @@ class FragmentTransition {
SparseArray<FragmentContainerTransition> transitioningFragments, boolean isPop,
boolean isOptimizedTransaction) {
final Fragment fragment = op.fragment;
+ if (fragment == null) {
+ return; // no fragment, no transition
+ }
final int containerId = fragment.mContainerId;
if (containerId == 0) {
return; // no container, no transition
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 5a4879367a97..c842f788feda 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -145,6 +145,7 @@ interface IActivityManager {
int flags, in Bundle arguments, in IInstrumentationWatcher watcher,
in IUiAutomationConnection connection, int userId,
in String abiOverride);
+ void addInstrumentationResults(in IApplicationThread target, in Bundle results);
void finishInstrumentation(in IApplicationThread target, int resultCode,
in Bundle results);
/**
@@ -539,7 +540,7 @@ interface IActivityManager {
*/
void swapDockedAndFullscreenStack();
void notifyLockedProfile(int userId);
- void startConfirmDeviceCredentialIntent(in Intent intent);
+ void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
void sendIdleJobTrigger();
int sendIntentSender(in IIntentSender target, int code, in Intent intent,
in String resolvedType, in IIntentReceiver finishedReceiver,
@@ -584,7 +585,7 @@ interface IActivityManager {
void unregisterTaskStackListener(ITaskStackListener listener);
void moveStackToDisplay(int stackId, int displayId);
boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
- int resultCode, in IBinder activityToken, int flags);
+ in IBinder activityToken);
void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
int restartUserInBackground(int userId);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 41d1255c0a28..4fc6fb9eee2e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -134,7 +134,7 @@ oneway interface IApplicationThread {
void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
void unstableProviderDied(IBinder provider);
void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId, int flags);
+ int requestType, int sessionId);
void scheduleTranslucentConversionComplete(IBinder token, boolean timeout);
void setProcessState(int state);
void scheduleInstallProvider(in ProviderInfo provider);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index d674bfe23231..58cd31010001 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -54,7 +54,9 @@ interface INotificationManager
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
+ void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
+ ParceledListSlice getNotificationChannelGroupsForPackage(String pkg, int uid, boolean includeDeleted);
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
NotificationChannel getNotificationChannel(String pkg, String channelId);
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
@@ -75,8 +77,6 @@ interface INotificationManager
void snoozeNotificationUntilContextFromListener(in INotificationListener token, String key, String snoozeCriterionId);
void snoozeNotificationUntilFromListener(in INotificationListener token, String key, long until);
- void snoozeNotificationFromListener(in INotificationListener token, String key);
- void unsnoozeNotificationFromListener(in INotificationListener token, String key);
void requestBindListener(in ComponentName component);
void requestUnbindListener(in INotificationListener token);
@@ -86,6 +86,7 @@ interface INotificationManager
void setNotificationsShownFromListener(in INotificationListener token, in String[] keys);
ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
+ ParceledListSlice getSnoozedNotificationsFromListener(in INotificationListener token, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
@@ -100,6 +101,7 @@ interface INotificationManager
void updateNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel);
void deleteNotificationChannelFromAssistant(in INotificationListener token, String pkg, String channelId);
ParceledListSlice getNotificationChannelsFromAssistant(in INotificationListener token, String pkg);
+ void unsnoozeNotificationFromAssistant(in INotificationListener token, String key);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index ecf2c73c32b7..b436aa2bcd0f 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -18,9 +18,6 @@ package android.app;
/** {@hide} */
oneway interface IProcessObserver {
-
void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
- void onProcessStateChanged(int pid, int uid, int procState);
void onProcessDied(int pid, int uid);
-
}
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 848464cf3823..7f0b6fb61f05 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -58,11 +58,16 @@ interface IUiModeManager {
void setTheme(String theme);
/**
- * Gets whith theme overlays to use within /vendor/overlay.
+ * Gets which theme overlays to use within /vendor/overlay.
*/
String getTheme();
/**
+ * Gets the themes available in /vendor/overlay.
+ */
+ String[] getAvailableThemes();
+
+ /**
* Tells if UI mode is locked or not.
*/
boolean isUiModeLocked();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b1bdea1cb502..4db29fb5a72a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -186,11 +186,25 @@ public class Instrumentation {
}
}
}
-
+
+ /**
+ * Report some results in the middle of instrumentation execution. Later results (including
+ * those provided by {@link #finish}) will be combined with {@link Bundle#putAll}.
+ */
+ public void addResults(Bundle results) {
+ IActivityManager am = ActivityManager.getService();
+ try {
+ am.addInstrumentationResults(mThread.getApplicationThread(), results);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
/**
* Terminate instrumentation of the application. This will cause the
* application process to exit, removing this instrumentation from the next
- * time the application is started.
+ * time the application is started. If multiple processes are currently running
+ * for this instrumentation, all of those processes will be killed.
*
* @param resultCode Overall success/failure of instrumentation.
* @param results Any results to send back to the code that started the
@@ -278,6 +292,18 @@ public class Instrumentation {
}
/**
+ * Return the name of the process this instrumentation is running in. Note this should
+ * only be used for testing and debugging. If you are thinking about using this to,
+ * for example, conditionalize what is initialized in an Application class, it is strongly
+ * recommended to instead use lazy initialization (such as a getter for the state that
+ * only creates it when requested). This can greatly reduce the work your process does
+ * when created for secondary things, such as to receive a broadcast.
+ */
+ public String getProcessName() {
+ return mThread.getProcessName();
+ }
+
+ /**
* Check whether this instrumentation was started with profiling enabled.
*
* @return Returns true if profiling was enabled when starting, else false.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 4ab07432ad1f..7ed96af6fa21 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -27,9 +27,11 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.split.SplitDependencyLoaderHelper;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
@@ -41,23 +43,22 @@ import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.system.Os;
-import android.system.OsConstants;
-import android.system.ErrnoException;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayAdjustments;
+import com.android.internal.util.ArrayUtils;
+
import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
import java.io.File;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -65,13 +66,12 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
-import libcore.io.IoUtils;
-
final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) {
super(msg);
@@ -97,8 +97,6 @@ public final class LoadedApk {
private ApplicationInfo mApplicationInfo;
private String mAppDir;
private String mResDir;
- private String[] mSplitAppDirs;
- private String[] mSplitResDirs;
private String[] mOverlayDirs;
private String[] mSharedLibraries;
private String mDataDir;
@@ -116,14 +114,18 @@ public final class LoadedApk {
private ClassLoader mClassLoader;
private Application mApplication;
+ private String[] mSplitNames;
+ private String[] mSplitAppDirs;
+ private String[] mSplitResDirs;
+
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
- = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
+ = new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
- = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
+ = new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
- = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
+ = new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
- = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
+ = new ArrayMap<>();
int mClientCount = 0;
@@ -300,9 +302,18 @@ public final class LoadedApk {
synchronized (this) {
createOrUpdateClassLoaderLocked(addedPaths);
if (mResources != null) {
- mResources = mActivityThread.getTopLevelResources(mResDir, mSplitResDirs,
- mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
- this);
+ final String[] splitPaths;
+ try {
+ splitPaths = getSplitPaths(null);
+ } catch (PackageManager.NameNotFoundException e) {
+ // This should NEVER fail.
+ throw new AssertionError("null split not found");
+ }
+
+ mResources = ResourcesManager.getInstance().getResources(null, mResDir,
+ splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
+ Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ getClassLoader());
}
}
}
@@ -313,8 +324,6 @@ public final class LoadedApk {
mApplicationInfo = aInfo;
mAppDir = aInfo.sourceDir;
mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
- mSplitAppDirs = aInfo.splitSourceDirs;
- mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
mOverlayDirs = aInfo.resourceDirs;
mSharedLibraries = aInfo.sharedLibraryFiles;
mDataDir = aInfo.dataDir;
@@ -322,19 +331,28 @@ public final class LoadedApk {
mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
mDeviceProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceProtectedDataDir);
mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
+
+ mSplitNames = aInfo.splitNames;
+ mSplitAppDirs = aInfo.splitSourceDirs;
+ mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
+
+ if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) {
+ mSplitLoader = new SplitDependencyLoader(aInfo.splitDependencies);
+ }
}
public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
List<String> outZipPaths, List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
- final String[] splitAppDirs = aInfo.splitSourceDirs;
final String libDir = aInfo.nativeLibraryDir;
final String[] sharedLibraries = aInfo.sharedLibraryFiles;
outZipPaths.clear();
outZipPaths.add(appDir);
- if (splitAppDirs != null) {
- Collections.addAll(outZipPaths, splitAppDirs);
+
+ // Do not load all available splits if the app requested isolated split loading.
+ if (aInfo.splitSourceDirs != null && !aInfo.requestsIsolatedSplitLoading()) {
+ Collections.addAll(outZipPaths, aInfo.splitSourceDirs);
}
if (outLibPaths != null) {
@@ -367,13 +385,18 @@ public final class LoadedApk {
|| appDir.equals(instrumentedAppDir)) {
outZipPaths.clear();
outZipPaths.add(instrumentationAppDir);
- if (instrumentationSplitAppDirs != null) {
- Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
- }
- if (!instrumentationAppDir.equals(instrumentedAppDir)) {
- outZipPaths.add(instrumentedAppDir);
- if (instrumentedSplitAppDirs != null) {
- Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+
+ // Only add splits if the app did not request isolated split loading.
+ if (!aInfo.requestsIsolatedSplitLoading()) {
+ if (instrumentationSplitAppDirs != null) {
+ Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
+ }
+
+ if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+ outZipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+ }
}
}
@@ -399,7 +422,7 @@ public final class LoadedApk {
// will be added to zipPaths that shouldn't be part of the library path.
if (aInfo.primaryCpuAbi != null) {
// Add fake libs into the library search path if we target prior to N.
- if (aInfo.targetSdkVersion <= 23) {
+ if (aInfo.targetSdkVersion < Build.VERSION_CODES.N) {
outLibPaths.add("/system/fake-libs" +
(VMRuntime.is64BitAbi(aInfo.primaryCpuAbi) ? "64" : ""));
}
@@ -434,6 +457,116 @@ public final class LoadedApk {
}
}
+ private class SplitDependencyLoader
+ extends SplitDependencyLoaderHelper<PackageManager.NameNotFoundException> {
+ private String[] mCachedBaseResourcePath;
+ private final String[][] mCachedResourcePaths;
+ private final ClassLoader[] mCachedSplitClassLoaders;
+
+ SplitDependencyLoader(SparseIntArray dependencies) {
+ super(dependencies);
+ mCachedResourcePaths = new String[mSplitNames.length][];
+ mCachedSplitClassLoaders = new ClassLoader[mSplitNames.length];
+ }
+
+ @Override
+ protected boolean isSplitCached(int splitIdx) {
+ if (splitIdx != -1) {
+ return mCachedSplitClassLoaders[splitIdx] != null;
+ }
+ return mClassLoader != null && mCachedBaseResourcePath != null;
+ }
+
+ private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) {
+ for (int i = 0; i < mSplitNames.length; i++) {
+ if (isConfigurationSplitOf(mSplitNames[i], splitName)) {
+ outAssetPaths.add(mSplitResDirs[i]);
+ }
+ }
+ }
+
+ @Override
+ protected void constructSplit(int splitIdx, int parentSplitIdx) throws
+ PackageManager.NameNotFoundException {
+ final ArrayList<String> splitPaths = new ArrayList<>();
+ if (splitIdx == -1) {
+ createOrUpdateClassLoaderLocked(null);
+ addAllConfigSplits(null, splitPaths);
+ mCachedBaseResourcePath = splitPaths.toArray(new String[splitPaths.size()]);
+ return;
+ }
+
+ final ClassLoader parent;
+ if (parentSplitIdx == -1) {
+ // The parent is the base APK, so use its ClassLoader as parent
+ // and its configuration splits as part of our own too.
+ parent = mClassLoader;
+ Collections.addAll(splitPaths, mCachedBaseResourcePath);
+ } else {
+ parent = mCachedSplitClassLoaders[parentSplitIdx];
+ Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]);
+ }
+
+ mCachedSplitClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader(
+ mSplitAppDirs[splitIdx], getTargetSdkVersion(), false, null, null, parent);
+
+ splitPaths.add(mSplitResDirs[splitIdx]);
+ addAllConfigSplits(mSplitNames[splitIdx], splitPaths);
+ mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]);
+ }
+
+ private int ensureSplitLoaded(String splitName)
+ throws PackageManager.NameNotFoundException {
+ final int idx;
+ if (splitName == null) {
+ idx = -1;
+ } else {
+ idx = Arrays.binarySearch(mSplitNames, splitName);
+ if (idx < 0) {
+ throw new PackageManager.NameNotFoundException(
+ "Split name '" + splitName + "' is not installed");
+ }
+ }
+
+ loadDependenciesForSplit(idx);
+ return idx;
+ }
+
+ ClassLoader getClassLoaderForSplit(String splitName)
+ throws PackageManager.NameNotFoundException {
+ final int idx = ensureSplitLoaded(splitName);
+ if (idx < 0) {
+ return mClassLoader;
+ }
+ return mCachedSplitClassLoaders[idx];
+ }
+
+ String[] getSplitPathsForSplit(String splitName)
+ throws PackageManager.NameNotFoundException {
+ final int idx = ensureSplitLoaded(splitName);
+ if (idx < 0) {
+ return mCachedBaseResourcePath;
+ }
+ return mCachedResourcePaths[idx];
+ }
+ }
+
+ private SplitDependencyLoader mSplitLoader;
+
+ ClassLoader getSplitClassLoader(String splitName) throws PackageManager.NameNotFoundException {
+ if (mSplitLoader == null) {
+ return mClassLoader;
+ }
+ return mSplitLoader.getClassLoaderForSplit(splitName);
+ }
+
+ String[] getSplitPaths(String splitName) throws PackageManager.NameNotFoundException {
+ if (mSplitLoader == null) {
+ return mSplitResDirs;
+ }
+ return mSplitLoader.getSplitPathsForSplit(splitName);
+ }
+
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
if (mPackageName.equals("android")) {
// Note: This branch is taken for system server and we don't need to setup
@@ -806,14 +939,24 @@ public final class LoadedApk {
return mCredentialProtectedDataDirFile;
}
- public AssetManager getAssets(ActivityThread mainThread) {
- return getResources(mainThread).getAssets();
+ public AssetManager getAssets() {
+ return getResources().getAssets();
}
- public Resources getResources(ActivityThread mainThread) {
+ public Resources getResources() {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
- mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, this);
+ final String[] splitPaths;
+ try {
+ splitPaths = getSplitPaths(null);
+ } catch (PackageManager.NameNotFoundException e) {
+ // This should never fail.
+ throw new AssertionError("null split not found");
+ }
+
+ mResources = ResourcesManager.getInstance().getResources(null, mResDir,
+ splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
+ Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ getClassLoader());
}
return mResources;
}
@@ -870,8 +1013,7 @@ public final class LoadedApk {
}
// Rewrite the R 'constants' for all library apks.
- SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
- .getAssignedPackageIdentifiers();
+ SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 82917d27d0d6..9ef40b4c0097 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -28,6 +28,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -46,6 +47,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
@@ -70,7 +72,6 @@ import android.widget.RemoteViews;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
-import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -222,13 +223,11 @@ public class Notification implements Parcelable
* superimposed over the icon in the status bar. Starting with
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
* {@link Notification.Builder} has displayed the number in the expanded notification view.
+ * Starting with {@link android.os.Build.VERSION_CODES#O}, the number may be displayed as a
+ * badge icon in Launchers that support badging.
*
- * If the number is 0 or negative, it is never shown.
- *
- * @deprecated this number is not shown anymore
*/
- @Deprecated
- public int number;
+ public int number = 1;
/**
* The intent to execute when the expanded status entry is clicked. If
@@ -338,7 +337,9 @@ public class Notification implements Parcelable
* <p>
* To play the default notification sound, see {@link #defaults}.
* </p>
+ * @deprecated use {@link NotificationChannel#getSound()}.
*/
+ @Deprecated
public Uri sound;
/**
@@ -346,7 +347,7 @@ public class Notification implements Parcelable
* the default stream type for notifications be used. Currently the
* default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
*
- * @deprecated Use {@link #audioAttributes} instead.
+ * @deprecated Use {@link NotificationChannel#getAudioAttributes()} instead.
*/
@Deprecated
public static final int STREAM_DEFAULT = -1;
@@ -371,7 +372,10 @@ public class Notification implements Parcelable
/**
* The {@link AudioAttributes audio attributes} to use when playing the sound.
+ *
+ * @deprecated use {@link NotificationChannel#getAudioAttributes()} instead.
*/
+ @Deprecated
public AudioAttributes audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
/**
@@ -381,12 +385,10 @@ public class Notification implements Parcelable
* To vibrate the default pattern, see {@link #defaults}.
* </p>
*
- * <p>
- * A notification that vibrates is more likely to be presented as a heads-up notification.
- * </p>
- *
* @see android.os.Vibrator#vibrate(long[],int)
+ * @deprecated use {@link NotificationChannel#getVibrationPattern()}.
*/
+ @Deprecated
public long[] vibrate;
/**
@@ -394,8 +396,10 @@ public class Notification implements Parcelable
*
* @see #FLAG_SHOW_LIGHTS
* @see #flags
+ * @deprecated use {@link NotificationChannel#shouldShowLights()}.
*/
@ColorInt
+ @Deprecated
public int ledARGB;
/**
@@ -404,7 +408,9 @@ public class Notification implements Parcelable
*
* @see #FLAG_SHOW_LIGHTS
* @see #flags
+ * @deprecated use {@link NotificationChannel#shouldShowLights()}.
*/
+ @Deprecated
public int ledOnMS;
/**
@@ -413,7 +419,10 @@ public class Notification implements Parcelable
*
* @see #FLAG_SHOW_LIGHTS
* @see #flags
+ *
+ * @deprecated use {@link NotificationChannel#shouldShowLights()}.
*/
+ @Deprecated
public int ledOffMS;
/**
@@ -423,7 +432,12 @@ public class Notification implements Parcelable
* {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
* values, use {@link #DEFAULT_ALL}.
* </p>
+ *
+ * @deprecated use {@link NotificationChannel#getSound()} and
+ * {@link NotificationChannel#shouldShowLights()} and
+ * {@link NotificationChannel#shouldVibrate()}.
*/
+ @Deprecated
public int defaults;
/**
@@ -443,7 +457,9 @@ public class Notification implements Parcelable
* <p>
* The alpha channel must be set for forward compatibility.
*
+ * @deprecated use {@link NotificationChannel#shouldShowLights()}.
*/
+ @Deprecated
public static final int FLAG_SHOW_LIGHTS = 0x00000001;
/**
@@ -532,33 +548,48 @@ public class Notification implements Parcelable
/**
* Default notification {@link #priority}. If your application does not prioritize its own
* notifications, use this value for all notifications.
+ *
+ * @deprecated use {@link NotificationManager#IMPORTANCE_DEFAULT} instead.
*/
+ @Deprecated
public static final int PRIORITY_DEFAULT = 0;
/**
* Lower {@link #priority}, for items that are less important. The UI may choose to show these
* items smaller, or at a different position in the list, compared with your app's
* {@link #PRIORITY_DEFAULT} items.
+ *
+ * @deprecated use {@link NotificationManager#IMPORTANCE_LOW} instead.
*/
+ @Deprecated
public static final int PRIORITY_LOW = -1;
/**
* Lowest {@link #priority}; these items might not be shown to the user except under special
* circumstances, such as detailed notification logs.
+ *
+ * @deprecated use {@link NotificationManager#IMPORTANCE_MIN} instead.
*/
+ @Deprecated
public static final int PRIORITY_MIN = -2;
/**
* Higher {@link #priority}, for more important notifications or alerts. The UI may choose to
* show these items larger, or at a different position in notification lists, compared with
* your app's {@link #PRIORITY_DEFAULT} items.
+ *
+ * @deprecated use {@link NotificationManager#IMPORTANCE_HIGH} instead.
*/
+ @Deprecated
public static final int PRIORITY_HIGH = 1;
/**
* Highest {@link #priority}, for your application's most important items that require the
* user's prompt attention or input.
+ *
+ * @deprecated use {@link NotificationManager#IMPORTANCE_HIGH} instead.
*/
+ @Deprecated
public static final int PRIORITY_MAX = 2;
/**
@@ -575,8 +606,10 @@ public class Notification implements Parcelable
* as a heads-up notification.
* </p>
*
+ * @deprecated use {@link NotificationChannel#getImportance()} instead.
*/
@Priority
+ @Deprecated
public int priority;
/**
@@ -599,9 +632,10 @@ public class Notification implements Parcelable
/**
* Special value of {@link #color} used as a place holder for an invalid color.
+ * @hide
*/
@ColorInt
- private static final int COLOR_INVALID = 1;
+ public static final int COLOR_INVALID = 1;
/**
* Sphere of visibility of this notification, which affects how and when the SystemUI reveals
@@ -972,6 +1006,21 @@ public class Notification implements Parcelable
public static final String EXTRA_MESSAGES = "android.messages";
/**
+ * {@link #extras} key: an array of
+ * {@link android.app.Notification.MessagingStyle#addHistoricMessage historic}
+ * {@link android.app.Notification.MessagingStyle.Message} bundles provided by a
+ * {@link android.app.Notification.MessagingStyle} notification. This extra is a parcelable
+ * array of bundles.
+ */
+ public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+
+ /**
+ * {@link #extras} key: whether the notification should be colorized as
+ * supplied to {@link Builder#setColorized(boolean)}}.
+ */
+ public static final String EXTRA_COLORIZED = "android.colorized";
+
+ /**
* {@link #extras} key: the user that built the notification.
*
* @hide
@@ -1022,6 +1071,27 @@ public class Notification implements Parcelable
private Icon mLargeIcon;
private String mChannelId;
+ private long mTimeout;
+
+ private String mShortcutId;
+
+ /**
+ * If this notification is being shown as a badge, always show as a number.
+ */
+ public static final int BADGE_ICON_NONE = 0;
+
+ /**
+ * If this notification is being shown as a badge, use the {@link #getSmallIcon()} to
+ * represent this notification.
+ */
+ public static final int BADGE_ICON_SMALL = 1;
+
+ /**
+ * If this notification is being shown as a badge, use the {@link #getLargeIcon()} to
+ * represent this notification.
+ */
+ public static final int BADGE_ICON_LARGE = 2;
+ private int mBadgeIcon = BADGE_ICON_LARGE;
/**
* Structure to encapsulate a named action that can be shown as part of this notification.
@@ -1766,6 +1836,13 @@ public class Notification implements Parcelable
if (parcel.readInt() != 0) {
mChannelId = parcel.readString();
}
+ mTimeout = parcel.readLong();
+
+ if (parcel.readInt() != 0) {
+ mShortcutId = parcel.readString();
+ }
+
+ mBadgeIcon = parcel.readInt();
}
@Override
@@ -1872,6 +1949,7 @@ public class Notification implements Parcelable
that.color = this.color;
that.mChannelId = this.mChannelId;
+ that.mTimeout = this.mTimeout;
if (!heavy) {
that.lightenPayload(); // will clean out extras
@@ -1895,6 +1973,9 @@ public class Notification implements Parcelable
final String[] keys = keyset.toArray(new String[N]);
for (int i=0; i<N; i++) {
final String key = keys[i];
+ if (TvExtender.EXTRA_TV_EXTENDER.equals(key)) {
+ continue;
+ }
final Object obj = extras.get(key);
if (obj != null &&
( obj instanceof Parcelable
@@ -1986,7 +2067,7 @@ public class Notification implements Parcelable
}
try {
// IMPORTANT: Add marshaling code in writeToParcelImpl as we
- // want to intercept all pending events written to the pacel.
+ // want to intercept all pending events written to the parcel.
writeToParcelImpl(parcel, flags);
// Must be written last!
parcel.writeArraySet(allPendingIntents);
@@ -2128,6 +2209,16 @@ public class Notification implements Parcelable
} else {
parcel.writeInt(0);
}
+ parcel.writeLong(mTimeout);
+
+ if (mShortcutId != null) {
+ parcel.writeInt(1);
+ parcel.writeString(mShortcutId);
+ } else {
+ parcel.writeInt(0);
+ }
+
+ parcel.writeInt(mBadgeIcon);
}
/**
@@ -2325,6 +2416,30 @@ public class Notification implements Parcelable
}
/**
+ * Returns the time at which this notification should be canceled by the system, if it's not
+ * canceled already.
+ */
+ public long getTimeout() {
+ return mTimeout;
+ }
+
+ /**
+ * Returns what icon should be shown for this notification if it is being displayed in a
+ * Launcher that supports badging. Will be one of {@link #BADGE_ICON_NONE},
+ * {@link #BADGE_ICON_SMALL}, or {@link #BADGE_ICON_LARGE}.
+ */
+ public int getBadgeIcon() {
+ return mBadgeIcon;
+ }
+
+ /**
+ * Returns the {@link ShortcutInfo#getId() id} that this notification supersedes, if any.
+ */
+ public String getShortcutId() {
+ return mShortcutId;
+ }
+
+ /**
* The small icon representing this notification in the status bar and content view.
*
* @return the small icon representing this notification.
@@ -2407,6 +2522,9 @@ public class Notification implements Parcelable
private static final int MAX_ACTION_BUTTONS = 3;
+ private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY =
+ SystemProperties.getBoolean("notifications.only_title", true);
+
private Context mContext;
private Notification mN;
private Bundle mUserExtras = new Bundle();
@@ -2414,7 +2532,8 @@ public class Notification implements Parcelable
private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
private ArrayList<String> mPersonList = new ArrayList<String>();
private NotificationColorUtil mColorUtil;
- private boolean mColorUtilInited = false;
+ private boolean mIsLegacy;
+ private boolean mIsLegacyInitialized;
/**
* Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
@@ -2432,6 +2551,10 @@ public class Notification implements Parcelable
* so make sure to call {@link StandardTemplateParams#reset()} before using it.
*/
StandardTemplateParams mParams = new StandardTemplateParams();
+ private int mTextColorsAreForBackground = COLOR_INVALID;
+ private int mPrimaryTextColor = COLOR_INVALID;
+ private int mSecondaryTextColor = COLOR_INVALID;
+ private int mActionBarColor = COLOR_INVALID;
/**
* Constructs a new Builder with the defaults:
@@ -2451,9 +2574,23 @@ public class Notification implements Parcelable
* A {@link Context} that will be used by the Builder to construct the
* RemoteViews. The Context will not be held past the lifetime of this Builder
* object.
+ * @param channelId
+ * The constructed Notification will be posted on this
+ * {@link NotificationChannel}. To use a NotificationChannel, it must first be
+ * created using {@link NotificationManager#createNotificationChannel}.
*/
+ public Builder(Context context, String channelId) {
+ this(context, (Notification) null);
+ mN.mChannelId = channelId;
+ }
+
+ /**
+ * @deprecated use {@link Notification.Builder#Notification.Builder(Context, String)}
+ * instead. All posted Notifications must specify a NotificationChannel Id.
+ */
+ @Deprecated
public Builder(Context context) {
- this(context, null);
+ this(context, (Notification) null);
}
/**
@@ -2514,16 +2651,42 @@ public class Notification implements Parcelable
}
private NotificationColorUtil getColorUtil() {
- if (!mColorUtilInited) {
- mColorUtilInited = true;
- if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
- mColorUtil = NotificationColorUtil.getInstance(mContext);
- }
+ if (mColorUtil == null) {
+ mColorUtil = NotificationColorUtil.getInstance(mContext);
}
return mColorUtil;
}
/**
+ * If this notification is duplicative of a Launcher shortcut, sets the
+ * {@link ShortcutInfo#getId() id} of the shortcut, in case the Launcher wants to hide
+ * the shortcut.
+ *
+ * This field will be ignored by Launchers that don't support badging or
+ * {@link android.content.pm.ShortcutManager shortcuts}.
+ *
+ * @param shortcutId the {@link ShortcutInfo#getId() id} of the shortcut this notification
+ * supersedes
+ */
+ public Builder setShortcutId(String shortcutId) {
+ mN.mShortcutId = shortcutId;
+ return this;
+ }
+
+ /**
+ * Sets which icon to display as a badge for this notification.
+ *
+ * Must be one of {@link #BADGE_ICON_NONE}, {@link #BADGE_ICON_SMALL},
+ * {@link #BADGE_ICON_LARGE}.
+ *
+ * Note: This value might be ignored, for launchers that don't support badge icons.
+ */
+ public Builder chooseBadgeIcon(int icon) {
+ mN.mBadgeIcon = icon;
+ return this;
+ }
+
+ /**
* Specifies the channel the notification should be delivered on.
*/
public Builder setChannel(String channelId) {
@@ -2532,6 +2695,15 @@ public class Notification implements Parcelable
}
/**
+ * Specifies the time at which this notification should be canceled, if it is not already
+ * canceled.
+ */
+ public Builder setTimeout(long when) {
+ mN.mTimeout = when;
+ return this;
+ }
+
+ /**
* Add a timestamp pertaining to the notification (usually the time the event occurred).
*
* For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this time is not
@@ -2709,13 +2881,9 @@ public class Notification implements Parcelable
}
/**
- * Set the large number at the right-hand side of the notification. This is
- * equivalent to setContentInfo, although it might show the number in a different
- * font size for readability.
- *
- * @deprecated this number is not shown anywhere anymore
+ * Sets the number of items this notification represents. May be displayed as a badge count
+ * for Launchers that support badging.
*/
- @Deprecated
public Builder setNumber(int number) {
mN.number = number;
return this;
@@ -2895,8 +3063,9 @@ public class Notification implements Parcelable
* It will be played using the {@link #AUDIO_ATTRIBUTES_DEFAULT default audio attributes}
* for notifications.
*
- * @see Notification#sound
+ * @deprecated use {@link NotificationChannel#setSound(Uri, AudioAttributes)} instead.
*/
+ @Deprecated
public Builder setSound(Uri sound) {
mN.sound = sound;
mN.audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
@@ -2908,8 +3077,7 @@ public class Notification implements Parcelable
*
* See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
*
- * @deprecated use {@link #setSound(Uri, AudioAttributes)} instead.
- * @see Notification#sound
+ * @deprecated use {@link NotificationChannel#setSound(Uri, AudioAttributes)}.
*/
@Deprecated
public Builder setSound(Uri sound, int streamType) {
@@ -2923,8 +3091,10 @@ public class Notification implements Parcelable
* Set the sound to play, along with specific {@link AudioAttributes audio attributes} to
* use during playback.
*
+ * @deprecated use {@link NotificationChannel#setSound(Uri, AudioAttributes)} instead.
* @see Notification#sound
*/
+ @Deprecated
public Builder setSound(Uri sound, AudioAttributes audioAttributes) {
mN.sound = sound;
mN.audioAttributes = audioAttributes;
@@ -2941,8 +3111,10 @@ public class Notification implements Parcelable
* A notification that vibrates is more likely to be presented as a heads-up notification.
* </p>
*
+ * @deprecated use {@link NotificationChannel#setVibrationPattern(long[])} instead.
* @see Notification#vibrate
*/
+ @Deprecated
public Builder setVibrate(long[] pattern) {
mN.vibrate = pattern;
return this;
@@ -2955,11 +3127,12 @@ public class Notification implements Parcelable
* Not all devices will honor all (or even any) of these values.
*
-
+ * @deprecated use {@link NotificationChannel#enableLights(boolean)} instead.
* @see Notification#ledARGB
* @see Notification#ledOnMS
* @see Notification#ledOffMS
*/
+ @Deprecated
public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
mN.ledARGB = argb;
mN.ledOnMS = onMs;
@@ -2992,6 +3165,26 @@ public class Notification implements Parcelable
}
/**
+ * Set whether this notification should be colorized. When set, the color set with
+ * {@link #setColor(int)} will be used as the background color of this notification.
+ * <p>
+ * This should only be used for high priority ongoing tasks like navigation, an ongoing
+ * call, or other similarly high-priority events for the user.
+ * <p>
+ * For most styles, the coloring will only be applied if the notification is ongoing.
+ * However, for {@link MediaStyle} and {@link DecoratedMediaCustomViewStyle} notifications
+ * that have a media session attached there is no requirement for it to be ongoing.
+ *
+ * @see Builder#setOngoing(boolean)
+ * @see Builder#setColor(int)
+ * @see MediaStyle#setMediaSession(MediaSession.Token)
+ */
+ public Builder setColorized(boolean colorize) {
+ mN.extras.putBoolean(EXTRA_COLORIZED, colorize);
+ return this;
+ }
+
+ /**
* Set this flag if you would only like the sound, vibrate
* and ticker to be played if the notification is not already showing.
*
@@ -3031,7 +3224,12 @@ public class Notification implements Parcelable
* {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
* <p>
* For all default values, use {@link #DEFAULT_ALL}.
+ *
+ * @deprecated use {@link NotificationChannel#enableVibration(boolean)} and
+ * {@link NotificationChannel#enableLights(boolean)} and
+ * {@link NotificationChannel#setSound(Uri, AudioAttributes)} instead.
*/
+ @Deprecated
public Builder setDefaults(int defaults) {
mN.defaults = defaults;
return this;
@@ -3041,7 +3239,9 @@ public class Notification implements Parcelable
* Set the priority of this notification.
*
* @see Notification#priority
+ * @deprecated use {@link NotificationChannel#setImportance(int)} instead.
*/
+ @Deprecated
public Builder setPriority(@Priority int pri) {
mN.priority = pri;
return this;
@@ -3356,6 +3556,10 @@ public class Notification implements Parcelable
if (profileBadge != null) {
contentView.setImageViewBitmap(R.id.profile_badge, profileBadge);
contentView.setViewVisibility(R.id.profile_badge, View.VISIBLE);
+ if (isColorized()) {
+ contentView.setDrawableParameters(R.id.profile_badge, false, -1,
+ getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP, -1);
+ }
}
}
@@ -3413,13 +3617,16 @@ public class Notification implements Parcelable
resetStandardTemplate(contentView);
final Bundle ex = mN.extras;
-
+ updateBackgroundColor(contentView);
bindNotificationHeader(contentView, p.ambient);
bindLargeIcon(contentView);
boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, p.title);
+ if (!p.ambient) {
+ setTextViewColorPrimary(contentView, R.id.title);
+ }
contentView.setViewLayoutWidth(R.id.title, showProgress
? ViewGroup.LayoutParams.WRAP_CONTENT
: ViewGroup.LayoutParams.MATCH_PARENT);
@@ -3428,6 +3635,9 @@ public class Notification implements Parcelable
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
contentView.setTextViewText(textId, p.text);
+ if (!p.ambient) {
+ setTextViewColorSecondary(contentView, textId);
+ }
contentView.setViewVisibility(textId, View.VISIBLE);
}
@@ -3436,6 +3646,52 @@ public class Notification implements Parcelable
return contentView;
}
+ private void setTextViewColorPrimary(RemoteViews contentView, int id) {
+ ensureColors();
+ contentView.setTextColor(id, mPrimaryTextColor);
+ }
+
+ private int getPrimaryTextColor() {
+ ensureColors();
+ return mPrimaryTextColor;
+ }
+
+ private int getActionBarColor() {
+ ensureColors();
+ return mActionBarColor;
+ }
+
+ private void setTextViewColorSecondary(RemoteViews contentView, int id) {
+ ensureColors();
+ contentView.setTextColor(id, mSecondaryTextColor);
+ }
+
+ private void ensureColors() {
+ int backgroundColor = getBackgroundColor();
+ if (mPrimaryTextColor == COLOR_INVALID
+ || mSecondaryTextColor == COLOR_INVALID
+ || mActionBarColor == COLOR_INVALID
+ || mTextColorsAreForBackground != backgroundColor) {
+ mTextColorsAreForBackground = backgroundColor;
+ mPrimaryTextColor = NotificationColorUtil.resolvePrimaryColor(
+ mContext, backgroundColor);
+ mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(
+ mContext, backgroundColor);
+ mActionBarColor = NotificationColorUtil.resolveActionBarColor(backgroundColor);
+ }
+ }
+
+ private void updateBackgroundColor(RemoteViews contentView) {
+ if (isColorized()) {
+ contentView.setInt(R.id.status_bar_latest_event_content, "setBackgroundColor",
+ getBackgroundColor());
+ } else {
+ // Clear it!
+ contentView.setInt(R.id.status_bar_latest_event_content, "setBackgroundResource",
+ 0);
+ }
+ }
+
/**
* @param remoteView the remote view to update the minheight in
* @param hasMinHeight does it have a mimHeight
@@ -3502,15 +3758,25 @@ public class Notification implements Parcelable
}
private void bindExpandButton(RemoteViews contentView) {
- contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(),
+ int color = getPrimaryHighlightColor();
+ contentView.setDrawableParameters(R.id.expand_button, false, -1, color,
PorterDuff.Mode.SRC_ATOP, -1);
contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
- resolveContrastColor());
+ color);
+ }
+
+ /**
+ * @return the color that is used as the first primary highlight color. This is applied
+ * in several places like the action buttons or the app name in the header.
+ */
+ private int getPrimaryHighlightColor() {
+ return isColorized() ? getPrimaryTextColor() : resolveContrastColor();
}
private void bindHeaderChronometerAndTime(RemoteViews contentView) {
if (showsTimeOrChronometer()) {
contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
+ setTextViewColorSecondary(contentView, R.id.time_divider);
if (mN.extras.getBoolean(EXTRA_SHOW_CHRONOMETER)) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
@@ -3518,9 +3784,11 @@ public class Notification implements Parcelable
contentView.setBoolean(R.id.chronometer, "setStarted", true);
boolean countsDown = mN.extras.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN);
contentView.setChronometerCountDown(R.id.chronometer, countsDown);
+ setTextViewColorSecondary(contentView, R.id.chronometer);
} else {
contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", mN.when);
+ setTextViewColorSecondary(contentView, R.id.time);
}
} else {
// We still want a time to be set but gone, such that we can show and hide it
@@ -3543,8 +3811,10 @@ public class Notification implements Parcelable
if (headerText != null) {
// TODO: Remove the span entirely to only have the string with propper formating.
contentView.setTextViewText(R.id.header_text, processLegacyText(headerText));
+ setTextViewColorSecondary(contentView, R.id.header_text);
contentView.setViewVisibility(R.id.header_text, View.VISIBLE);
contentView.setViewVisibility(R.id.header_text_divider, View.VISIBLE);
+ setTextViewColorSecondary(contentView, R.id.header_text_divider);
}
}
@@ -3583,8 +3853,12 @@ public class Notification implements Parcelable
}
private void bindHeaderAppName(RemoteViews contentView, boolean ambient) {
contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
- contentView.setTextColor(R.id.app_name_text,
- ambient ? resolveAmbientColor() : resolveContrastColor());
+ if (isColorized() && !ambient) {
+ setTextViewColorPrimary(contentView, R.id.app_name_text);
+ } else {
+ contentView.setTextColor(R.id.app_name_text,
+ ambient ? resolveAmbientColor() : resolveContrastColor());
+ }
}
private void bindSmallIcon(RemoteViews contentView, boolean ambient) {
@@ -3642,6 +3916,11 @@ public class Notification implements Parcelable
big.setViewVisibility(R.id.actions, View.VISIBLE);
if (p.ambient) {
big.setInt(R.id.actions, "setBackgroundColor", Color.TRANSPARENT);
+ } else if (isColorized()) {
+ big.setInt(R.id.actions, "setBackgroundColor", getActionBarColor());
+ } else {
+ big.setInt(R.id.actions, "setBackgroundColor", mContext.getColor(
+ R.color.notification_action_list));
}
big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
R.dimen.notification_action_list_height);
@@ -3663,15 +3942,18 @@ public class Notification implements Parcelable
&& replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
+ setTextViewColorSecondary(big, R.id.notification_material_reply_text_1);
if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_2, replyText[1]);
+ setTextViewColorSecondary(big, R.id.notification_material_reply_text_2);
if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
big.setViewVisibility(
R.id.notification_material_reply_text_3, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_3, replyText[2]);
+ setTextViewColorSecondary(big, R.id.notification_material_reply_text_3);
}
}
}
@@ -3706,10 +3988,24 @@ public class Notification implements Parcelable
* 3. Standard template view
*/
public RemoteViews createContentView() {
+ return createContentView(false /* increasedheight */ );
+ }
+
+ /**
+ * Construct a RemoteViews for the smaller content view.
+ *
+ * @param increasedHeight true if this layout be created with an increased height. Some
+ * styles may support showing more then just that basic 1U size
+ * and the system may decide to render important notifications
+ * slightly bigger even when collapsed.
+ *
+ * @hide
+ */
+ public RemoteViews createContentView(boolean increasedHeight) {
if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.contentView;
} else if (mStyle != null) {
- final RemoteViews styleView = mStyle.makeContentView();
+ final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
if (styleView != null) {
return styleView;
}
@@ -3731,7 +4027,7 @@ public class Notification implements Parcelable
} else if (mActions.size() != 0) {
result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
- adaptNotificationHeaderForBigContentView(result);
+ makeHeaderExpanded(result);
return result;
}
@@ -3766,7 +4062,12 @@ public class Notification implements Parcelable
}
}
- private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
+ /**
+ * Adapt the Notification header if this view is used as an expanded view.
+ *
+ * @hide
+ */
+ public static void makeHeaderExpanded(RemoteViews result) {
if (result != null) {
result.setBoolean(R.id.notification_header, "setExpanded", true);
}
@@ -3826,7 +4127,57 @@ public class Notification implements Parcelable
return publicView;
}
+ /**
+ * Construct a content view for the display when low - priority
+ *
+ * @param useRegularSubtext uses the normal subtext set if there is one available. Otherwise
+ * a new subtext is created consisting of the content of the
+ * notification.
+ * @hide
+ */
+ public RemoteViews makeLowPriorityContentView(boolean useRegularSubtext) {
+ int color = mN.color;
+ mN.color = COLOR_DEFAULT;
+ CharSequence summary = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
+ if (!useRegularSubtext || TextUtils.isEmpty(summary)) {
+ CharSequence newSummary = createSummaryText();
+ if (!TextUtils.isEmpty(newSummary)) {
+ mN.extras.putCharSequence(EXTRA_SUB_TEXT, newSummary);
+ }
+ }
+ RemoteViews header = makeNotificationHeader();
+ if (summary != null) {
+ mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);
+ } else {
+ mN.extras.remove(EXTRA_SUB_TEXT);
+ }
+ mN.color = color;
+ return header;
+ }
+ private CharSequence createSummaryText() {
+ CharSequence titleText = mN.extras.getCharSequence(Notification.EXTRA_TITLE);
+ if (USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY) {
+ return titleText;
+ }
+ SpannableStringBuilder summary = new SpannableStringBuilder();
+ if (titleText == null) {
+ titleText = mN.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
+ }
+ BidiFormatter bidi = BidiFormatter.getInstance();
+ if (titleText != null) {
+ summary.append(bidi.unicodeWrap(titleText));
+ }
+ CharSequence contentText = mN.extras.getCharSequence(Notification.EXTRA_TEXT);
+ if (titleText != null && contentText != null) {
+ summary.append(bidi.unicodeWrap(mContext.getText(
+ R.string.notification_header_divider_symbol_with_spaces)));
+ }
+ if (contentText != null) {
+ summary.append(bidi.unicodeWrap(contentText));
+ }
+ return summary;
+ }
private RemoteViews generateActionButton(Action action, boolean emphazisedMode,
boolean oddAction, boolean ambient) {
@@ -3842,6 +4193,7 @@ public class Notification implements Parcelable
if (action.mRemoteInputs != null) {
button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
}
+ // TODO: handle emphasized mode / actions right
if (emphazisedMode) {
// change the background bgColor
int bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
@@ -3857,16 +4209,19 @@ public class Notification implements Parcelable
title = ensureColorSpanContrast(title, bgColor, outResultColor);
}
button.setTextViewText(R.id.action0, title);
+ setTextViewColorPrimary(button, R.id.action0);
if (outResultColor != null && outResultColor[0] != null) {
// We need to set the text color as well since changing a text to uppercase
// clears its spans.
button.setTextColor(R.id.action0, outResultColor[0]);
- } else if (mN.color != COLOR_DEFAULT) {
+ } else if (mN.color != COLOR_DEFAULT && !isColorized()) {
button.setTextColor(R.id.action0,resolveContrastColor());
}
} else {
button.setTextViewText(R.id.action0, processLegacyText(action.title));
- if (mN.color != COLOR_DEFAULT) {
+ if (isColorized() && !ambient) {
+ setTextViewColorPrimary(button, R.id.action0);
+ } else if (mN.color != COLOR_DEFAULT) {
button.setTextColor(R.id.action0,
ambient ? resolveAmbientColor() : resolveContrastColor());
}
@@ -3985,11 +4340,16 @@ public class Notification implements Parcelable
* doesn't create material notifications by itself) app.
*/
private boolean isLegacy() {
- return getColorUtil() != null;
+ if (!mIsLegacyInitialized) {
+ mIsLegacy = mContext.getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.LOLLIPOP;
+ mIsLegacyInitialized = true;
+ }
+ return mIsLegacy;
}
private CharSequence processLegacyText(CharSequence charSequence) {
- if (isLegacy()) {
+ if (isLegacy() || textColorsNeedInversion()) {
return getColorUtil().invertCharSequenceColors(charSequence);
} else {
return charSequence;
@@ -4002,7 +4362,7 @@ public class Notification implements Parcelable
private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
boolean ambient) {
boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
- int color = ambient ? resolveAmbientColor() : resolveContrastColor();
+ int color = ambient ? resolveAmbientColor() : getPrimaryHighlightColor();
if (colorable) {
contentView.setDrawableParameters(R.id.icon, false, -1, color,
PorterDuff.Mode.SRC_ATOP, -1);
@@ -4251,6 +4611,78 @@ public class Notification implements Parcelable
private int getActionTombstoneLayoutResource() {
return R.layout.notification_material_action_tombstone;
}
+
+ private int getBackgroundColor() {
+ if (isColorized()) {
+ return mN.color;
+ } else {
+ return COLOR_DEFAULT;
+ }
+ }
+
+ private boolean isColorized() {
+ return mN.isColorized();
+ }
+
+ private boolean textColorsNeedInversion() {
+ if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) {
+ return false;
+ }
+ int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ return targetSdkVersion > Build.VERSION_CODES.M
+ && targetSdkVersion < Build.VERSION_CODES.O;
+ }
+ }
+
+ /**
+ * @return whether this notification is ongoing and can't be dismissed by the user.
+ */
+ private boolean isOngoing() {
+ final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE
+ | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
+ return (flags & ongoingFlags) != 0;
+ }
+
+ /**
+ * @return whether this notification has a media session attached
+ * @hide
+ */
+ public boolean hasMediaSession() {
+ return extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null;
+ }
+
+ /**
+ * @return the style class of this notification
+ * @hide
+ */
+ public Class<? extends Notification.Style> getNotificationStyle() {
+ String templateClass = extras.getString(Notification.EXTRA_TEMPLATE);
+
+ if (!TextUtils.isEmpty(templateClass)) {
+ return Notification.getNotificationStyleClass(templateClass);
+ }
+ return null;
+ }
+
+ /**
+ * @return true if this notification is colorized. This also factors in whether the
+ * notification is ongoing.
+ *
+ * @hide
+ */
+ public boolean isColorized() {
+ Class<? extends Style> style = getNotificationStyle();
+ if (MediaStyle.class.equals(style)) {
+ Boolean colorized = (Boolean) extras.get(EXTRA_COLORIZED);
+ if ((colorized == null || colorized) && hasMediaSession()) {
+ return true;
+ }
+ } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
+ if (extras.getBoolean(EXTRA_COLORIZED) && hasMediaSession()) {
+ return true;
+ }
+ }
+ return extras.getBoolean(EXTRA_COLORIZED) && isOngoing();
}
private boolean hasLargeIcon() {
@@ -4364,11 +4796,13 @@ public class Notification implements Parcelable
}
/**
- * Construct a Style-specific RemoteViews for the final 1U notification layout.
+ * Construct a Style-specific RemoteViews for the collapsed notification layout.
* The default implementation has nothing additional to add.
+ *
+ * @param increasedHeight true if this layout be created with an increased height.
* @hide
*/
- public RemoteViews makeContentView() {
+ public RemoteViews makeContentView(boolean increasedHeight) {
return null;
}
@@ -4584,6 +5018,7 @@ public class Notification implements Parcelable
RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
if (mSummaryTextSet) {
contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(mSummaryText));
+ mBuilder.setTextViewColorSecondary(contentView, R.id.text);
contentView.setViewVisibility(R.id.text, View.VISIBLE);
}
mBuilder.setContentMinHeight(contentView, mBuilder.mN.hasLargeIcon());
@@ -4713,6 +5148,23 @@ public class Notification implements Parcelable
}
/**
+ * @param increasedHeight true if this layout be created with an increased height.
+ *
+ * @hide
+ */
+ @Override
+ public RemoteViews makeContentView(boolean increasedHeight) {
+ if (increasedHeight) {
+ ArrayList<Action> actions = mBuilder.mActions;
+ mBuilder.mActions = new ArrayList<>();
+ RemoteViews remoteViews = makeBigContentView();
+ mBuilder.mActions = actions;
+ return remoteViews;
+ }
+ return super.makeContentView(increasedHeight);
+ }
+
+ /**
* @hide
*/
public RemoteViews makeBigContentView() {
@@ -4739,6 +5191,7 @@ public class Notification implements Parcelable
static void applyBigTextContentView(Builder builder,
RemoteViews contentView, CharSequence bigTextText) {
contentView.setTextViewText(R.id.big_text, bigTextText);
+ builder.setTextViewColorSecondary(contentView, R.id.big_text);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines(builder));
@@ -4789,6 +5242,7 @@ public class Notification implements Parcelable
CharSequence mUserDisplayName;
CharSequence mConversationTitle;
List<Message> mMessages = new ArrayList<>();
+ List<Message> mHistoricMessages = new ArrayList<>();
MessagingStyle() {
}
@@ -4845,15 +5299,15 @@ public class Notification implements Parcelable
* @return this object for method chaining
*/
public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) {
- mMessages.add(new Message(text, timestamp, sender));
- if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) {
- mMessages.remove(0);
- }
- return this;
+ return addMessage(new Message(text, timestamp, sender));
}
/**
* Adds a {@link Message} for display in this notification.
+ *
+ * <p>The messages should be added in chronologic order, i.e. the oldest first,
+ * the newest last.
+ *
* @param message The {@link Message} to be displayed
* @return this object for method chaining
*/
@@ -4866,6 +5320,27 @@ public class Notification implements Parcelable
}
/**
+ * Adds a {@link Message} for historic context in this notification.
+ *
+ * <p>Messages should be added as historic if they are not the main subject of the
+ * notification but may give context to a conversation. The system may choose to present
+ * them only when relevant, e.g. when replying to a message through a {@link RemoteInput}.
+ *
+ * <p>The messages should be added in chronologic order, i.e. the oldest first,
+ * the newest last.
+ *
+ * @param message The historic {@link Message} to be added
+ * @return this object for method chaining
+ */
+ public MessagingStyle addHistoricMessage(Message message) {
+ mHistoricMessages.add(message);
+ if (mHistoricMessages.size() > MAXIMUM_RETAINED_MESSAGES) {
+ mHistoricMessages.remove(0);
+ }
+ return this;
+ }
+
+ /**
* Gets the list of {@code Message} objects that represent the notification
*/
public List<Message> getMessages() {
@@ -4873,6 +5348,13 @@ public class Notification implements Parcelable
}
/**
+ * Gets the list of historic {@code Message}s in the notification.
+ */
+ public List<Message> getHistoricMessages() {
+ return mHistoricMessages;
+ }
+
+ /**
* @hide
*/
@Override
@@ -4887,6 +5369,9 @@ public class Notification implements Parcelable
if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES,
Message.getBundleArrayForMessages(mMessages));
}
+ if (!mHistoricMessages.isEmpty()) { extras.putParcelableArray(EXTRA_HISTORIC_MESSAGES,
+ Message.getBundleArrayForMessages(mHistoricMessages));
+ }
fixTitleAndTextExtras(extras);
}
@@ -4926,11 +5411,16 @@ public class Notification implements Parcelable
super.restoreFromExtras(extras);
mMessages.clear();
+ mHistoricMessages.clear();
mUserDisplayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
mConversationTitle = extras.getCharSequence(EXTRA_CONVERSATION_TITLE);
- Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES);
- if (parcelables != null && parcelables instanceof Parcelable[]) {
- mMessages = Message.getMessagesFromBundleArray(parcelables);
+ Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+ if (messages != null && messages instanceof Parcelable[]) {
+ mMessages = Message.getMessagesFromBundleArray(messages);
+ }
+ Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
+ if (histMessages != null && histMessages instanceof Parcelable[]) {
+ mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
}
}
@@ -4938,17 +5428,25 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView() {
- Message m = findLatestIncomingMessage();
- CharSequence title = mConversationTitle != null
- ? mConversationTitle
- : (m == null) ? null : m.mSender;
- CharSequence text = (m == null)
- ? null
- : mConversationTitle != null ? makeMessageLine(m) : m.mText;
-
- return mBuilder.applyStandardTemplateWithActions(mBuilder.getBaseLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
+ public RemoteViews makeContentView(boolean increasedHeight) {
+ if (!increasedHeight) {
+ Message m = findLatestIncomingMessage();
+ CharSequence title = mConversationTitle != null
+ ? mConversationTitle
+ : (m == null) ? null : m.mSender;
+ CharSequence text = (m == null)
+ ? null
+ : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
+
+ return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(),
+ mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
+ } else {
+ ArrayList<Action> actions = mBuilder.mActions;
+ mBuilder.mActions = new ArrayList<>();
+ RemoteViews remoteViews = makeBigContentView();
+ mBuilder.mActions = actions;
+ return remoteViews;
+ }
}
private Message findLatestIncomingMessage() {
@@ -4983,7 +5481,7 @@ public class Notification implements Parcelable
CharSequence text;
if (hasTitle) {
bigTitle = title;
- text = makeMessageLine(mMessages.get(0));
+ text = makeMessageLine(mMessages.get(0), mBuilder);
} else {
bigTitle = mMessages.get(0).mSender;
text = mMessages.get(0).mText;
@@ -5015,13 +5513,29 @@ public class Notification implements Parcelable
int contractedChildId = View.NO_ID;
Message contractedMessage = findLatestIncomingMessage();
+ int firstHistoricMessage = Math.max(0, mHistoricMessages.size()
+ - (rowIds.length - mMessages.size()));
+ while (firstHistoricMessage + i < mHistoricMessages.size() && i < rowIds.length) {
+ Message m = mHistoricMessages.get(firstHistoricMessage + i);
+ int rowId = rowIds[i];
+
+ contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
+
+ if (contractedMessage == m) {
+ contractedChildId = rowId;
+ }
+
+ i++;
+ }
+
int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
while (firstMessage + i < mMessages.size() && i < rowIds.length) {
Message m = mMessages.get(firstMessage + i);
int rowId = rowIds[i];
contentView.setViewVisibility(rowId, View.VISIBLE);
- contentView.setTextViewText(rowId, makeMessageLine(m));
+ contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
+ mBuilder.setTextViewColorSecondary(contentView, rowId);
if (contractedMessage == m) {
contractedChildId = rowId;
@@ -5029,23 +5543,36 @@ public class Notification implements Parcelable
i++;
}
+ // Clear the remaining views for reapply. Ensures that historic message views can
+ // reliably be identified as being GONE and having non-null text.
+ while (i < rowIds.length) {
+ int rowId = rowIds[i];
+ contentView.setTextViewText(rowId, null);
+ i++;
+ }
+
// Record this here to allow transformation between the contracted and expanded views.
contentView.setInt(R.id.notification_messaging, "setContractedChildId",
contractedChildId);
return contentView;
}
- private CharSequence makeMessageLine(Message m) {
+ private CharSequence makeMessageLine(Message m, Builder builder) {
BidiFormatter bidi = BidiFormatter.getInstance();
SpannableStringBuilder sb = new SpannableStringBuilder();
+ boolean colorize = builder.isColorized();
if (TextUtils.isEmpty(m.mSender)) {
CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName;
sb.append(bidi.unicodeWrap(replyName),
- makeFontColorSpan(mBuilder.resolveContrastColor()),
+ makeFontColorSpan(colorize
+ ? builder.getPrimaryTextColor()
+ : mBuilder.resolveContrastColor()),
0 /* flags */);
} else {
sb.append(bidi.unicodeWrap(m.mSender),
- makeFontColorSpan(Color.BLACK),
+ makeFontColorSpan(colorize
+ ? builder.getPrimaryTextColor()
+ : Color.BLACK),
0 /* flags */);
}
CharSequence text = m.mText == null ? "" : m.mText;
@@ -5064,7 +5591,7 @@ public class Notification implements Parcelable
: (m == null) ? null : m.mSender;
CharSequence text = (m == null)
? null
- : mConversationTitle != null ? makeMessageLine(m) : m.mText;
+ : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
@@ -5355,6 +5882,7 @@ public class Notification implements Parcelable
if (!TextUtils.isEmpty(str)) {
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str));
+ mBuilder.setTextViewColorSecondary(contentView, rowIds[i]);
contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0);
handleInboxImageMargin(contentView, rowIds[i], first);
if (first) {
@@ -5399,21 +5927,27 @@ public class Notification implements Parcelable
* shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to
* {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will be
* treated as album artwork.
- *
+ * <p>
* Unlike the other styles provided here, MediaStyle can also modify the standard-size
* {@link Notification#contentView}; by providing action indices to
* {@link #setShowActionsInCompactView(int...)} you can promote up to 3 actions to be displayed
* in the standard view alongside the usual content.
- *
+ * <p>
* Notifications created with MediaStyle will have their category set to
* {@link Notification#CATEGORY_TRANSPORT CATEGORY_TRANSPORT} unless you set a different
* category using {@link Notification.Builder#setCategory(String) setCategory()}.
- *
+ * <p>
* Finally, if you attach a {@link android.media.session.MediaSession.Token} using
* {@link android.app.Notification.MediaStyle#setMediaSession(MediaSession.Token)},
* the System UI can identify this as a notification representing an active media session
* and respond accordingly (by showing album artwork in the lockscreen, for example).
*
+ * <p>
+ * Starting at {@link android.os.Build.VERSION_CODES#O Android O} any notification that has a
+ * media session attached with {@link #setMediaSession(MediaSession.Token)} will be colorized.
+ * You can opt-out of this behavior by using {@link Notification.Builder#setColorized(boolean)}.
+ * <p>
+ *
* To use this style with your Notification, feed it to
* {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
* <pre class="prettyprint">
@@ -5428,6 +5962,7 @@ public class Notification implements Parcelable
* </pre>
*
* @see Notification#bigContentView
+ * @see Notification.Builder#setColorized(boolean)
*/
public static class MediaStyle extends Style {
static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
@@ -5483,7 +6018,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView() {
+ public RemoteViews makeContentView(boolean increasedHeight) {
return makeMediaContentView();
}
@@ -5565,7 +6100,7 @@ public class Notification implements Parcelable
final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
final RemoteViews button = generateMediaActionButton(action,
- mBuilder.resolveContrastColor());
+ getPrimaryHighlightColor());
view.addView(com.android.internal.R.id.media_actions, button);
}
}
@@ -5579,6 +6114,10 @@ public class Notification implements Parcelable
return view;
}
+ private int getPrimaryHighlightColor() {
+ return mBuilder.getPrimaryHighlightColor();
+ }
+
private RemoteViews makeMediaBigContentView() {
final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
// Dont add an expanded view if there is no more content to be revealed
@@ -5596,7 +6135,7 @@ public class Notification implements Parcelable
big.removeAllViews(com.android.internal.R.id.media_actions);
for (int i = 0; i < actionCount; i++) {
final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
- mBuilder.resolveContrastColor());
+ getPrimaryHighlightColor());
big.addView(com.android.internal.R.id.media_actions, button);
}
}
@@ -5659,7 +6198,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView() {
+ public RemoteViews makeContentView(boolean increasedHeight) {
return makeStandardTemplateWithCustomContent(mBuilder.mN.contentView);
}
@@ -5741,7 +6280,10 @@ public class Notification implements Parcelable
* {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
* {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
* corresponding custom views to display.
- *
+ * <p>
+ * Contrary to {@link MediaStyle} a developer has to opt-in to the colorizing of the
+ * notification by using {@link Notification.Builder#setColorized(boolean)}.
+ * <p>
* To use this style with your Notification, feed it to
* {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
* <pre class="prettyprint">
@@ -5773,8 +6315,8 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView() {
- RemoteViews remoteViews = super.makeContentView();
+ public RemoteViews makeContentView(boolean increasedHeight) {
+ RemoteViews remoteViews = super.makeContentView(false /* increasedHeight */);
return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
mBuilder.mN.contentView);
}
@@ -5796,7 +6338,7 @@ public class Notification implements Parcelable
return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
customRemoteView);
} else if (customRemoteView != mBuilder.mN.contentView){
- remoteViews = super.makeContentView();
+ remoteViews = super.makeContentView(false /* increasedHeight */);
return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
customRemoteView);
} else {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index be5f80a82b1b..1a516087a6e5 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -21,6 +21,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.annotation.SystemApi;
+import android.graphics.Color;
+import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -49,13 +51,16 @@ public final class NotificationChannel implements Parcelable {
private static final String ATT_VISIBILITY = "visibility";
private static final String ATT_IMPORTANCE = "importance";
private static final String ATT_LIGHTS = "lights";
+ private static final String ATT_LIGHT_COLOR = "light_color";
private static final String ATT_VIBRATION = "vibration";
private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
private static final String ATT_SOUND = "sound";
- //TODO: add audio attributes support
- private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes";
+ private static final String ATT_USAGE = "usage";
+ private static final String ATT_FLAGS = "flags";
+ private static final String ATT_CONTENT_TYPE = "content_type";
private static final String ATT_SHOW_BADGE = "show_badge";
private static final String ATT_USER_LOCKED = "locked";
+ private static final String ATT_GROUP = "group";
private static final String DELIMITER = ",";
/**
@@ -105,6 +110,12 @@ public final class NotificationChannel implements Parcelable {
* @hide
*/
@SystemApi
+ public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 0x00000100;
+
+ /**
+ * @hide
+ */
+ @SystemApi
public static final int[] LOCKABLE_FIELDS = new int[] {
USER_LOCKED_PRIORITY,
USER_LOCKED_VISIBILITY,
@@ -113,10 +124,11 @@ public final class NotificationChannel implements Parcelable {
USER_LOCKED_VIBRATION,
USER_LOCKED_SOUND,
USER_LOCKED_ALLOWED,
- USER_LOCKED_SHOW_BADGE
+ USER_LOCKED_SHOW_BADGE,
+ USER_LOCKED_AUDIO_ATTRIBUTES
};
-
+ private static final int DEFAULT_LIGHT_COLOR = 0;
private static final int DEFAULT_VISIBILITY =
NotificationManager.VISIBILITY_NO_OVERRIDE;
private static final int DEFAULT_IMPORTANCE =
@@ -131,11 +143,14 @@ public final class NotificationChannel implements Parcelable {
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
private Uri mSound;
private boolean mLights;
+ private int mLightColor = DEFAULT_LIGHT_COLOR;
private long[] mVibration;
private int mUserLockedFields;
private boolean mVibrationEnabled;
private boolean mShowBadge = DEFAULT_SHOW_BADGE;
private boolean mDeleted = DEFAULT_DELETED;
+ private String mGroup;
+ private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
/**
* Creates a notification channel.
@@ -173,6 +188,13 @@ public final class NotificationChannel implements Parcelable {
mVibrationEnabled = in.readByte() != 0;
mShowBadge = in.readByte() != 0;
mDeleted = in.readByte() != 0;
+ if (in.readByte() != 0) {
+ mGroup = in.readString();
+ } else {
+ mGroup = null;
+ }
+ mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
+ mLightColor = in.readInt();
}
@Override
@@ -199,6 +221,19 @@ public final class NotificationChannel implements Parcelable {
dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0);
dest.writeByte(mDeleted ? (byte) 1 : (byte) 0);
+ if (mGroup != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mGroup);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ if (mAudioAttributes != null) {
+ dest.writeInt(1);
+ mAudioAttributes.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(mLightColor);
}
/**
@@ -255,6 +290,21 @@ public final class NotificationChannel implements Parcelable {
// Modifiable by apps on channel creation.
/**
+ * Sets what group this channel belongs to.
+ *
+ * Group information is only used for presentation, not for behavior.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
+ *
+ * @param groupId the id of a group created by
+ * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.
+ */
+ public void setGroup(String groupId) {
+ this.mGroup = groupId;
+ }
+
+ /**
* Sets whether notifications posted to this channel can appear as application icon badges
* in a Launcher.
*
@@ -265,37 +315,60 @@ public final class NotificationChannel implements Parcelable {
}
/**
- * Sets the sound that should be played for notifications posted to this channel if
- * the notifications don't supply a sound. Only modifiable before the channel is submitted
- * to the NotificationManager.
+ * Sets the sound that should be played for notifications posted to this channel and its
+ * audio attributes.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
*/
- public void setSound(Uri sound) {
+ public void setSound(Uri sound, AudioAttributes audioAttributes) {
this.mSound = sound;
+ this.mAudioAttributes = audioAttributes;
}
/**
* Sets whether notifications posted to this channel should display notification lights,
- * on devices that support that feature. Only modifiable before the channel is submitted to
- * the NotificationManager.
+ * on devices that support that feature.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
*/
- public void setLights(boolean lights) {
+ public void enableLights(boolean lights) {
this.mLights = lights;
}
/**
+ * Sets the notification light color for notifications posted to this channel, if lights are
+ * {@link #enableLights(boolean) enabled} on this channel and the device supports that feature.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
+ */
+ public void setLightColor(int argb) {
+ this.mLightColor = argb;
+ }
+
+ /**
* Sets whether notification posted to this channel should vibrate. The vibration pattern can
- * be set with {@link #setVibrationPattern(long[])}. Only modifiable before the channel is
- * submitted to the NotificationManager.
+ * be set with {@link #setVibrationPattern(long[])}.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
*/
public void enableVibration(boolean vibration) {
this.mVibrationEnabled = vibration;
}
/**
- * Sets whether notification posted to this channel should vibrate. Only modifiable before the
- * channel is submitted to the NotificationManager.
+ * Sets the vibration pattern for notifications posted to this channel. If the provided
+ * pattern is valid (non-null, non-empty), will {@link #enableVibration(boolean)} enable
+ * vibration} as well. Otherwise, vibration will be disabled.
+ *
+ * Only modifiable before the channel is submitted to
+ * {@link NotificationManager#notify(String, int, Notification)}.
*/
public void setVibrationPattern(long[] vibrationPattern) {
+ this.mVibrationEnabled = vibrationPattern != null && vibrationPattern.length > 0;
this.mVibration = vibrationPattern;
}
@@ -337,6 +410,13 @@ public final class NotificationChannel implements Parcelable {
}
/**
+ * Returns the audio attributes for sound played by notifications posted to this channel.
+ */
+ public AudioAttributes getAudioAttributes() {
+ return mAudioAttributes;
+ }
+
+ /**
* Returns whether notifications posted to this channel trigger notification lights.
*/
public boolean shouldShowLights() {
@@ -344,6 +424,14 @@ public final class NotificationChannel implements Parcelable {
}
/**
+ * Returns the notification light color for notifications posted to this channel. Irrelevant
+ * unless {@link #shouldShowLights()}.
+ */
+ public int getLightColor() {
+ return mLightColor;
+ }
+
+ /**
* Returns whether notifications posted to this channel always vibrate.
*/
public boolean shouldVibrate() {
@@ -377,6 +465,15 @@ public final class NotificationChannel implements Parcelable {
}
/**
+ * Returns what group this channel belongs to.
+ *
+ * This is used only for visually grouping channels in the UI.
+ */
+ public String getGroup() {
+ return mGroup;
+ }
+
+ /**
* @hide
*/
@SystemApi
@@ -401,12 +498,14 @@ public final class NotificationChannel implements Parcelable {
setBypassDnd(Notification.PRIORITY_DEFAULT
!= safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
- setSound(safeUri(parser, ATT_SOUND));
- setLights(safeBool(parser, ATT_LIGHTS, false));
+ setSound(safeUri(parser, ATT_SOUND), safeAudioAttributes(parser));
+ enableLights(safeBool(parser, ATT_LIGHTS, false));
+ setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
setDeleted(safeBool(parser, ATT_DELETED, false));
+ setGroup(parser.getAttributeValue(null, ATT_GROUP));
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
}
@@ -433,9 +532,18 @@ public final class NotificationChannel implements Parcelable {
if (getSound() != null) {
out.attribute(null, ATT_SOUND, getSound().toString());
}
+ if (getAudioAttributes() != null) {
+ out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
+ out.attribute(null, ATT_CONTENT_TYPE,
+ Integer.toString(getAudioAttributes().getContentType()));
+ out.attribute(null, ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
+ }
if (shouldShowLights()) {
out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
}
+ if (getLightColor() != DEFAULT_LIGHT_COLOR) {
+ out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
+ }
if (shouldVibrate()) {
out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
}
@@ -451,6 +559,9 @@ public final class NotificationChannel implements Parcelable {
if (isDeleted()) {
out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
}
+ if (getGroup() != null) {
+ out.attribute(null, ATT_GROUP, getGroup());
+ }
out.endTag(null, TAG_CHANNEL);
}
@@ -476,15 +587,35 @@ public final class NotificationChannel implements Parcelable {
if (getSound() != null) {
record.put(ATT_SOUND, getSound().toString());
}
+ if (getAudioAttributes() != null) {
+ record.put(ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
+ record.put(ATT_CONTENT_TYPE,
+ Integer.toString(getAudioAttributes().getContentType()));
+ record.put(ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
+ }
record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+ record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
record.put(ATT_DELETED, Boolean.toString(isDeleted()));
+ record.put(ATT_GROUP, getGroup());
return record;
}
+ private static AudioAttributes safeAudioAttributes(XmlPullParser parser) {
+ int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION);
+ int contentType = safeInt(parser, ATT_CONTENT_TYPE,
+ AudioAttributes.CONTENT_TYPE_SONIFICATION);
+ int flags = safeInt(parser, ATT_FLAGS, 0);
+ return new AudioAttributes.Builder()
+ .setUsage(usage)
+ .setContentType(contentType)
+ .setFlags(flags)
+ .build();
+ }
+
private static Uri safeUri(XmlPullParser parser, String att) {
final String val = parser.getAttributeValue(null, att);
return val == null ? null : Uri.parse(val);
@@ -527,10 +658,12 @@ public final class NotificationChannel implements Parcelable {
private static String longArrayToString(long[] values) {
StringBuffer sb = new StringBuffer();
- for (int i = 0; i < values.length - 1; i++) {
- sb.append(values[i]).append(DELIMITER);
+ if (values != null) {
+ for (int i = 0; i < values.length - 1; i++) {
+ sb.append(values[i]).append(DELIMITER);
+ }
+ sb.append(values[values.length - 1]);
}
- sb.append(values[values.length - 1]);
return sb.toString();
}
@@ -558,35 +691,48 @@ public final class NotificationChannel implements Parcelable {
NotificationChannel that = (NotificationChannel) o;
- if (mImportance != that.mImportance) return false;
+ if (getImportance() != that.getImportance()) return false;
if (mBypassDnd != that.mBypassDnd) return false;
- if (mLockscreenVisibility != that.mLockscreenVisibility) return false;
+ if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
if (mLights != that.mLights) return false;
- if (mUserLockedFields != that.mUserLockedFields) return false;
+ if (getLightColor() != that.getLightColor()) return false;
+ if (getUserLockedFields() != that.getUserLockedFields()) return false;
if (mVibrationEnabled != that.mVibrationEnabled) return false;
if (mShowBadge != that.mShowBadge) return false;
- if (mDeleted != that.mDeleted) return false;
- if (mId != null ? !mId.equals(that.mId) : that.mId != null) return false;
- if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
- if (mSound != null ? !mSound.equals(that.mSound) : that.mSound != null) return false;
- return Arrays.equals(mVibration, that.mVibration);
+ if (isDeleted() != that.isDeleted()) return false;
+ if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
+ return false;
+ }
+ if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) {
+ return false;
+ }
+ if (!Arrays.equals(mVibration, that.mVibration)) return false;
+ if (getGroup() != null ? !getGroup().equals(that.getGroup()) : that.getGroup() != null) {
+ return false;
+ }
+ return getAudioAttributes() != null ? getAudioAttributes().equals(that.getAudioAttributes())
+ : that.getAudioAttributes() == null;
}
@Override
public int hashCode() {
- int result = mId != null ? mId.hashCode() : 0;
- result = 31 * result + (mName != null ? mName.hashCode() : 0);
- result = 31 * result + mImportance;
+ int result = getId() != null ? getId().hashCode() : 0;
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + getImportance();
result = 31 * result + (mBypassDnd ? 1 : 0);
- result = 31 * result + mLockscreenVisibility;
- result = 31 * result + (mSound != null ? mSound.hashCode() : 0);
+ result = 31 * result + getLockscreenVisibility();
+ result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
result = 31 * result + (mLights ? 1 : 0);
+ result = 31 * result + getLightColor();
result = 31 * result + Arrays.hashCode(mVibration);
- result = 31 * result + mUserLockedFields;
+ result = 31 * result + getUserLockedFields();
result = 31 * result + (mVibrationEnabled ? 1 : 0);
result = 31 * result + (mShowBadge ? 1 : 0);
- result = 31 * result + (mDeleted ? 1 : 0);
+ result = 31 * result + (isDeleted() ? 1 : 0);
+ result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0);
+ result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0);
return result;
}
@@ -600,11 +746,14 @@ public final class NotificationChannel implements Parcelable {
", mLockscreenVisibility=" + mLockscreenVisibility +
", mSound=" + mSound +
", mLights=" + mLights +
+ ", mLightColor=" + mLightColor +
", mVibration=" + Arrays.toString(mVibration) +
", mUserLockedFields=" + mUserLockedFields +
", mVibrationEnabled=" + mVibrationEnabled +
", mShowBadge=" + mShowBadge +
", mDeleted=" + mDeleted +
+ ", mGroup='" + mGroup + '\'' +
+ ", mAudioAttributes=" + mAudioAttributes +
'}';
}
}
diff --git a/core/java/android/app/NotificationChannelGroup.aidl b/core/java/android/app/NotificationChannelGroup.aidl
new file mode 100644
index 000000000000..c0da037cccd1
--- /dev/null
+++ b/core/java/android/app/NotificationChannelGroup.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable NotificationChannelGroup; \ No newline at end of file
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
new file mode 100644
index 000000000000..68cac27cb7ca
--- /dev/null
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -0,0 +1,187 @@
+/*
+ * 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.app;
+
+import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.notification.NotificationListenerService;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A grouping of related notification channels. e.g., channels that all belong to a single account.
+ */
+public final class NotificationChannelGroup implements Parcelable {
+
+ private static final String TAG_GROUP = "channelGroup";
+ private static final String ATT_NAME = "name";
+ private static final String ATT_ID = "id";
+
+ private final String mId;
+ private CharSequence mName;
+ private List<NotificationChannel> mChannels = new ArrayList<>();
+
+ /**
+ * Creates a notification channel.
+ *
+ * @param id The id of the group. Must be unique per package.
+ * @param name The user visible name of the group.
+ */
+ public NotificationChannelGroup(String id, CharSequence name) {
+ this.mId = id;
+ this.mName = name;
+ }
+
+ protected NotificationChannelGroup(Parcel in) {
+ if (in.readByte() != 0) {
+ mId = in.readString();
+ } else {
+ mId = null;
+ }
+ mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mId != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mId);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ TextUtils.writeToParcel(mName, dest, flags);
+ dest.writeParcelableList(mChannels, flags);
+ }
+
+ /**
+ * Returns the id of this channel.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the user visible name of this channel.
+ */
+ public CharSequence getName() {
+ return mName;
+ }
+
+ /*
+ * Returns the list of channels that belong to this group
+ *
+ * @hide
+ */
+ @SystemApi
+ public List<NotificationChannel> getChannels() {
+ return mChannels;
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public void addChannel(NotificationChannel channel) {
+ mChannels.add(channel);
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public void writeXml(XmlSerializer out) throws IOException {
+ out.startTag(null, TAG_GROUP);
+
+ out.attribute(null, ATT_ID, getId());
+ out.attribute(null, ATT_NAME, getName().toString());
+
+ out.endTag(null, TAG_GROUP);
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public JSONObject toJson() throws JSONException {
+ JSONObject record = new JSONObject();
+ record.put(ATT_ID, getId());
+ record.put(ATT_NAME, getName());
+ return record;
+ }
+
+ public static final Creator<NotificationChannelGroup> CREATOR =
+ new Creator<NotificationChannelGroup>() {
+ @Override
+ public NotificationChannelGroup createFromParcel(Parcel in) {
+ return new NotificationChannelGroup(in);
+ }
+
+ @Override
+ public NotificationChannelGroup[] newArray(int size) {
+ return new NotificationChannelGroup[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ NotificationChannelGroup that = (NotificationChannelGroup) o;
+
+ if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
+ return false;
+ }
+ return getChannels() != null ? getChannels().equals(that.getChannels())
+ : that.getChannels() == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = getId() != null ? getId().hashCode() : 0;
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "NotificationChannelGroup{" +
+ "mId='" + mId + '\'' +
+ ", mName=" + mName +
+ '}';
+ }
+}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c0aae6df34fe..5205959361a5 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -383,8 +383,46 @@ public class NotificationManager
}
/**
+ * Creates a group container for {@link NotificationChannel} objects.
+ *
+ * This is a no-op for groups that already exist.
+ * <p>
+ * Group information is only used for presentation, not for behavior. Groups are optional
+ * for channels, and you can have a mix of channels that belong to groups and channels
+ * that do not.
+ * </p>
+ * <p>
+ * For example, if your application supports multiple accounts, and those accounts will
+ * have similar channels, you can create a group for each account with account specific
+ * labels instead of appending account information to each channel's label.
+ * </p>
+ *
+ * @param group The group to create
+ */
+ public void createNotificationChannelGroup(@NonNull NotificationChannelGroup group) {
+ createNotificationChannelGroups(Arrays.asList(group));
+ }
+
+ /**
+ * Creates multiple notification channel groups.
+ *
+ * @param groups The list of groups to create
+ */
+ public void createNotificationChannelGroups(@NonNull List<NotificationChannelGroup> groups) {
+ INotificationManager service = getService();
+ try {
+ service.createNotificationChannelGroups(mContext.getPackageName(),
+ new ParceledListSlice(groups));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a notification channel that notifications can be posted to.
*
+ * This is a no-op for channels that already exist.
+ *
* @param channel the channel to create. Note that the created channel may differ from this
* value. If the channel already exists, it will not be modified.
*/
@@ -1093,7 +1131,7 @@ public class NotificationManager
* can be used from within background operations like broadcast receivers
* or scheduled jobs.
*
- * @param service Description of the service to be stopped. The Intent must be either
+ * @param service Description of the service to be started. The Intent must be either
* fully explicit (supplying a component name) or specify a specific package
* name it is targeted to.
* @param id The identifier for this notification as per
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index cea7c3cbe8c3..f3fe6778375b 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -39,11 +39,16 @@ public class ProfilerInfo implements Parcelable {
/* Automatically stop the profiler when the app goes idle. */
public final boolean autoStopProfiler;
- public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop) {
+ /* Indicates whether to stream the profiling info to the out file continuously. */
+ public final boolean streamingOutput;
+
+ public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
+ boolean streaming) {
profileFile = filename;
profileFd = fd;
samplingInterval = interval;
autoStopProfiler = autoStop;
+ streamingOutput = streaming;
}
public int describeContents() {
@@ -64,6 +69,7 @@ public class ProfilerInfo implements Parcelable {
}
out.writeInt(samplingInterval);
out.writeInt(autoStopProfiler ? 1 : 0);
+ out.writeInt(streamingOutput ? 1 : 0);
}
public static final Parcelable.Creator<ProfilerInfo> CREATOR =
@@ -82,5 +88,6 @@ public class ProfilerInfo implements Parcelable {
profileFd = in.readInt() != 0 ? ParcelFileDescriptor.CREATOR.createFromParcel(in) : null;
samplingInterval = in.readInt();
autoStopProfiler = in.readInt() != 0;
+ streamingOutput = in.readInt() != 0;
}
}
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index a37680f7a8f8..5958bc14d474 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -35,55 +35,30 @@ import java.io.PrintWriter;
*/
public final class RemoteAction implements Parcelable {
- /**
- * Interface definition for a callback to be invoked when an action is invoked.
- */
- public interface OnActionListener {
- /**
- * Called when the associated action is invoked.
- *
- * @param action The action that was invoked.
- */
- void onAction(RemoteAction action);
- }
-
private static final String TAG = "RemoteAction";
- private static final int MESSAGE_ACTION_INVOKED = 1;
-
private final Icon mIcon;
private final CharSequence mTitle;
private final CharSequence mContentDescription;
- private OnActionListener mActionCallback;
- private final Messenger mMessenger;
+ private final PendingIntent mActionIntent;
RemoteAction(Parcel in) {
mIcon = Icon.CREATOR.createFromParcel(in);
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mMessenger = in.readParcelable(Messenger.class.getClassLoader());
+ mActionIntent = PendingIntent.CREATOR.createFromParcel(in);
}
public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title,
- @NonNull CharSequence contentDescription, @NonNull OnActionListener callback) {
- if (icon == null || title == null || contentDescription == null || callback == null) {
+ @NonNull CharSequence contentDescription, @NonNull PendingIntent intent) {
+ if (icon == null || title == null || contentDescription == null || intent == null) {
throw new IllegalArgumentException("Expected icon, title, content description and " +
"action callback");
}
mIcon = icon;
mTitle = title;
mContentDescription = contentDescription;
- mActionCallback = callback;
- mMessenger = new Messenger(new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_ACTION_INVOKED:
- mActionCallback.onAction(RemoteAction.this);
- break;
- }
- }
- });
+ mActionIntent = intent;
}
/**
@@ -108,22 +83,15 @@ public final class RemoteAction implements Parcelable {
}
/**
- * Sends a message that the action was invoked.
- * @hide
+ * Return the action intent.
*/
- public void sendActionInvoked() {
- Message m = Message.obtain();
- m.what = MESSAGE_ACTION_INVOKED;
- try {
- mMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not send action-invoked", e);
- }
+ public @NonNull PendingIntent getActionIntent() {
+ return mActionIntent;
}
@Override
public RemoteAction clone() {
- return new RemoteAction(mIcon, mTitle, mContentDescription, mActionCallback);
+ return new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent);
}
@Override
@@ -136,7 +104,7 @@ public final class RemoteAction implements Parcelable {
mIcon.writeToParcel(out, 0);
TextUtils.writeToParcel(mTitle, out, flags);
TextUtils.writeToParcel(mContentDescription, out, flags);
- out.writeParcelable(mMessenger, flags);
+ mActionIntent.writeToParcel(out, flags);
}
public void dump(String prefix, PrintWriter pw) {
@@ -144,6 +112,7 @@ public final class RemoteAction implements Parcelable {
pw.print("title=" + mTitle);
pw.print(" contentDescription=" + mContentDescription);
pw.print(" icon=" + mIcon);
+ pw.print(" action=" + mActionIntent.getIntent());
pw.println();
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5d8909c1dbae..44db326ba33a 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -30,6 +30,8 @@ import android.app.usage.StorageStatsManager;
import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
+import android.companion.CompanionDeviceManager;
+import android.companion.ICompanionDeviceManager;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.IRestrictionsManager;
@@ -112,8 +114,10 @@ import android.os.health.SystemHealthManager;
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.autofill.IAutoFillManagerService;
import android.service.persistentdata.IPersistentDataBlockService;
import android.service.persistentdata.PersistentDataBlockManager;
+import android.service.vr.IVrManager;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -126,6 +130,7 @@ import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager;
+import android.view.autofill.AutoFillManager;
import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassificationManager;
import android.view.textservice.TextServicesManager;
@@ -631,6 +636,18 @@ final class SystemServiceRegistry {
UserHandle.getAppId(Process.myUid()));
}});
+ registerService(Context.COMPANION_DEVICE_SERVICE, CompanionDeviceManager.class,
+ new CachedServiceFetcher<CompanionDeviceManager>() {
+ @Override
+ public CompanionDeviceManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder iBinder =
+ ServiceManager.getServiceOrThrow(Context.COMPANION_DEVICE_SERVICE);
+ ICompanionDeviceManager service =
+ ICompanionDeviceManager.Stub.asInterface(iBinder);
+ return new CompanionDeviceManager(service, ctx);
+ }});
+
registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
new CachedServiceFetcher<ConsumerIrManager>() {
@Override
@@ -804,6 +821,22 @@ final class SystemServiceRegistry {
IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
return new FontManager(IFontManager.Stub.asInterface(b));
}});
+ registerService(Context.AUTO_FILL_MANAGER_SERVICE, AutoFillManager.class,
+ new CachedServiceFetcher<AutoFillManager>() {
+ @Override
+ public AutoFillManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.AUTO_FILL_MANAGER_SERVICE);
+ IAutoFillManagerService service = IAutoFillManagerService.Stub.asInterface(b);
+ return new AutoFillManager(ctx, service);
+ }});
+
+ registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
+ @Override
+ public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.VR_SERVICE);
+ return new VrManager(IVrManager.Stub.asInterface(b));
+ }
+ });
}
/**
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index 0077db1eb317..bab993f855e9 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -226,7 +226,7 @@ public class TaskStackBuilder {
* Start the task stack constructed by this builder.
*
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*/
public void startActivities(Bundle options) {
@@ -259,7 +259,7 @@ public class TaskStackBuilder {
* {@link Intent#fillIn(Intent, int)} to control which unspecified parts of the
* intent that can be supplied when the actual send happens.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @return The obtained PendingIntent
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 3f467a01bee2..b219f2afd016 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -145,14 +145,25 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
}
@Override
+ public void show() {
+ super.show();
+ getButton(BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (mTimePicker.validateInput()) {
+ if (mTimeSetListener != null) {
+ mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+ mTimePicker.getCurrentMinute());
+ }
+ dismiss();
+ }
+ }
+ });
+ }
+
+ @Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
- case BUTTON_POSITIVE:
- if (mTimeSetListener != null) {
- mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
- mTimePicker.getCurrentMinute());
- }
- break;
case BUTTON_NEGATIVE:
cancel();
break;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 54cc4a096772..1d6f42ecdb0b 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1108,6 +1108,26 @@ public final class UiAutomation {
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
/* do nothing */
}
+
+ @Override
+ public void onFingerprintCapturingGesturesChanged(boolean active) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onFingerprintGesture(int gesture) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onAccessibilityButtonClicked() {
+ /* do nothing */
+ }
+
+ @Override
+ public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+ /* do nothing */
+ }
});
}
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 2572a2021e24..af41a7d5ac5d 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -271,6 +271,21 @@ public class UiModeManager {
}
/**
+ * Gets the valid inputs to {@link #setTheme(String)}.
+ * @hide
+ */
+ public String[] getAvailableThemes() {
+ if (mService != null) {
+ try {
+ return mService.getAvailableThemes();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the currently configured night mode.
* <p>
* May be one of:
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
new file mode 100644
index 000000000000..a0b0eeaaf1aa
--- /dev/null
+++ b/core/java/android/app/VrManager.java
@@ -0,0 +1,44 @@
+package android.app;
+
+
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.service.vr.IVrManager;
+
+/**
+ * Used to control aspects of a devices Virtual Reality (VR) capabilities.
+ * <p>
+ * You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ * @hide
+ */
+@SystemApi
+public class VrManager {
+ private final IVrManager mService;
+
+ /**
+ * {@hide}
+ */
+ public VrManager(IVrManager service) {
+ mService = service;
+ }
+
+ /**
+ * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+ * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
+ * by VR viewers to indicate that a device is placed in a VR viewer.
+ *
+ * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+ *
+ * @see Activity#setVrModeEnabled(boolean, ComponentName)
+ * @param enabled true if the device should be placed in persistent VR mode.
+ */
+ public void setPersistentVrModeEnabled(boolean enabled) {
+ try {
+ mService.setPersistentVrModeEnabled(enabled);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index aa56be6f36cd..f1ccabe57e32 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -34,6 +34,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
@@ -376,7 +377,7 @@ public class DevicePolicyManager {
* @hide
*/
public static final String ACTION_BUGREPORT_SHARING_ACCEPTED =
- "com.android.server.action.BUGREPORT_SHARING_ACCEPTED";
+ "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED";
/**
* Action: Bugreport sharing with device owner has been declined by the user.
@@ -384,7 +385,7 @@ public class DevicePolicyManager {
* @hide
*/
public static final String ACTION_BUGREPORT_SHARING_DECLINED =
- "com.android.server.action.BUGREPORT_SHARING_DECLINED";
+ "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED";
/**
* Action: Bugreport has been collected and is dispatched to {@code DevicePolicyManagerService}.
@@ -909,6 +910,16 @@ public class DevicePolicyManager {
* or the organization name.
*
* <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+ *
+ * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a
+ * disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}.
+ * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT}. Here is the example:
+ *
+ * <pre>
+ * &lt;meta-data
+ * android:name="android.app.extra.PROVISIONING_DISCLAIMER_HEADER"
+ * android:resource="@string/disclaimer_header"
+ * /&gt;</pre>
*/
public static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER =
"android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
@@ -931,6 +942,16 @@ public class DevicePolicyManager {
* {@link android.content.ClipData} of the intent too.
*
* <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+ *
+ * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a
+ * disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}.
+ * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}. Here is the example:
+ *
+ * <pre>
+ * &lt;meta-data
+ * android:name="android.app.extra.PROVISIONING_DISCLAIMER_CONTENT"
+ * android:resource="@string/disclaimer_content"
+ * /&gt;</pre>
*/
public static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT =
"android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
@@ -1091,6 +1112,30 @@ public class DevicePolicyManager {
public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
/**
+ * Constant to indicate the feature of disabling the camera. Used as argument to
+ * {@link #createAdminSupportIntent(String)}.
+ * @see #setCameraDisabled(ComponentName, boolean)
+ */
+ public static final String POLICY_DISABLE_CAMERA = "policy_disable_camera";
+
+ /**
+ * Constant to indicate the feature of disabling screen captures. Used as argument to
+ * {@link #createAdminSupportIntent(String)}.
+ * @see #setScreenCaptureDisabled(ComponentName, boolean)
+ */
+ public static final String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
+
+ /**
+ * A String indicating a specific restricted feature. Can be a user restriction from the
+ * {@link UserManager}, e.g. {@link UserManager#DISALLOW_ADJUST_VOLUME}, or one of the values
+ * {@link #POLICY_DISABLE_CAMERA} or {@link #POLICY_DISABLE_SCREEN_CAPTURE}.
+ * @see #createAdminSupportIntent(String)
+ * @hide
+ */
+ @TestApi
+ public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+
+ /**
* Activity action: have the user enter a new password. This activity should
* be launched after using {@link #setPasswordQuality(ComponentName, int)},
* or {@link #setPasswordMinimumLength(ComponentName, int)} to have the user
@@ -1132,6 +1177,23 @@ public class DevicePolicyManager {
= "android.app.action.SHOW_DEVICE_MONITORING_DIALOG";
/**
+ * Broadcast Action: Sent after application delegation scopes are changed. The new delegation
+ * scopes will be sent in an {@code ArrayList<String>} extra identified by the
+ * {@link #EXTRA_DELEGATION_SCOPES} key.
+ *
+ * <p class=”note”> Note: This is a protected intent that can only be sent by the system.</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED =
+ "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+
+ /**
+ * An {@code ArrayList<String>} corresponding to the delegation scopes given to an app in the
+ * {@link #ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED} broadcast.
+ */
+ public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
+
+ /**
* Flag used by {@link #addCrossProfileIntentFilter} to allow activities in
* the parent profile to access intents sent from the managed profile.
* That is, when an app in the managed profile calls
@@ -1194,6 +1256,53 @@ public class DevicePolicyManager {
public static final int PERMISSION_GRANT_STATE_DENIED = 2;
/**
+ * Delegation of certificate installation and management. This scope grants access to the
+ * {@link #getInstalledCaCerts}, {@link #hasCaCertInstalled}, {@link #installCaCert},
+ * {@link #uninstallCaCert}, {@link #uninstallAllUserCaCerts} and {@link #installKeyPair} APIs.
+ */
+ public static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+
+ /**
+ * Delegation of application restrictions management. This scope grants access to the
+ * {@link #setApplicationRestrictions} and {@link #getApplicationRestrictions} APIs.
+ */
+ public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
+
+ /**
+ * Delegation of application uninstall block. This scope grants access to the
+ * {@link #setUninstallBlocked} API.
+ */
+ public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+
+ /**
+ * Delegation of permission policy and permission grant state. This scope grants access to the
+ * {@link #setPermissionPolicy}, {@link #getPermissionGrantState},
+ * and {@link #setPermissionGrantState} APIs.
+ */
+ public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
+
+ /**
+ * Delegation of package access state. This scope grants access to the
+ * {@link #isApplicationHidden}, {@link #setApplicationHidden}, {@link #isPackageSuspended}, and
+ * {@link #setPackagesSuspended} APIs.
+ */
+ public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+
+ /**
+ * Delegation for enabling system apps. This scope grants access to the {@link #enableSystemApp}
+ * API.
+ */
+ public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+
+ /**
+ * Delegation of management of uninstalled packages. This scope grants access to the
+ * {@code #setKeepUninstalledPackages} and {@code #getKeepUninstalledPackages} APIs.
+ * @hide
+ */
+ public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES =
+ "delegation-keep-uninstalled-packages";
+
+ /**
* No management for current user in-effect. This is the default.
* @hide
*/
@@ -3246,6 +3355,10 @@ public class DevicePolicyManager {
/**
* Installs the given certificate as a user CA.
*
+ * The caller must be a profile or device owner on that user, or a delegate package given the
+ * {@link #DELEGATION_CERT_INSTALL} scope via {@link #setDelegatedScopes}; otherwise a
+ * security exception will be thrown.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param certBuffer encoded form of the certificate to install.
@@ -3254,12 +3367,14 @@ public class DevicePolicyManager {
* interrupted, true otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
*/
public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
throwIfParentInstance("installCaCert");
if (mService != null) {
try {
- return mService.installCaCert(admin, certBuffer);
+ return mService.installCaCert(admin, mContext.getPackageName(), certBuffer);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3270,18 +3385,24 @@ public class DevicePolicyManager {
/**
* Uninstalls the given certificate from trusted user CAs, if present.
*
+ * The caller must be a profile or device owner on that user, or a delegate package given the
+ * {@link #DELEGATION_CERT_INSTALL} scope via {@link #setDelegatedScopes}; otherwise a
+ * security exception will be thrown.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param certBuffer encoded form of the certificate to remove.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
*/
public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
throwIfParentInstance("uninstallCaCert");
if (mService != null) {
try {
final String alias = getCaCertAlias(certBuffer);
- mService.uninstallCaCerts(admin, new String[] {alias});
+ mService.uninstallCaCerts(admin, mContext.getPackageName(), new String[] {alias});
} catch (CertificateException e) {
Log.w(TAG, "Unable to parse certificate", e);
} catch (RemoteException e) {
@@ -3306,7 +3427,7 @@ public class DevicePolicyManager {
throwIfParentInstance("getInstalledCaCerts");
if (mService != null) {
try {
- mService.enforceCanManageCaCerts(admin);
+ mService.enforceCanManageCaCerts(admin, mContext.getPackageName());
final TrustedCertificateStore certStore = new TrustedCertificateStore();
for (String alias : certStore.userAliases()) {
try {
@@ -3335,8 +3456,8 @@ public class DevicePolicyManager {
throwIfParentInstance("uninstallAllUserCaCerts");
if (mService != null) {
try {
- mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
- .toArray(new String[0]));
+ mService.uninstallCaCerts(admin, mContext.getPackageName(),
+ new TrustedCertificateStore().userAliases() .toArray(new String[0]));
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -3356,7 +3477,7 @@ public class DevicePolicyManager {
throwIfParentInstance("hasCaCertInstalled");
if (mService != null) {
try {
- mService.enforceCanManageCaCerts(admin);
+ mService.enforceCanManageCaCerts(admin, mContext.getPackageName());
return getCaCertAlias(certBuffer) != null;
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -3388,6 +3509,8 @@ public class DevicePolicyManager {
* @return {@code true} if the keys were installed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate cert, @NonNull String alias) {
@@ -3419,6 +3542,8 @@ public class DevicePolicyManager {
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
* @see android.security.KeyChain#getCertificateChain
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
@@ -3431,8 +3556,8 @@ public class DevicePolicyManager {
}
final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
.getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
- return mService.installKeyPair(admin, pkcs8Key, pemCert, pemChain, alias,
- requestAccess);
+ return mService.installKeyPair(admin, mContext.getPackageName(), pkcs8Key, pemCert,
+ pemChain, alias, requestAccess);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
@@ -3453,11 +3578,13 @@ public class DevicePolicyManager {
* @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
*/
public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
throwIfParentInstance("removeKeyPair");
try {
- return mService.removeKeyPair(admin, alias);
+ return mService.removeKeyPair(admin, mContext.getPackageName(), alias);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3493,7 +3620,11 @@ public class DevicePolicyManager {
* @param installerPackage The package name of the certificate installer which will be given
* access. If {@code null} is given the current package will be cleared.
* @throws SecurityException if {@code admin} is not a device or a profile owner.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}. Use {@link #setDelegatedScopes}
+ * with the {@link #DELEGATION_CERT_INSTALL} scope instead.
*/
+ @Deprecated
public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String
installerPackage) throws SecurityException {
throwIfParentInstance("setCertInstallerPackage");
@@ -3507,14 +3638,19 @@ public class DevicePolicyManager {
}
/**
- * Called by a profile owner or device owner to retrieve the certificate installer for the user.
- * null if none is set.
+ * Called by a profile owner or device owner to retrieve the certificate installer for the user,
+ * or {@code null} if none is set. If there are multiple delegates this function will return one
+ * of them.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return The package name of the current delegated certificate installer, or {@code null} if
* none is set.
* @throws SecurityException if {@code admin} is not a device or a profile owner.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}. Use {@link #getDelegatePackages}
+ * with the {@link #DELEGATION_CERT_INSTALL} scope instead.
*/
+ @Deprecated
public @Nullable String getCertInstallerPackage(@NonNull ComponentName admin)
throws SecurityException {
throwIfParentInstance("getCertInstallerPackage");
@@ -3529,6 +3665,88 @@ public class DevicePolicyManager {
}
/**
+ * Called by a profile owner or device owner to grant access to privileged APIs to another app.
+ * Granted APIs are determined by {@code scopes}, which is a list of the {@code DELEGATION_*}
+ * constants.
+ * <p>
+ * A broadcast with the {@link #ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED} action will be
+ * sent to the {@code delegatePackage} with its new scopes in an {@code ArrayList<String>} extra
+ * under the {@link #EXTRA_DELEGATION_SCOPES} key. The broadcast is sent with the
+ * {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY} flag.
+ * <p>
+ * Delegated scopes are a per-user state. The delegated access is persistent until it is later
+ * cleared by calling this method with an empty {@code scopes} list or uninstalling the
+ * {@code delegatePackage}.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param delegatePackage The package name of the app which will be given access.
+ * @param scopes The groups of privileged APIs whose access should be granted to
+ * {@code delegatedPackage}.
+ * @throws SecurityException if {@code admin} is not a device or a profile owner.
+ */
+ public void setDelegatedScopes(@NonNull ComponentName admin, @NonNull String delegatePackage,
+ @NonNull List<String> scopes) {
+ throwIfParentInstance("setDelegatedScopes");
+ if (mService != null) {
+ try {
+ mService.setDelegatedScopes(admin, delegatePackage, scopes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Called by a profile owner or device owner to retrieve a list of the scopes given to a
+ * delegate package. Other apps can use this method to retrieve their own delegated scopes by
+ * passing {@code null} for {@code admin} and their own package name as
+ * {@code delegatedPackage}.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is {@code delegatedPackage}.
+ * @param delegatedPackage The package name of the app whose scopes should be retrieved.
+ * @return A list containing the scopes given to {@code delegatedPackage}.
+ * @throws SecurityException if {@code admin} is not a device or a profile owner.
+ */
+ @NonNull
+ public List<String> getDelegatedScopes(@Nullable ComponentName admin,
+ @NonNull String delegatedPackage) {
+ throwIfParentInstance("getDelegatedScopes");
+ if (mService != null) {
+ try {
+ return mService.getDelegatedScopes(admin, delegatedPackage);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called by a profile owner or device owner to retrieve a list of delegate packages that were
+ * granted a delegation scope.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param delegationScope The scope whose delegates should be retrieved.
+ * @return A list of package names of the current delegated packages for
+ {@code delegationScope}.
+ * @throws SecurityException if {@code admin} is not a device or a profile owner.
+ */
+ @Nullable
+ public List<String> getDelegatePackages(@NonNull ComponentName admin,
+ @NonNull String delegationScope) {
+ throwIfParentInstance("getDelegatePackages");
+ if (mService != null) {
+ try {
+ return mService.getDelegatePackages(admin, delegationScope);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Called by a device or profile owner to configure an always-on VPN connection through a
* specific application for the current user.
*
@@ -4433,7 +4651,9 @@ public class DevicePolicyManager {
}
/**
- * Called by device or profile owners to suspend packages for this user.
+ * Called by device or profile owners to suspend packages for this user. This function can be
+ * called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PACKAGE_ACCESS} scope via {@link #setDelegatedScopes}.
* <p>
* A suspended package will not be able to start activities. Its notifications will be hidden,
* it will not show up in recents, will not be able to show toasts or dialogs or ring the
@@ -4443,20 +4663,24 @@ public class DevicePolicyManager {
* package will no longer be suspended. The admin can block this by using
* {@link #setUninstallBlocked}.
*
- * @param admin The name of the admin component to check.
+ * @param admin The name of the admin component to check, or {@code null} if the caller is a
+ * package access delegate.
* @param packageNames The package names to suspend or unsuspend.
* @param suspended If set to {@code true} than the packages will be suspended, if set to
* {@code false} the packages will be unsuspended.
* @return an array of package names for which the suspended status is not set as requested in
* this method.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public @NonNull String[] setPackagesSuspended(@NonNull ComponentName admin,
@NonNull String[] packageNames, boolean suspended) {
throwIfParentInstance("setPackagesSuspended");
if (mService != null) {
try {
- return mService.setPackagesSuspended(admin, packageNames, suspended);
+ return mService.setPackagesSuspended(admin, mContext.getPackageName(), packageNames,
+ suspended);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -4465,21 +4689,26 @@ public class DevicePolicyManager {
}
/**
- * Called by device or profile owners to determine if a package is suspended.
+ * Determine if a package is suspended. This function can be called by a device owner, profile
+ * owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to retrieve the suspended status of.
* @return {@code true} if the package is suspended or {@code false} if the package is not
* suspended, could not be found or an error occurred.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @throws NameNotFoundException if the package could not be found.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
throws NameNotFoundException {
throwIfParentInstance("isPackageSuspended");
if (mService != null) {
try {
- return mService.isPackageSuspended(admin, packageName);
+ return mService.isPackageSuspended(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IllegalArgumentException ex) {
@@ -4686,7 +4915,11 @@ public class DevicePolicyManager {
* APIs. If {@code null} is given the current package will be cleared.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @throws NameNotFoundException if {@code packageName} is not found
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}. Use {@link #setDelegatedScopes}
+ * with the {@link #DELEGATION_APP_RESTRICTIONS} scope instead.
*/
+ @Deprecated
public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin,
@Nullable String packageName) throws NameNotFoundException {
throwIfParentInstance("setApplicationRestrictionsManagingPackage");
@@ -4703,14 +4936,20 @@ public class DevicePolicyManager {
/**
* Called by a profile owner or device owner to retrieve the application restrictions managing
- * package for the current user, or {@code null} if none is set.
+ * package for the current user, or {@code null} if none is set. If there are multiple
+ * delegates this function will return one of them.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return The package name allowed to manage application restrictions on the current user, or
* {@code null} if none is set.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}. Use {@link #getDelegatePackages}
+ * with the {@link #DELEGATION_APP_RESTRICTIONS} scope instead.
*/
- public @Nullable String getApplicationRestrictionsManagingPackage(
+ @Deprecated
+ @Nullable
+ public String getApplicationRestrictionsManagingPackage(
@NonNull ComponentName admin) {
throwIfParentInstance("getApplicationRestrictionsManagingPackage");
if (mService != null) {
@@ -4730,12 +4969,17 @@ public class DevicePolicyManager {
*
* <p>This is done by comparing the calling Linux uid with the uid of the package specified by
* that method.
+ *
+ * @deprecated From {@link android.os.Build.VERSION_CODES#O}. Use {@link #getDelegatedScopes}
+ * instead.
*/
+ @Deprecated
public boolean isCallerApplicationRestrictionsManagingPackage() {
throwIfParentInstance("isCallerApplicationRestrictionsManagingPackage");
if (mService != null) {
try {
- return mService.isCallerApplicationRestrictionsManagingPackage();
+ return mService.isCallerApplicationRestrictionsManagingPackage(
+ mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4747,8 +4991,8 @@ public class DevicePolicyManager {
* Sets the application restrictions for a given target application running in the calling user.
* <p>
* The caller must be a profile or device owner on that user, or the package allowed to manage
- * application restrictions via {@link #setApplicationRestrictionsManagingPackage}; otherwise a
- * security exception will be thrown.
+ * application restrictions via {@link #setDelegatedScopes} with the
+ * {@link #DELEGATION_APP_RESTRICTIONS} scope; otherwise a security exception will be thrown.
* <p>
* The provided {@link Bundle} consists of key-value pairs, where the types of values may be:
* <ul>
@@ -4775,7 +5019,8 @@ public class DevicePolicyManager {
* @param settings A {@link Bundle} to be parsed by the receiving application, conveying a new
* set of active restrictions.
* @throws SecurityException if {@code admin} is not a device or profile owner.
- * @see #setApplicationRestrictionsManagingPackage
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_APP_RESTRICTIONS
* @see UserManager#KEY_RESTRICTIONS_PENDING
*/
@WorkerThread
@@ -4784,7 +5029,8 @@ public class DevicePolicyManager {
throwIfParentInstance("setApplicationRestrictions");
if (mService != null) {
try {
- mService.setApplicationRestrictions(admin, packageName, settings);
+ mService.setApplicationRestrictions(admin, mContext.getPackageName(), packageName,
+ settings);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5332,19 +5578,24 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to get the list of apps to keep around as APKs even if no user has
- * currently installed it.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * Get the list of apps to keep around as APKs even if no user has currently installed it. This
+ * function can be called by a device owner or by a delegate given the
+ * {@link #DELEGATION_KEEP_UNINSTALLED_PACKAGES} scope via {@link #setDelegatedScopes}.
+ * <p>
+ * Please note that packages returned in this method are not automatically pre-cached.
*
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a keep uninstalled packages delegate.
* @return List of package names to keep cached.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
* @hide
*/
- public @Nullable List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) {
+ public @Nullable List<String> getKeepUninstalledPackages(@Nullable ComponentName admin) {
throwIfParentInstance("getKeepUninstalledPackages");
if (mService != null) {
try {
- return mService.getKeepUninstalledPackages(admin);
+ return mService.getKeepUninstalledPackages(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5353,23 +5604,27 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to set a list of apps to keep around as APKs even if no user has
- * currently installed it.
+ * Set a list of apps to keep around as APKs even if no user has currently installed it. This
+ * function can be called by a device owner or by a delegate given the
+ * {@link #DELEGATION_KEEP_UNINSTALLED_PACKAGES} scope via {@link #setDelegatedScopes}.
*
* <p>Please note that setting this policy does not imply that specified apps will be
* automatically pre-cached.</p>
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a keep uninstalled packages delegate.
* @param packageNames List of package names to keep cached.
* @throws SecurityException if {@code admin} is not a device owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
* @hide
*/
- public void setKeepUninstalledPackages(@NonNull ComponentName admin,
+ public void setKeepUninstalledPackages(@Nullable ComponentName admin,
@NonNull List<String> packageNames) {
throwIfParentInstance("setKeepUninstalledPackages");
if (mService != null) {
try {
- mService.setKeepUninstalledPackages(admin, packageNames);
+ mService.setKeepUninstalledPackages(admin, mContext.getPackageName(), packageNames);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5523,8 +5778,8 @@ public class DevicePolicyManager {
* user.
* <p>
* The caller must be a profile or device owner on that user, or the package allowed to manage
- * application restrictions via {@link #setApplicationRestrictionsManagingPackage}; otherwise a
- * security exception will be thrown.
+ * application restrictions via {@link #setDelegatedScopes} with the
+ * {@link #DELEGATION_APP_RESTRICTIONS} scope; otherwise a security exception will be thrown.
*
* <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread
*
@@ -5535,7 +5790,8 @@ public class DevicePolicyManager {
* {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty
* {@link Bundle} if no restrictions have been set.
* @throws SecurityException if {@code admin} is not a device or profile owner.
- * @see #setApplicationRestrictionsManagingPackage
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_APP_RESTRICTIONS
*/
@WorkerThread
public @NonNull Bundle getApplicationRestrictions(
@@ -5543,7 +5799,8 @@ public class DevicePolicyManager {
throwIfParentInstance("getApplicationRestrictions");
if (mService != null) {
try {
- return mService.getApplicationRestrictions(admin, packageName);
+ return mService.getApplicationRestrictions(admin, mContext.getPackageName(),
+ packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5620,22 +5877,55 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to hide or unhide packages. When a package is hidden it is
- * unavailable for use, but the data and actual package file remain.
+ * Called by any app to display a support dialog when a feature was disabled by an admin.
+ * This returns an intent that can be used with {@link Context#startActivity(Intent)} to
+ * display the dialog. It will tell the user that the feature indicated by {@code restriction}
+ * was disabled by an admin, and include a link for more information. The default content of
+ * the dialog can be changed by the restricting admin via
+ * {@link #setShortSupportMessage(ComponentName, CharSequence)}. If the restriction is not
+ * set (i.e. the feature is available), then the return value will be {@code null}.
+ * @param restriction Indicates for which feature the dialog should be displayed. Can be a
+ * user restriction from {@link UserManager}, e.g.
+ * {@link UserManager#DISALLOW_ADJUST_VOLUME}, or one of the constants
+ * {@link #POLICY_DISABLE_CAMERA} or {@link #POLICY_DISABLE_SCREEN_CAPTURE}.
+ * @return Intent An intent to be used to start the dialog-activity if the restriction is
+ * set by an admin, or null if the restriction does not exist or no admin set it.
+ */
+ public Intent createAdminSupportIntent(@NonNull String restriction) {
+ throwIfParentInstance("createAdminSupportIntent");
+ if (mService != null) {
+ try {
+ return mService.createAdminSupportIntent(restriction);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and
+ * actual package file remain. This function can be called by a device owner, profile owner, or
+ * by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to hide or unhide.
* @param hidden {@code true} if the package should be hidden, {@code false} if it should be
* unhidden.
* @return boolean Whether the hidden setting of the package was successfully updated.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
boolean hidden) {
throwIfParentInstance("setApplicationHidden");
if (mService != null) {
try {
- return mService.setApplicationHidden(admin, packageName, hidden);
+ return mService.setApplicationHidden(admin, mContext.getPackageName(), packageName,
+ hidden);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5644,18 +5934,23 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to determine if a package is hidden.
+ * Determine if a package is hidden. This function can be called by a device owner, profile
+ * owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to retrieve the hidden status of.
* @return boolean {@code true} if the package is hidden, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
throwIfParentInstance("isApplicationHidden");
if (mService != null) {
try {
- return mService.isApplicationHidden(admin, packageName);
+ return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5664,18 +5959,22 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to re-enable a system app that was disabled by default
- * when the user was initialized.
+ * Re-enable a system app that was disabled by default when the user was initialized. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_ENABLE_SYSTEM_APP} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is an enable system app delegate.
* @param packageName The package to be re-enabled in the calling profile.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
- mService.enableSystemApp(admin, packageName);
+ mService.enableSystemApp(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5683,20 +5982,24 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to re-enable system apps by intent that were disabled by
- * default when the user was initialized.
+ * Re-enable system apps by intent that were disabled by default when the user was initialized.
+ * This function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_ENABLE_SYSTEM_APP} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is an enable system app delegate.
* @param intent An intent matching the app(s) to be installed. All apps that resolve for this
* intent will be re-enabled in the calling profile.
* @return int The number of activities that matched the intent and were installed.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
- return mService.enableSystemAppWithIntent(admin, intent);
+ return mService.enableSystemAppWithIntent(admin, mContext.getPackageName(), intent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5770,20 +6073,24 @@ public class DevicePolicyManager {
/**
* Sets which packages may enter lock task mode.
* <p>
- * Any packages that shares uid with an allowed package will also be allowed to activate lock
+ * Any packages that share uid with an allowed package will also be allowed to activate lock
* task. From {@link android.os.Build.VERSION_CODES#M} removing packages from the lock task
- * package list results in locked tasks belonging to those packages to be finished. This
- * function can only be called by the device owner.
+ * package list results in locked tasks belonging to those packages to be finished.
+ * <p>
+ * This function can only be called by the device owner or by a profile owner of a user/profile
+ * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any packages
+ * set via this method will be cleared if the user becomes unaffiliated.
*
* @param packages The list of packages allowed to enter lock task mode
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
+ * an affiliated user or profile.
* @see Activity#startLockTask()
* @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
* @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
* @see UserManager#DISALLOW_CREATE_WINDOWS
*/
- public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages)
+ public void setLockTaskPackages(@NonNull ComponentName admin, @NonNull String[] packages)
throws SecurityException {
throwIfParentInstance("setLockTaskPackages");
if (mService != null) {
@@ -5796,10 +6103,11 @@ public class DevicePolicyManager {
}
/**
- * This function returns the list of packages allowed to start the lock task mode.
+ * Returns the list of packages allowed to start the lock task mode.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @hide
+ * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
+ * an affiliated user or profile.
+ * @see #setLockTaskPackages
*/
public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) {
throwIfParentInstance("getLockTaskPackages");
@@ -5810,7 +6118,7 @@ public class DevicePolicyManager {
throw e.rethrowFromSystemServer();
}
}
- return null;
+ return new String[0];
}
/**
@@ -5974,19 +6282,25 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to change whether a user can uninstall a package.
+ * Change whether a user can uninstall a package. This function can be called by a device owner,
+ * profile owner, or by a delegate given the {@link #DELEGATION_BLOCK_UNINSTALL} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a block uninstall delegate.
* @param packageName package to change.
* @param uninstallBlocked true if the user shouldn't be able to uninstall the package.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_BLOCK_UNINSTALL
*/
- public void setUninstallBlocked(@NonNull ComponentName admin, String packageName,
+ public void setUninstallBlocked(@Nullable ComponentName admin, String packageName,
boolean uninstallBlocked) {
throwIfParentInstance("setUninstallBlocked");
if (mService != null) {
try {
- mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
+ mService.setUninstallBlocked(admin, mContext.getPackageName(), packageName,
+ uninstallBlocked);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -6272,12 +6586,14 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owners to set the default response for future runtime permission
- * requests by applications. The policy can allow for normal operation which prompts the user to
- * grant a permission, or can allow automatic granting or denying of runtime permission requests
- * by an application. This also applies to new permissions declared by app updates. When a
- * permission is denied or granted this way, the effect is equivalent to setting the permission
- * grant state via {@link #setPermissionGrantState}.
+ * Set the default response for future runtime permission requests by applications. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
+ * The policy can allow for normal operation which prompts the user to grant a permission, or
+ * can allow automatic granting or denying of runtime permission requests by an application.
+ * This also applies to new permissions declared by app updates. When a permission is denied or
+ * granted this way, the effect is equivalent to setting the permission * grant state via
+ * {@link #setPermissionGrantState}.
* <p/>
* As this policy only acts on runtime permission requests, it only applies to applications
* built with a {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
@@ -6287,11 +6603,13 @@ public class DevicePolicyManager {
* {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @see #setPermissionGrantState
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public void setPermissionPolicy(@NonNull ComponentName admin, int policy) {
throwIfParentInstance("setPermissionPolicy");
try {
- mService.setPermissionPolicy(admin, policy);
+ mService.setPermissionPolicy(admin, mContext.getPackageName(), policy);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -6300,6 +6618,7 @@ public class DevicePolicyManager {
/**
* Returns the current runtime permission policy set by the device or profile owner. The
* default is {@link #PERMISSION_POLICY_PROMPT}.
+ *
* @param admin Which profile or device owner this request is associated with.
* @return the current policy for future permission requests.
*/
@@ -6319,7 +6638,8 @@ public class DevicePolicyManager {
* cannot manage it through the UI, and {@link #PERMISSION_GRANT_STATE_GRANTED granted} in which
* the permission is granted and the user cannot manage it through the UI. This might affect all
* permissions in a group that the runtime permission belongs to. This method can only be called
- * by a profile or device owner.
+ * by a profile owner, device owner, or a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
* <p/>
* Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not revoke
* the permission. It retains the previous grant, if any.
@@ -6338,21 +6658,27 @@ public class DevicePolicyManager {
* @see #PERMISSION_GRANT_STATE_DENIED
* @see #PERMISSION_GRANT_STATE_DEFAULT
* @see #PERMISSION_GRANT_STATE_GRANTED
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName,
String permission, int grantState) {
throwIfParentInstance("setPermissionGrantState");
try {
- return mService.setPermissionGrantState(admin, packageName, permission, grantState);
+ return mService.setPermissionGrantState(admin, mContext.getPackageName(), packageName,
+ permission, grantState);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
- * Returns the current grant state of a runtime permission for a specific application.
+ * Returns the current grant state of a runtime permission for a specific application. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which profile or device owner this request is associated with.
+ * @param admin Which profile or device owner this request is associated with, or {@code null}
+ * if the caller is a permission grant delegate.
* @param packageName The application to check the grant state for.
* @param permission The permission to check for.
* @return the current grant state specified by device policy. If the profile or device owner
@@ -6367,12 +6693,15 @@ public class DevicePolicyManager {
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @see #setPermissionGrantState(ComponentName, String, String, int)
* @see PackageManager#checkPermission(String, String)
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
String permission) {
throwIfParentInstance("getPermissionGrantState");
try {
- return mService.getPermissionGrantState(admin, packageName, permission);
+ return mService.getPermissionGrantState(admin, mContext.getPackageName(), packageName,
+ permission);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -7289,8 +7618,8 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to bind to a service from a profile owner of a managed profile or
- * vice versa. See {@link #getBindDeviceAdminTargetUsers} for a definition of which
+ * Called by a device owner to bind to a service from a profile owner or vice versa.
+ * See {@link #getBindDeviceAdminTargetUsers} for a definition of which
* device/profile owners are allowed to bind to services of another profile/device owner.
* <p>
* The service must be unexported. Note that the {@link Context} used to obtain this
@@ -7336,14 +7665,10 @@ public class DevicePolicyManager {
* Returns the list of target users that the calling device or profile owner can use when
* calling {@link #bindDeviceAdminServiceAsUser}.
* <p>
- * A device owner can bind to a service from a profile owner of a managed profile and
- * vice versa, provided that:
+ * A device owner can bind to a service from a profile owner and vice versa, provided that:
* <ul>
* <li>Both belong to the same package name.
- * <li>The managed profile is a profile of the user where the device owner is set.
- * See {@link UserManager#getUserProfiles()}
- * <li>Both users are affiliated.
- * See {@link #setAffiliationIds}.
+ * <li>Both users are affiliated. See {@link #setAffiliationIds}.
* </ul>
*/
public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 80ef557de831..79fe10ec6158 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -150,20 +150,24 @@ interface IDevicePolicyManager {
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();
- String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
- boolean isPackageSuspended(in ComponentName admin, String packageName);
+ String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended);
+ boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName);
- boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
- void uninstallCaCerts(in ComponentName admin, in String[] aliases);
- void enforceCanManageCaCerts(in ComponentName admin);
+ boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer);
+ void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases);
+ void enforceCanManageCaCerts(in ComponentName admin, in String callerPackage);
boolean approveCaCert(in String alias, int userHandle, boolean approval);
boolean isCaCertApproved(in String alias, int userHandle);
- boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
- in byte[] certChainBuffer, String alias, boolean requestAccess);
- boolean removeKeyPair(in ComponentName who, String alias);
+ boolean installKeyPair(in ComponentName who, in String callerPackage, in byte[] privKeyBuffer,
+ in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess);
+ boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
+ void setDelegatedScopes(in ComponentName who, in String delegatePackage, in List<String> scopes);
+ List<String> getDelegatedScopes(in ComponentName who, String delegatePackage);
+ List<String> getDelegatePackages(in ComponentName who, String scope);
+
void setCertInstallerPackage(in ComponentName who, String installerPackage);
String getCertInstallerPackage(in ComponentName who);
@@ -173,11 +177,11 @@ interface IDevicePolicyManager {
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
- void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
- Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
+ void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings);
+ Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName);
boolean setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
String getApplicationRestrictionsManagingPackage(in ComponentName admin);
- boolean isCallerApplicationRestrictionsManagingPackage();
+ boolean isCallerApplicationRestrictionsManagingPackage(in String callerPackage);
void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
ComponentName getRestrictionsProvider(int userHandle);
@@ -197,15 +201,16 @@ interface IDevicePolicyManager {
List getPermittedInputMethodsForCurrentUser();
boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId);
- boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
- boolean isApplicationHidden(in ComponentName admin, in String packageName);
+ Intent createAdminSupportIntent(in String restriction);
+ boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden);
+ boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName);
UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
boolean switchUser(in ComponentName who, in UserHandle userHandle);
- void enableSystemApp(in ComponentName admin, in String packageName);
- int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+ void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
+ int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
String[] getAccountTypesWithManagementDisabled();
@@ -223,7 +228,7 @@ interface IDevicePolicyManager {
void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userId);
- void setUninstallBlocked(in ComponentName admin, in String packageName, boolean uninstallBlocked);
+ void setUninstallBlocked(in ComponentName admin, in String callerPackage, in String packageName, boolean uninstallBlocked);
boolean isUninstallBlocked(in ComponentName admin, in String packageName);
void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
@@ -267,15 +272,15 @@ interface IDevicePolicyManager {
void notifyPendingSystemUpdate(in SystemUpdateInfo info);
SystemUpdateInfo getPendingSystemUpdate(in ComponentName admin);
- void setPermissionPolicy(in ComponentName admin, int policy);
+ void setPermissionPolicy(in ComponentName admin, in String callerPackage, int policy);
int getPermissionPolicy(in ComponentName admin);
- boolean setPermissionGrantState(in ComponentName admin, String packageName,
+ boolean setPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName,
String permission, int grantState);
- int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
+ int getPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName, String permission);
boolean isProvisioningAllowed(String action, String packageName);
int checkProvisioningPreCondition(String action, String packageName);
- void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList);
- List<String> getKeepUninstalledPackages(in ComponentName admin);
+ void setKeepUninstalledPackages(in ComponentName admin, in String callerPackage, in List<String> packageList);
+ List<String> getKeepUninstalledPackages(in ComponentName admin, in String callerPackage);
boolean isManagedProfile(in ComponentName admin);
boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress(in ComponentName admin);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 2858991fbdf4..91b87d74694d 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -144,8 +144,7 @@ public class SecurityLog {
}
/**
- * Returns the payload contained in this log. Each call to this method will
- * retrieve the next payload item. If no more payload exists, it returns {@code null}.
+ * Returns the payload contained in this log entry or {@code null} if there is no payload.
*/
public Object getData() {
return mEvent.getData();
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index b94264e1ac5d..08aa5f2589bf 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -22,6 +22,7 @@ import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import android.view.autofill.AutoFillId;
import java.util.ArrayList;
@@ -53,6 +54,8 @@ public class AssistStructure implements Parcelable {
Rect mTmpRect = new Rect();
+ boolean mSanitizeOnWrite = false;
+
static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
static final String DESCRIPTOR = "android.app.AssistStructure";
@@ -113,8 +116,10 @@ public class AssistStructure implements Parcelable {
int mNumWrittenWindows;
int mNumWrittenViews;
final float[] mTmpMatrix = new float[9];
+ final boolean mSanitizeOnWrite;
ParcelTransferWriter(AssistStructure as, Parcel out) {
+ mSanitizeOnWrite = as.mSanitizeOnWrite;
mWriteStructure = as.waitForReady();
ComponentName.writeToParcel(as.mActivityComponent, out);
mNumWindows = as.mWindowNodes.size();
@@ -186,7 +191,7 @@ public class AssistStructure implements Parcelable {
+ ", views=" + mNumWrittenViews
+ ", level=" + (mCurViewStackPos+levelAdj));
out.writeInt(VALIDATE_VIEW_TOKEN);
- int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
+ int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
mNumWrittenViews++;
// If the child has children, push it on the stack to write them next.
if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
@@ -374,8 +379,8 @@ public class AssistStructure implements Parcelable {
}
}
- void writeToParcel(Parcel out, boolean simple) {
- TextUtils.writeToParcel(mText, out, 0);
+ void writeToParcel(Parcel out, boolean simple, boolean writeSensitive) {
+ TextUtils.writeToParcel(writeSensitive ? mText : "", out, 0);
out.writeFloat(mTextSize);
out.writeInt(mTextStyle);
out.writeInt(mTextColor);
@@ -402,7 +407,7 @@ public class AssistStructure implements Parcelable {
final int mDisplayId;
final ViewNode mRoot;
- WindowNode(AssistStructure assist, ViewRootImpl root, int flags) {
+ WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill) {
View view = root.getView();
Rect rect = new Rect();
view.getBoundsOnScreen(rect);
@@ -414,19 +419,14 @@ public class AssistStructure implements Parcelable {
mDisplayId = root.getDisplayId();
mRoot = new ViewNode();
- // Must explicitly call the proper method based on flags since we don't know which
- // method (if any) was overridden by the View subclass.
- boolean forAutoFill = (flags
- & (View.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
-
- ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
+ ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false, 0);
if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
// This is a secure window, so it doesn't want a screenshot, and that
// means we should also not copy out its view hierarchy.
if (forAutoFill) {
- view.onProvideAutoFillStructure(builder, flags);
+ // NOTE: flags are currently not supported, hence 0
+ view.onProvideAutoFillStructure(builder, 0);
} else {
view.onProvideStructure(builder);
}
@@ -434,7 +434,8 @@ public class AssistStructure implements Parcelable {
return;
}
if (forAutoFill) {
- view.dispatchProvideAutoFillStructure(builder, flags);
+ // NOTE: flags are currently not supported, hence 0
+ view.dispatchProvideAutoFillStructure(builder, 0);
} else {
view.dispatchProvideStructure(builder);
}
@@ -537,6 +538,8 @@ public class AssistStructure implements Parcelable {
// fields (viewId and childId) of the field.
AutoFillId mAutoFillId;
AutoFillType mAutoFillType;
+ AutoFillValue mAutoFillValue;
+ boolean mSanitized;
int mX;
int mY;
int mScrollX;
@@ -610,8 +613,10 @@ public class AssistStructure implements Parcelable {
}
}
if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+ mSanitized = in.readInt() == 1;
mAutoFillId = in.readParcelable(null);
mAutoFillType = in.readParcelable(null);
+ mAutoFillValue = in.readParcelable(null);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -663,7 +668,11 @@ public class AssistStructure implements Parcelable {
}
}
- int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
+ int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
+ float[] tmpMatrix) {
+ // Guard used to skip non-sanitized data when writing for auto-fill.
+ boolean writeSensitive = true;
+
int flags = mFlags & ~FLAGS_ALL_CONTROL;
if (mId != View.NO_ID) {
flags |= FLAGS_HAS_ID;
@@ -716,8 +725,12 @@ public class AssistStructure implements Parcelable {
}
}
if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+ writeSensitive = mSanitized || !sanitizeOnWrite;
+ out.writeInt(mSanitized ? 1 : 0);
out.writeParcelable(mAutoFillId, 0);
out.writeParcelable(mAutoFillType, 0);
+ final AutoFillValue sanitizedValue = writeSensitive ? mAutoFillValue : null;
+ out.writeParcelable(sanitizedValue, 0);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -746,7 +759,7 @@ public class AssistStructure implements Parcelable {
TextUtils.writeToParcel(mContentDescription, out, 0);
}
if ((flags&FLAGS_HAS_TEXT) != 0) {
- mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
+ mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
}
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
out.writeBundle(mExtras);
@@ -794,6 +807,7 @@ public class AssistStructure implements Parcelable {
* <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
* for assist.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public AutoFillId getAutoFillId() {
return mAutoFillId;
}
@@ -804,11 +818,47 @@ public class AssistStructure implements Parcelable {
* <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
* for assist.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public AutoFillType getAutoFillType() {
return mAutoFillType;
}
/**
+ * Gets the the value of this view.
+ *
+ * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+ * for assist.
+ */
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public AutoFillValue getAutoFillValue() {
+ return mAutoFillValue;
+ }
+
+ /** @hide */
+ public boolean isSanitized() {
+ return mSanitized;
+ }
+
+ /**
+ * Updates the {@link AutoFillValue} of this structure.
+ *
+ * <p>Should be used just before sending the structure to the
+ * {@link android.service.autofill.AutoFillService} for saving, since it will override the
+ * initial value.
+ *
+ * @hide
+ */
+ public void updateAutoFillValue(AutoFillValue value) {
+ mAutoFillValue = value;
+ // TODO(b/33197203, b/33802548): decide whether to set text as well (so it would work
+ // with "legacy" views) or just the auto-fill value
+ final CharSequence text = value.getTextValue();
+ if (text != null) {
+ mText.mText = text;
+ }
+ }
+
+ /**
* Returns the left edge of this view, in pixels, relative to the left edge of its parent.
*/
public int getLeft() {
@@ -1113,10 +1163,11 @@ public class AssistStructure implements Parcelable {
final ViewNode mNode;
final boolean mAsync;
- ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
+ ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async, int flags) {
mAssist = assist;
mNode = node;
mAsync = async;
+ mNode.mSanitized = (flags & AUTO_FILL_FLAG_SANITIZED) != 0;
}
@Override
@@ -1350,19 +1401,20 @@ public class AssistStructure implements Parcelable {
}
}
- private ViewStructure newChild(int index, boolean forAutoFill, int virtualId) {
+ private ViewStructure newChild(int index, boolean forAutoFill, int virtualId, int flags) {
ViewNode node = new ViewNode();
setAutoFillId(node, forAutoFill, virtualId);
mNode.mChildren[index] = node;
- return new ViewNodeBuilder(mAssist, node, false);
+ return new ViewNodeBuilder(mAssist, node, false, flags);
}
- private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId) {
+ private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId,
+ int flags) {
synchronized (mAssist) {
ViewNode node = new ViewNode();
setAutoFillId(node, forAutoFill, virtualId);
mNode.mChildren[index] = node;
- ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
+ ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true, flags);
mAssist.mPendingAsyncChildren.add(builder);
return builder;
}
@@ -1370,22 +1422,23 @@ public class AssistStructure implements Parcelable {
@Override
public ViewStructure newChild(int index) {
- return newChild(index, false, 0);
+ return newChild(index, false, 0, 0);
}
+ // TODO(b/33197203, b/33802548): add CTS/unit test
@Override
- public ViewStructure newChild(int index, int virtualId) {
- return newChild(index, true, virtualId);
+ public ViewStructure newChild(int index, int virtualId, int flags) {
+ return newChild(index, true, virtualId, flags);
}
@Override
public ViewStructure asyncNewChild(int index) {
- return asyncNewChild(index, false, 0);
+ return asyncNewChild(index, false, 0, 0);
}
@Override
- public ViewStructure asyncNewChild(int index, int virtualId) {
- return asyncNewChild(index, true, virtualId);
+ public ViewStructure asyncNewChild(int index, int virtualId, int flags) {
+ return asyncNewChild(index, true, virtualId, flags);
}
@Override
@@ -1422,17 +1475,29 @@ public class AssistStructure implements Parcelable {
mNode.mAutoFillType = type;
}
+ @Override
+ public void setAutoFillValue(AutoFillValue value) {
+ mNode.mAutoFillValue = value;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void setSanitized(boolean sanitized) {
+ mNode.mSanitized = sanitized;
+ }
}
/** @hide */
- public AssistStructure(Activity activity, int flags) {
+ public AssistStructure(Activity activity, boolean forAutoFill) {
mHaveData = true;
mActivityComponent = activity.getComponentName();
ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
activity.getActivityToken());
for (int i=0; i<views.size(); i++) {
ViewRootImpl root = views.get(i);
- mWindowNodes.add(new WindowNode(this, root, flags));
+ mWindowNodes.add(new WindowNode(this, root, forAutoFill));
}
}
@@ -1446,9 +1511,24 @@ public class AssistStructure implements Parcelable {
mReceiveChannel = in.readStrongBinder();
}
+ /**
+ * Helper method used to sanitize the structure before it's written to a parcel.
+ *
+ * <p>Used just on auto-fill.
+ * @hide
+ */
+ public void sanitizeForParceling(boolean sanitize) {
+ mSanitizeOnWrite = sanitize;
+ }
+
/** @hide */
public void dump() {
+ if (mActivityComponent == null) {
+ Log.i(TAG, "dump(): calling ensureData() first");
+ ensureData();
+ }
Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+ Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
final int N = getWindowNodeCount();
for (int i=0; i<N; i++) {
WindowNode node = getWindowNodeAt(i);
@@ -1515,6 +1595,16 @@ public class AssistStructure implements Parcelable {
if (node.isAssistBlocked()) {
Log.i(TAG, prefix + " BLOCKED");
}
+ AutoFillId autoFillId = node.getAutoFillId();
+ if (autoFillId == null) {
+ Log.i(TAG, prefix + " NO AUTO-FILL ID");
+ } else {
+ Log.i(TAG, prefix + "AutoFill info: id= " + autoFillId
+ + ", type=" + node.getAutoFillType()
+ + ", value=" + node.getAutoFillValue()
+ + ", sanitized=" + node.isSanitized());
+ }
+
final int NCHILDREN = node.getChildCount();
if (NCHILDREN > 0) {
Log.i(TAG, prefix + " Children:");
@@ -1589,10 +1679,12 @@ public class AssistStructure implements Parcelable {
}
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
if (mHaveData) {
// This object holds its data. We want to write a send channel that the
@@ -1609,10 +1701,12 @@ public class AssistStructure implements Parcelable {
public static final Parcelable.Creator<AssistStructure> CREATOR
= new Parcelable.Creator<AssistStructure>() {
+ @Override
public AssistStructure createFromParcel(Parcel in) {
return new AssistStructure(in);
}
+ @Override
public AssistStructure[] newArray(int size) {
return new AssistStructure[size];
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index bad632555c42..45d9fb718c97 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -493,7 +493,7 @@ public abstract class BackupAgent extends ContextWrapper {
* <p class="note">Attempting to back up files in directories that are ignored by
* the backup system will have no effect. For example, if the app calls this method
* with a file inside the {@link #getNoBackupFilesDir()} directory, it will be ignored.
- * See {@link #onFullBackup(FullBackupDataOutput) for details on what directories
+ * See {@link #onFullBackup(FullBackupDataOutput)} for details on what directories
* are excluded from backups.
*
* @param file The file to be backed up. The file must exist and be readable by
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 540683deeecb..f0abe33c4df3 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -17,6 +17,7 @@
package android.app.backup;
import android.annotation.SystemApi;
+import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
@@ -157,6 +158,25 @@ public class BackupManager {
@SystemApi
public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+
+ /**
+ * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)}
+ * if the requested transport is unavailable.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_TRANSPORT_UNAVAILABLE = -1;
+
+ /**
+ * This error code is passed to {@link SelectBackupTransportCallback#onFailure(int)} if the
+ * requested transport is not a valid BackupTransport.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_TRANSPORT_INVALID = -2;
+
private Context mContext;
private static IBackupManager sService;
@@ -390,17 +410,20 @@ public class BackupManager {
}
/**
- * Specify the current backup transport. Callers must hold the
- * android.permission.BACKUP permission to use this method.
+ * Specify the current backup transport.
+ *
+ * <p> Callers must hold the android.permission.BACKUP permission to use this method.
*
* @param transport The name of the transport to select. This should be one
- * of the names returned by {@link #listAllTransports()}.
+ * of the names returned by {@link #listAllTransports()}. This is the String returned by
+ * {@link BackupTransport#name()} for the particular transport.
* @return The name of the previously selected transport. If the given transport
* name is not one of the currently available transports, no change is made to
* the current transport setting and the method returns null.
*
* @hide
*/
+ @Deprecated
@SystemApi
public String selectBackupTransport(String transport) {
checkServiceBinder();
@@ -415,6 +438,34 @@ public class BackupManager {
}
/**
+ * Specify the current backup transport and get notified when the transport is ready to be used.
+ * This method is async because BackupManager might need to bind to the specified transport
+ * which is in a separate process.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @param transport ComponentName of the service hosting the transport. This is different from
+ * the transport's name that is returned by {@link BackupTransport#name()}.
+ * @param listener A listener object to get a callback on the transport being selected.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void selectBackupTransport(ComponentName transport,
+ SelectBackupTransportCallback listener) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ SelectTransportListenerWrapper wrapper = listener == null ?
+ null : new SelectTransportListenerWrapper(mContext, listener);
+ sService.selectBackupTransportAsync(transport, wrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "selectBackupTransportAsync() couldn't connect");
+ }
+ }
+ }
+
+ /**
* Schedule an immediate backup attempt for all pending key/value updates. This
* is primarily intended for transports to use when they detect a suitable
* opportunity for doing a backup pass. If there are no pending updates to
@@ -598,4 +649,35 @@ public class BackupManager {
mHandler.obtainMessage(MSG_FINISHED, status, 0));
}
}
+
+ private class SelectTransportListenerWrapper extends ISelectBackupTransportCallback.Stub {
+
+ private final Handler mHandler;
+ private final SelectBackupTransportCallback mListener;
+
+ SelectTransportListenerWrapper(Context context, SelectBackupTransportCallback listener) {
+ mHandler = new Handler(context.getMainLooper());
+ mListener = listener;
+ }
+
+ @Override
+ public void onSuccess(final String transportName) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onSuccess(transportName);
+ }
+ });
+ }
+
+ @Override
+ public void onFailure(final int reason) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onFailure(reason);
+ }
+ });
+ }
+ }
}
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index fe23c288c7ce..1657e2e98698 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -19,8 +19,10 @@ package android.app.backup;
import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.app.backup.ISelectBackupTransportCallback;
import android.os.ParcelFileDescriptor;
import android.content.Intent;
+import android.content.ComponentName;
/**
* Direct interface to the Backup Manager Service that applications invoke on. The only
@@ -217,6 +219,8 @@ interface IBackupManager {
*/
String[] listAllTransports();
+ ComponentName[] listAllTransportComponents();
+
/**
* Retrieve the list of whitelisted transport components. Callers do </i>not</i> need
* any special permission.
@@ -238,6 +242,21 @@ interface IBackupManager {
String selectBackupTransport(String transport);
/**
+ * Specify the current backup transport and get notified when the transport is ready to be used.
+ * This method is async because BackupManager might need to bind to the specified transport
+ * which is in a separate process.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @param transport ComponentName of the service hosting the transport. This is different from
+ * the transport's name that is returned by {@link BackupTransport#name()}.
+ * @param listener A listener object to get a callback on the transport being selected.
+ *
+ * @hide
+ */
+ void selectBackupTransportAsync(in ComponentName transport, ISelectBackupTransportCallback listener);
+
+ /**
* Get the configuration Intent, if any, from the given transport. Callers must
* hold the android.permission.BACKUP permission in order to use this method.
*
diff --git a/core/java/android/app/backup/ISelectBackupTransportCallback.aidl b/core/java/android/app/backup/ISelectBackupTransportCallback.aidl
new file mode 100644
index 000000000000..5de7c5e1ed6a
--- /dev/null
+++ b/core/java/android/app/backup/ISelectBackupTransportCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.backup;
+
+/**
+ * Callback class for receiving success or failure callbacks on selecting a backup transport. These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+oneway interface ISelectBackupTransportCallback {
+
+ /**
+ * Called when BackupManager has successfully bound to the requested transport.
+ *
+ * @param transportName Name of the selected transport. This is the String returned by
+ * {@link BackupTransport#name()}.
+ */
+ void onSuccess(String transportName);
+
+ /**
+ * Called when BackupManager fails to bind to the requested transport.
+ *
+ * @param reason Error code denoting reason for failure.
+ */
+ void onFailure(int reason);
+}
diff --git a/core/java/android/app/backup/SelectBackupTransportCallback.java b/core/java/android/app/backup/SelectBackupTransportCallback.java
new file mode 100644
index 000000000000..0c8a0dcb86ef
--- /dev/null
+++ b/core/java/android/app/backup/SelectBackupTransportCallback.java
@@ -0,0 +1,44 @@
+/*
+ * 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.app.backup;
+
+import android.annotation.SystemApi;
+
+/**
+ * Callback class for receiving success or failure callbacks on selecting a backup transport. These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class SelectBackupTransportCallback {
+
+ /**
+ * Called when BackupManager has successfully bound to the requested transport.
+ *
+ * @param transportName Name of the selected transport. This is the String returned by
+ * {@link BackupTransport#name()}.
+ */
+ public void onSuccess(String transportName){}
+
+ /**
+ * Called when BackupManager fails to bind to the requested transport.
+ *
+ * @param reason Error code denoting reason for failure.
+ */
+ public void onFailure(int reason){}
+}
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 695994b4eae3..9d30771aaeba 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -18,6 +18,7 @@ package android.app.usage;
import android.annotation.WorkerThread;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -99,6 +100,8 @@ public class StorageStatsManager {
* @param volumeUuid the UUID of the storage volume you're interested in, or
* {@code null} to specify the default internal storage.
* @param uid the UID you're interested in.
+ * @see ApplicationInfo#volumeUuid
+ * @see ApplicationInfo#uid
*/
@WorkerThread
public StorageStats queryStatsForUid(String volumeUuid, int uid) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 9980e9661dd3..077331e36f05 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -1072,6 +1072,18 @@ public class AppWidgetManager {
}
/**
+ * Return {@code TRUE} if the default launcher supports
+ * {@link #requestPinAppWidget(ComponentName, PendingIntent)}
+ */
+ public boolean isRequestPinAppWidgetSupported() {
+ try {
+ return mService.isRequestPinAppWidgetSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Request to pin an app widget on the current launcher. It's up to the launcher to accept this
* request (optionally showing a user confirmation). If the request is accepted, the caller will
* get a confirmation with extra {@link #EXTRA_APPWIDGET_ID}.
@@ -1095,6 +1107,7 @@ public class AppWidgetManager {
*
* @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
* @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
+ * @see #isRequestPinAppWidgetSupported()
*
* @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
* service or when the user is locked.
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 1ce80077a748..6e31d807a044 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -106,10 +106,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* Intent used to broadcast the change in the Audio Codec state of the
* A2DP Source profile.
*
- * <p>This intent will have 3 extras:
+ * <p>This intent will have 2 extras:
* <ul>
- * <li> {@link #EXTRA_CODEC_CONFIG} - The current codec configuration. </li>
- * <li> {@link #EXTRA_PREVIOUS_CODEC_CONFIG} - The previous codec configuration. </li>
+ * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
* <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
* connected, otherwise it is not included.</li>
* </ul>
@@ -565,24 +564,24 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
/**
- * Gets the current codec configuration.
+ * Gets the current codec status (configuration and capability).
*
- * @return the current codec configuration
+ * @return the current codec status
* @hide
*/
- public BluetoothCodecConfig getCodecConfig() {
- if (DBG) Log.d(TAG, "getCodecConfig");
+ public BluetoothCodecStatus getCodecStatus() {
+ if (DBG) Log.d(TAG, "getCodecStatus");
try {
mServiceLock.readLock().lock();
if (mService != null && isEnabled()) {
- return mService.getCodecConfig();
+ return mService.getCodecStatus();
}
if (mService == null) {
Log.w(TAG, "Proxy not attached to service");
}
return null;
} catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in getCodecConfig()", e);
+ Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
return null;
} finally {
mServiceLock.readLock().unlock();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 885b42f3b10c..453476772430 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1184,6 +1184,25 @@ public final class BluetoothAdapter {
}
/**
+ * Get the end time of the latest remote device discovery process.
+ * @return the latest time that the bluetooth adapter was/will be in discovery mode,
+ * in milliseconds since the epoch.
+ * This time can be in the future if {@link #startDiscovery()} has been called recently.
+ * @hide
+ */
+ public long getDiscoveryEndMillis() {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getDiscoveryEndMillis();
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return -1;
+ }
+
+ /**
* Start the remote device discovery process.
* <p>The discovery process usually involves an inquiry scan of about 12
* seconds, followed by a page scan of each new device to retrieve its
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 52cd2de4c2b6..176e48fb6e08 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -29,34 +29,19 @@ import java.util.Objects;
* {@hide}
*/
public final class BluetoothCodecConfig implements Parcelable {
-
- /**
- * Extra for the codec configuration intents of the individual profiles.
- *
- * This extra represents the current codec configuration of the A2DP
- * profile.
- */
- public static final String EXTRA_CODEC_CONFIG = "android.bluetooth.codec.extra.CODEC_CONFIG";
-
- /**
- * Extra for the codec configuration intents of the individual profiles.
- *
- * This extra represents the previous codec configuration of the A2DP
- * profile.
- */
- public static final String EXTRA_PREVIOUS_CODEC_CONFIG =
- "android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG";
-
// Add an entry for each source codec here.
// NOTE: The values should be same as those listed in the following file:
// hardware/libhardware/include/hardware/bt_av.h
public static final int SOURCE_CODEC_TYPE_SBC = 0;
- public static final int SOURCE_CODEC_TYPE_APTX = 1;
- public static final int SOURCE_CODEC_TYPE_APTX_HD = 2;
- public static final int SOURCE_CODEC_TYPE_LDAC = 3;
+ public static final int SOURCE_CODEC_TYPE_AAC = 1;
+ public static final int SOURCE_CODEC_TYPE_APTX = 2;
+ public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
+ public static final int SOURCE_CODEC_TYPE_LDAC = 4;
+ public static final int SOURCE_CODEC_TYPE_MAX = 5;
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+ public static final int CODEC_PRIORITY_DISABLED = -1;
public static final int CODEC_PRIORITY_DEFAULT = 0;
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
@@ -89,7 +74,7 @@ public final class BluetoothCodecConfig implements Parcelable {
public BluetoothCodecConfig(int codecType, int codecPriority,
int sampleRate, int bitsPerSample,
- int channelMode,long codecSpecific1,
+ int channelMode, long codecSpecific1,
long codecSpecific2, long codecSpecific3,
long codecSpecific4) {
mCodecType = codecType;
@@ -127,13 +112,93 @@ public final class BluetoothCodecConfig implements Parcelable {
mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
}
+ /**
+ * Checks whether the object contains valid codec configuration.
+ *
+ * @return true if the object contains valid codec configuration,
+ * otherwise false.
+ */
+ public boolean isValid() {
+ return (mSampleRate != SAMPLE_RATE_NONE) &&
+ (mBitsPerSample != BITS_PER_SAMPLE_NONE) &&
+ (mChannelMode != CHANNEL_MODE_NONE);
+ }
+
+ /**
+ * Adds capability string to an existing string.
+ *
+ * @param prevStr the previous string with the capabilities. Can be
+ * a null pointer.
+ * @param capStr the capability string to append to prevStr argument.
+ * @return the result string in the form "prevStr|capStr".
+ */
+ private static String appendCapabilityToString(String prevStr,
+ String capStr) {
+ if (prevStr == null) {
+ return capStr;
+ }
+ return prevStr + "|" + capStr;
+ }
+
@Override
public String toString() {
- return "{mCodecType:" + mCodecType +
+ String sampleRateStr = null;
+ if (mSampleRate == SAMPLE_RATE_NONE) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
+ }
+ if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
+ }
+ if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
+ }
+ if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
+ }
+ if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
+ }
+ if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
+ }
+ if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
+ }
+
+ String bitsPerSampleStr = null;
+ if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
+ }
+
+ String channelModeStr = null;
+ if (mChannelMode == CHANNEL_MODE_NONE) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
+ }
+ if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
+ }
+ if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
+ }
+
+ return "{codecName:" + getCodecName() +
+ ",mCodecType:" + mCodecType +
",mCodecPriority:" + mCodecPriority +
",mSampleRate:" + String.format("0x%x", mSampleRate) +
+ "(" + sampleRateStr + ")" +
",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) +
+ "(" + bitsPerSampleStr + ")" +
",mChannelMode:" + String.format("0x%x", mChannelMode) +
+ "(" + channelModeStr + ")" +
",mCodecSpecific1:" + mCodecSpecific1 +
",mCodecSpecific2:" + mCodecSpecific2 +
",mCodecSpecific3:" + mCodecSpecific3 +
@@ -180,7 +245,32 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec type.
+ * Gets the codec name.
+ *
+ * @return the codec name
+ */
+ public String getCodecName() {
+ switch (mCodecType) {
+ case SOURCE_CODEC_TYPE_SBC:
+ return "SBC";
+ case SOURCE_CODEC_TYPE_AAC:
+ return "AAC";
+ case SOURCE_CODEC_TYPE_APTX:
+ return "aptX";
+ case SOURCE_CODEC_TYPE_APTX_HD:
+ return "aptX HD";
+ case SOURCE_CODEC_TYPE_LDAC:
+ return "LDAC";
+ case SOURCE_CODEC_TYPE_INVALID:
+ return "INVALID CODEC";
+ default:
+ break;
+ }
+ return "UNKNOWN CODEC(" + mCodecType + ")";
+ }
+
+ /**
+ * Gets the codec type.
* See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
*
* @return the codec type
@@ -190,7 +280,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec selection priority.
+ * Gets the codec selection priority.
* The codec selection priority is relative to other codecs: larger value
* means higher priority. If 0, reset to default.
*
@@ -201,7 +291,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec sample rate. The value can be a bitmask with all
+ * Gets the codec sample rate. The value can be a bitmask with all
* supported sample rates:
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
@@ -218,7 +308,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec bits per sample. The value can be a bitmask with all
+ * Gets the codec bits per sample. The value can be a bitmask with all
* bits per sample supported:
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
@@ -232,7 +322,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec channel mode. The value can be a bitmask with all
+ * Gets the codec channel mode. The value can be a bitmask with all
* supported channel modes:
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
@@ -245,7 +335,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value1.
+ * Gets a codec specific value1.
*
* @return a codec specific value1.
*/
@@ -254,7 +344,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value2.
+ * Gets a codec specific value2.
*
* @return a codec specific value2
*/
@@ -263,7 +353,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value3.
+ * Gets a codec specific value3.
*
* @return a codec specific value3
*/
@@ -272,7 +362,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value4.
+ * Gets a codec specific value4.
*
* @return a codec specific value4
*/
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.aidl b/core/java/android/bluetooth/BluetoothCodecStatus.aidl
new file mode 100644
index 000000000000..f9c3a3de2f4c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothCodecStatus;
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
new file mode 100644
index 000000000000..c8cd8d17ce36
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -0,0 +1,134 @@
+/*
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Represents the codec status (configuration and capability) for a Bluetooth
+ * A2DP source device.
+ *
+ * {@see BluetoothA2dp}
+ *
+ * {@hide}
+ */
+public final class BluetoothCodecStatus implements Parcelable {
+ /**
+ * Extra for the codec configuration intents of the individual profiles.
+ *
+ * This extra represents the current codec status of the A2DP
+ * profile.
+ */
+ public static final String EXTRA_CODEC_STATUS =
+ "android.bluetooth.codec.extra.CODEC_STATUS";
+
+ private final BluetoothCodecConfig mCodecConfig;
+ private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
+ private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
+
+ public BluetoothCodecStatus(BluetoothCodecConfig codecConfig,
+ BluetoothCodecConfig[] codecsLocalCapabilities,
+ BluetoothCodecConfig[] codecsSelectableCapabilities) {
+ mCodecConfig = codecConfig;
+ mCodecsLocalCapabilities = codecsLocalCapabilities;
+ mCodecsSelectableCapabilities = codecsSelectableCapabilities;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothCodecStatus) {
+ BluetoothCodecStatus other = (BluetoothCodecStatus)o;
+ return (Objects.equals(other.mCodecConfig, mCodecConfig) &&
+ Objects.equals(other.mCodecsLocalCapabilities,
+ mCodecsLocalCapabilities) &&
+ Objects.equals(other.mCodecsSelectableCapabilities,
+ mCodecsSelectableCapabilities));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
+ mCodecsLocalCapabilities);
+ }
+
+ @Override
+ public String toString() {
+ return "{mCodecConfig:" + mCodecConfig +
+ ",mCodecsLocalCapabilities:" + Arrays.toString(mCodecsLocalCapabilities) +
+ ",mCodecsSelectableCapabilities:" + Arrays.toString(mCodecsSelectableCapabilities) +
+ "}";
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothCodecStatus> CREATOR =
+ new Parcelable.Creator<BluetoothCodecStatus>() {
+ public BluetoothCodecStatus createFromParcel(Parcel in) {
+ final BluetoothCodecConfig codecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR);
+ final BluetoothCodecConfig[] codecsLocalCapabilities = in.createTypedArray(BluetoothCodecConfig.CREATOR);
+ final BluetoothCodecConfig[] codecsSelectableCapabilities = in.createTypedArray(BluetoothCodecConfig.CREATOR);
+
+ return new BluetoothCodecStatus(codecConfig,
+ codecsLocalCapabilities,
+ codecsSelectableCapabilities);
+ }
+ public BluetoothCodecStatus[] newArray(int size) {
+ return new BluetoothCodecStatus[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeTypedObject(mCodecConfig, 0);
+ out.writeTypedArray(mCodecsLocalCapabilities, 0);
+ out.writeTypedArray(mCodecsSelectableCapabilities, 0);
+ }
+
+ /**
+ * Gets the current codec configuration.
+ *
+ * @return the current codec configuration
+ */
+ public BluetoothCodecConfig getCodecConfig() {
+ return mCodecConfig;
+ }
+
+ /**
+ * Gets the codecs local capabilities.
+ *
+ * @return an array with the codecs local capabilities
+ */
+ public BluetoothCodecConfig[] getCodecsLocalCapabilities() {
+ return mCodecsLocalCapabilities;
+ }
+
+ /**
+ * Gets the codecs selectable capabilities.
+ *
+ * @return an array with the codecs selectable capabilities
+ */
+ public BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
+ return mCodecsSelectableCapabilities;
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 7c5458b7704b..53fef2add344 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -52,6 +52,7 @@ interface IBluetooth
boolean startDiscovery();
boolean cancelDiscovery();
boolean isDiscovering();
+ long getDiscoveryEndMillis();
int getAdapterConnectionState();
int getProfileConnectionState(int profile);
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 5b524eb18a5e..dbb5b7d7944b 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
/**
@@ -37,6 +38,6 @@ interface IBluetoothA2dp {
oneway void adjustAvrcpAbsoluteVolume(int direction);
oneway void setAvrcpAbsoluteVolume(int volume);
boolean isA2dpPlaying(in BluetoothDevice device);
- BluetoothCodecConfig getCodecConfig();
+ BluetoothCodecStatus getCodecStatus();
oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 17a802d59f4f..b89c64a8cac6 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -67,7 +67,9 @@ public final class ScanFilter implements Parcelable {
private final byte[] mManufacturerData;
@Nullable
private final byte[] mManufacturerDataMask;
- private static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
+
+ /** @hide */
+ public static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
@@ -318,8 +320,12 @@ public final class ScanFilter implements Parcelable {
return true;
}
- // Check if the uuid pattern is contained in a list of parcel uuids.
- private boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
+ /**
+ * Check if the uuid pattern is contained in a list of parcel uuids.
+ *
+ * @hide
+ */
+ public static boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
List<ParcelUuid> uuids) {
if (uuid == null) {
return true;
@@ -338,7 +344,7 @@ public final class ScanFilter implements Parcelable {
}
// Check if the uuid pattern matches the particular service uuid.
- private boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
+ private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
if (mask == null) {
return uuid.equals(data);
}
diff --git a/core/java/android/companion/AssociationRequest.aidl b/core/java/android/companion/AssociationRequest.aidl
new file mode 100644
index 000000000000..6c9106209735
--- /dev/null
+++ b/core/java/android/companion/AssociationRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+parcelable AssociationRequest;
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
new file mode 100644
index 000000000000..d477f43ac8c2
--- /dev/null
+++ b/core/java/android/companion/AssociationRequest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.OneTimeUseBuilder;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A request for the user to select a companion device to associate with.
+ *
+ * You can optionally set a {@link Builder#setDeviceFilter filter} for which devices to show to the
+ * user to select from.
+ * The exact type and fields of the filter you can set depend on the
+ * medium type. See {@link Builder}'s static factory methods for specific protocols that are
+ * supported.
+ *
+ * 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
+ *
+ * @param <F> Device filter type
+ */
+public final class AssociationRequest<F extends DeviceFilter> implements Parcelable {
+
+ /** @hide */
+ public static final int MEDIUM_TYPE_BLUETOOTH = 0;
+ /** @hide */
+ public static final int MEDIUM_TYPE_BLUETOOTH_LE = 1;
+ /** @hide */
+ public static final int MEDIUM_TYPE_WIFI = 2;
+
+ /** @hide */
+ @IntDef({MEDIUM_TYPE_BLUETOOTH, MEDIUM_TYPE_BLUETOOTH_LE, MEDIUM_TYPE_WIFI})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MediumType {}
+
+ private final boolean mSingleDevice;
+ private final int mMediumType;
+ private final F mDeviceFilter;
+
+ private AssociationRequest(boolean singleDevice, int mMediumType, F deviceFilter) {
+ this.mSingleDevice = singleDevice;
+ this.mMediumType = mMediumType;
+ this.mDeviceFilter = deviceFilter;
+ }
+
+ private AssociationRequest(Parcel in) {
+ this(
+ in.readByte() != 0,
+ in.readInt(),
+ in.readParcelable(AssociationRequest.class.getClassLoader()));
+ }
+
+ /** @hide */
+ public boolean isSingleDevice() {
+ return mSingleDevice;
+ }
+
+ /** @hide */
+ @MediumType
+ public int getMediumType() {
+ return mMediumType;
+ }
+
+ /** @hide */
+ @Nullable
+ public F getDeviceFilter() {
+ return mDeviceFilter;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte((byte) (mSingleDevice ? 1 : 0));
+ dest.writeInt(mMediumType);
+ dest.writeParcelable(mDeviceFilter, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final 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}
+ *
+ * @param <F> the type of filter for the request.
+ */
+ public static final class Builder<F extends DeviceFilter>
+ extends OneTimeUseBuilder<AssociationRequest<F>> {
+ private boolean mSingleDevice = false;
+ @MediumType private int mMediumType;
+ @Nullable private F mDeviceFilter = null;
+
+ private Builder() {}
+
+ /**
+ * Create a new builder for an association request with a Bluetooth LE device
+ */
+ @NonNull
+ public static Builder<BluetoothLEDeviceFilter> createForBluetoothLEDevice() {
+ return new Builder<BluetoothLEDeviceFilter>()
+ .setMediumType(MEDIUM_TYPE_BLUETOOTH_LE);
+ }
+
+ /**
+ * Create a new builder for an association request with a Bluetooth(non-LE) device
+ */
+ @NonNull
+ public static Builder<BluetoothDeviceFilter> createForBluetoothDevice() {
+ return new Builder<BluetoothDeviceFilter>()
+ .setMediumType(MEDIUM_TYPE_BLUETOOTH);
+ }
+
+ //TODO implement, once specific filter classes are available
+// public static Builder<> createForWiFiDevice()
+// public static Builder<> createForNanDevice()
+
+ /**
+ * @param singleDevice if true, scanning for a device will stop as soon as at least one
+ * fitting device is found
+ */
+ @NonNull
+ public Builder<F> setSingleDevice(boolean singleDevice) {
+ checkNotUsed();
+ this.mSingleDevice = singleDevice;
+ return this;
+ }
+
+ /**
+ * @param deviceFilter if set, only devices matching the given filter will be shown to the
+ * user
+ */
+ @NonNull
+ public Builder<F> setDeviceFilter(@Nullable F deviceFilter) {
+ checkNotUsed();
+ this.mDeviceFilter = deviceFilter;
+ return this;
+ }
+
+ /**
+ * @param deviceType A type of medium over which to discover devices
+ *
+ * @see MediumType
+ */
+ @NonNull
+ private Builder<F> setMediumType(@MediumType int deviceType) {
+ mMediumType = deviceType;
+ return this;
+ }
+
+ /** @inheritDoc */
+ @NonNull
+ @Override
+ public AssociationRequest<F> build() {
+ markUsed();
+ return new AssociationRequest<>(mSingleDevice, mMediumType, mDeviceFilter);
+ }
+ }
+}
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
new file mode 100644
index 000000000000..5a69955429aa
--- /dev/null
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -0,0 +1,202 @@
+/*
+ * 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 static android.companion.BluetoothDeviceFilterUtils.matchesAddress;
+import static android.companion.BluetoothDeviceFilterUtils.matchesName;
+import static android.companion.BluetoothDeviceFilterUtils.matchesServiceUuids;
+import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
+import static android.companion.BluetoothDeviceFilterUtils.patternToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.provider.OneTimeUseBuilder;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A filter for Bluetooth(non-LE) devices
+ */
+public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice> {
+
+ private static BluetoothDeviceFilter NO_OP;
+
+ private final Pattern mNamePattern;
+ private final String mAddress;
+ private final List<ParcelUuid> mServiceUuids;
+ private final List<ParcelUuid> mServiceUuidMasks;
+
+ private BluetoothDeviceFilter(
+ Pattern namePattern,
+ String address,
+ List<ParcelUuid> serviceUuids,
+ List<ParcelUuid> serviceUuidMasks) {
+ mNamePattern = namePattern;
+ mAddress = address;
+ mServiceUuids = ArrayUtils.emptyIfNull(serviceUuids);
+ mServiceUuidMasks = ArrayUtils.emptyIfNull(serviceUuidMasks);
+ }
+
+ private BluetoothDeviceFilter(Parcel in) {
+ this(
+ patternFromString(in.readString()),
+ in.readString(),
+ readUuids(in),
+ readUuids(in));
+ }
+
+ private static List<ParcelUuid> readUuids(Parcel in) {
+ final ArrayList<ParcelUuid> list = new ArrayList<>();
+ in.readParcelableList(list, ParcelUuid.class.getClassLoader());
+ return list;
+ }
+
+ /** @hide */
+ @NonNull
+ public static BluetoothDeviceFilter nullsafe(@Nullable BluetoothDeviceFilter nullable) {
+ return nullable != null ? nullable : noOp();
+ }
+
+ /** @hide */
+ @NonNull
+ public static BluetoothDeviceFilter noOp() {
+ if (NO_OP == null) NO_OP = new Builder().build();
+ return NO_OP;
+ }
+
+ /** @hide */
+ @Override
+ public boolean matches(BluetoothDevice device) {
+ return matchesAddress(mAddress, device)
+ && matchesServiceUuids(mServiceUuids, mServiceUuidMasks, device)
+ && matchesName(getNamePattern(), device);
+ }
+
+ /** @hide */
+ @Nullable
+ public Pattern getNamePattern() {
+ return mNamePattern;
+ }
+
+ /** @hide */
+ @Nullable
+ public String getAddress() {
+ return mAddress;
+ }
+
+ /** @hide */
+ @NonNull
+ public List<ParcelUuid> getServiceUuids() {
+ return mServiceUuids;
+ }
+
+ /** @hide */
+ @NonNull
+ public List<ParcelUuid> getServiceUuidMasks() {
+ return mServiceUuidMasks;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(patternToString(getNamePattern()));
+ dest.writeString(mAddress);
+ dest.writeParcelableList(mServiceUuids, flags);
+ dest.writeParcelableList(mServiceUuidMasks, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<BluetoothDeviceFilter> CREATOR
+ = new Creator<BluetoothDeviceFilter>() {
+ @Override
+ public BluetoothDeviceFilter createFromParcel(Parcel in) {
+ return new BluetoothDeviceFilter(in);
+ }
+
+ @Override
+ public BluetoothDeviceFilter[] newArray(int size) {
+ return new BluetoothDeviceFilter[size];
+ }
+ };
+
+ /**
+ * A builder for {@link BluetoothDeviceFilter}
+ */
+ public static final class Builder extends OneTimeUseBuilder<BluetoothDeviceFilter> {
+ private Pattern mNamePattern;
+ private String mAddress;
+ private ArrayList<ParcelUuid> mServiceUuid;
+ private ArrayList<ParcelUuid> mServiceUuidMask;
+
+ /**
+ * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
+ * given regular expression will be shown
+ */
+ public Builder setNamePattern(@Nullable Pattern regex) {
+ checkNotUsed();
+ mNamePattern = regex;
+ return this;
+ }
+
+ /**
+ * @param address if set, only devices with MAC address exactly matching the given one will
+ * pass the filter
+ */
+ @NonNull
+ public Builder setAddress(@Nullable String address) {
+ checkNotUsed();
+ mAddress = address;
+ return this;
+ }
+
+ /**
+ * Add filtering by certain bits of {@link BluetoothDevice#getUuids()}
+ *
+ * A device with any uuid matching the given bits is considered passing
+ *
+ * @param serviceUuid the values for the bits to match
+ * @param serviceUuidMask if provided, only those bits would have to match.
+ */
+ @NonNull
+ public Builder addServiceUuid(
+ @Nullable ParcelUuid serviceUuid, @Nullable ParcelUuid serviceUuidMask) {
+ checkNotUsed();
+ mServiceUuid = ArrayUtils.add(mServiceUuid, serviceUuid);
+ mServiceUuidMask = ArrayUtils.add(mServiceUuidMask, serviceUuidMask);
+ return this;
+ }
+
+ /** @inheritDoc */
+ @Override
+ @NonNull
+ public BluetoothDeviceFilter build() {
+ markUsed();
+ return new BluetoothDeviceFilter(
+ mNamePattern, mAddress, mServiceUuid, mServiceUuidMask);
+ }
+ }
+}
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
new file mode 100644
index 000000000000..289f9953a068
--- /dev/null
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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 static android.text.TextUtils.firstNotEmpty;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.ScanFilter;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/** @hide */
+public class BluetoothDeviceFilterUtils {
+ private BluetoothDeviceFilterUtils() {}
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "BluetoothDeviceFilterUtil";
+
+ @Nullable
+ static String patternToString(@Nullable Pattern p) {
+ return p == null ? null : p.pattern();
+ }
+
+ @Nullable
+ static Pattern patternFromString(@Nullable String s) {
+ return s == null ? null : Pattern.compile(s);
+ }
+
+ static boolean matches(ScanFilter filter, BluetoothDevice device) {
+ return matchesAddress(filter.getDeviceAddress(), device)
+ && matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
+ }
+
+ static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
+ final boolean result = deviceAddress == null
+ || (device == null || !deviceAddress.equals(device.getAddress()));
+ if (DEBUG) debugLogMatchResult(result, device, deviceAddress);
+ return result;
+ }
+
+ static boolean matchesServiceUuids(List<ParcelUuid> serviceUuids,
+ List<ParcelUuid> serviceUuidMasks, BluetoothDevice device) {
+ for (int i = 0; i < serviceUuids.size(); i++) {
+ ParcelUuid uuid = serviceUuids.get(i);
+ ParcelUuid uuidMask = serviceUuidMasks.get(i);
+ if (!matchesServiceUuid(uuid, uuidMask, device)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static boolean matchesServiceUuid(ParcelUuid serviceUuid, ParcelUuid serviceUuidMask,
+ BluetoothDevice device) {
+ final boolean result = serviceUuid == null ||
+ ScanFilter.matchesServiceUuids(
+ serviceUuid,
+ serviceUuidMask,
+ Arrays.asList(device.getUuids()));
+ if (DEBUG) debugLogMatchResult(result, device, serviceUuid);
+ return result;
+ }
+
+ static boolean matchesName(@Nullable Pattern namePattern, BluetoothDevice device) {
+ boolean result;
+ if (namePattern == null) {
+ result = true;
+ } else if (device == null) {
+ result = false;
+ } else {
+ final String name = device.getName();
+ result = name != null && namePattern.matcher(name).find();
+ }
+ if (DEBUG) debugLogMatchResult(result, device, namePattern);
+ return result;
+ }
+
+ private static void debugLogMatchResult(
+ boolean result, BluetoothDevice device, Object criteria) {
+ Log.i(LOG_TAG, getDeviceDisplayName(device) + (result ? " ~ " : " !~ ") + criteria);
+ }
+
+ public static String getDeviceDisplayName(@NonNull BluetoothDevice device) {
+ return firstNotEmpty(device.getAliasName(), device.getAddress());
+ }
+}
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.aidl b/core/java/android/companion/BluetoothLEDeviceFilter.aidl
new file mode 100644
index 000000000000..628cf7b2bdfc
--- /dev/null
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+parcelable BluetoothLEDeviceFilter;
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
new file mode 100644
index 000000000000..4a481ca80045
--- /dev/null
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -0,0 +1,151 @@
+/*
+ * 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 static android.companion.BluetoothDeviceFilterUtils.patternFromString;
+import static android.companion.BluetoothDeviceFilterUtils.patternToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.ScanFilter;
+import android.os.Parcel;
+import android.provider.OneTimeUseBuilder;
+
+import com.android.internal.util.ObjectUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * A filter for Bluetooth LE devices
+ *
+ * @see ScanFilter
+ */
+public final class BluetoothLEDeviceFilter implements DeviceFilter<BluetoothDevice> {
+
+ private static BluetoothLEDeviceFilter NO_OP;
+
+ private final Pattern mNamePattern;
+ private final ScanFilter mScanFilter;
+
+ private BluetoothLEDeviceFilter(Pattern namePattern, ScanFilter scanFilter) {
+ mNamePattern = namePattern;
+ mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
+ }
+
+ @SuppressLint("ParcelClassLoader")
+ private BluetoothLEDeviceFilter(Parcel in) {
+ this(
+ patternFromString(in.readString()),
+ in.readParcelable(null));
+ }
+
+ /** @hide */
+ @NonNull
+ public static BluetoothLEDeviceFilter nullsafe(@Nullable BluetoothLEDeviceFilter nullable) {
+ return nullable != null ? nullable : noOp();
+ }
+
+ /** @hide */
+ @NonNull
+ public static BluetoothLEDeviceFilter noOp() {
+ if (NO_OP == null) NO_OP = new Builder().build();
+ return NO_OP;
+ }
+
+ /** @hide */
+ @Nullable
+ public Pattern getNamePattern() {
+ return mNamePattern;
+ }
+
+ /** @hide */
+ @NonNull
+ public ScanFilter getScanFilter() {
+ return mScanFilter;
+ }
+
+ /** @hide */
+ @Override
+ public boolean matches(BluetoothDevice device) {
+ return BluetoothDeviceFilterUtils.matches(getScanFilter(), device)
+ && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(patternToString(getNamePattern()));
+ dest.writeParcelable(mScanFilter, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<BluetoothLEDeviceFilter> CREATOR
+ = new Creator<BluetoothLEDeviceFilter>() {
+ @Override
+ public BluetoothLEDeviceFilter createFromParcel(Parcel in) {
+ return new BluetoothLEDeviceFilter(in);
+ }
+
+ @Override
+ public BluetoothLEDeviceFilter[] newArray(int size) {
+ return new BluetoothLEDeviceFilter[size];
+ }
+ };
+
+ /**
+ * Builder for {@link BluetoothLEDeviceFilter}
+ */
+ public static final class Builder extends OneTimeUseBuilder<BluetoothLEDeviceFilter> {
+ private ScanFilter mScanFilter;
+ private Pattern mNamePattern;
+
+ /**
+ * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
+ * given regular expression will be shown
+ */
+ public Builder setNamePattern(@Nullable Pattern regex) {
+ checkNotUsed();
+ mNamePattern = regex;
+ return this;
+ }
+
+ /**
+ * @param scanFilter a {@link ScanFilter} to filter devices by
+ *
+ * @see ScanFilter for specific details on its various fields
+ */
+ @NonNull
+ public Builder setScanFilter(@Nullable ScanFilter scanFilter) {
+ checkNotUsed();
+ mScanFilter = scanFilter;
+ return this;
+ }
+
+ /** @inheritDoc */
+ @Override
+ @NonNull
+ public BluetoothLEDeviceFilter build() {
+ markUsed();
+ return new BluetoothLEDeviceFilter(mNamePattern, mScanFilter);
+ }
+ }
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
new file mode 100644
index 000000000000..b379c7c57554
--- /dev/null
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -0,0 +1,141 @@
+/*
+ * 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.IntentSender;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+
+/**
+ * System level service for managing companion devices
+ *
+ * Usage:
+ * To obtain an instance call
+ * {@link Context#getSystemService}({@link Context#COMPANION_DEVICE_SERVICE})
+ *
+ * Then, call {@link #associate} to initiate the flow of associating current package
+ * with a device selected by user
+ *
+ * @see AssociationRequest
+ */
+public final class CompanionDeviceManager {
+
+ /**
+ * A device, returned in the activity result of the {@link IntentSender} received in
+ * {@link Callback#onDeviceFound}
+ */
+ public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+
+ /**
+ * A callback to receive once at least one suitable device is found, or the search failed
+ * (e.g. timed out)
+ */
+ public abstract static class Callback {
+
+ /**
+ * Called once at least one suitable device is found
+ *
+ * @param chooserLauncher a {@link IntentSender} to launch the UI for user to select a
+ * device
+ */
+ public abstract void onDeviceFound(IntentSender chooserLauncher);
+
+ /**
+ * Called if there was an error looking for device(s), e.g. timeout
+ *
+ * @param error the cause of the error
+ */
+ public abstract void onFailure(CharSequence error);
+ }
+
+ private final ICompanionDeviceManager mService;
+ private final Context mContext;
+
+ /** @hide */
+ public CompanionDeviceManager(
+ @NonNull ICompanionDeviceManager service, @NonNull Context context) {
+ mService = service;
+ mContext = context;
+ }
+
+ /**
+ * Associate this app with a companion device, selected by user
+ *
+ * Once at least one appropriate device is found, {@code callback} will be called with a
+ * {@link PendingIntent} that can be used to show the list of available devices for the user
+ * to select.
+ * It should be started for result (i.e. using
+ * {@link android.app.Activity#startIntentSenderForResult}), as the resulting
+ * {@link android.content.Intent} will contain extra {@link #EXTRA_DEVICE}, with the selected
+ * device. (e.g. {@link android.bluetooth.BluetoothDevice})
+ *
+ * @param request specific details about this request
+ * @param callback will be called once there's at least one device found for user to choose from
+ * @param handler A handler to control which thread the callback will be delivered on, or null,
+ * to deliver it on main thread
+ *
+ * @see AssociationRequest
+ */
+ public void associate(
+ @NonNull AssociationRequest<?> request,
+ @NonNull Callback callback,
+ @Nullable Handler handler) {
+ final Handler finalHandler = handler != null
+ ? handler
+ : new Handler(Looper.getMainLooper());
+ try {
+ mService.associate(
+ request,
+ new IOnAssociateCallback.Stub() {
+
+ @Override
+ public void onSuccess(PendingIntent launcher) throws RemoteException {
+ finalHandler.post(() -> {
+ callback.onDeviceFound(launcher.getIntentSender());
+ });
+ }
+
+ @Override
+ public void onFailure(CharSequence reason) throws RemoteException {
+ finalHandler.post(() -> callback.onFailure(reason));
+ }
+ },
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void requestNotificationAccess() {
+ //TODO implement
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ /** @hide */
+ public boolean haveNotificationAccess() {
+ //TODO implement
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
new file mode 100644
index 000000000000..8362b2dab8fd
--- /dev/null
+++ b/core/java/android/companion/DeviceFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.companion;
+
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+/**
+ * A filter for companion devices of type {@code D}
+ *
+ * @param <D> Type of devices, filtered by this filter,
+ * e.g. {@link android.bluetooth.BluetoothDevice}, {@link android.net.wifi.WifiInfo}
+ */
+public interface DeviceFilter<D extends Parcelable> extends Parcelable {
+
+ /**
+ * @return whether the given device matches this filter
+ *
+ * @hide
+ */
+ boolean matches(D device);
+
+ /**
+ * A nullsafe {@link #matches(Parcelable)}, returning true if the filter is null
+ *
+ * @hide
+ */
+ static <D extends Parcelable> boolean matches(@Nullable DeviceFilter<D> filter, D device) {
+ return filter == null || filter.matches(device);
+ }
+}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
new file mode 100644
index 000000000000..065e31be9adf
--- /dev/null
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.companion.IOnAssociateCallback;
+import android.companion.AssociationRequest;
+
+/**
+ * Interface for communication with the core companion device manager service.
+ *
+ * @hide
+ */
+interface ICompanionDeviceManager {
+ void associate(in AssociationRequest request,
+ in IOnAssociateCallback callback,
+ in String callingPackage); //TODO int userId?
+
+ //TODO add these
+// boolean haveNotificationAccess(String packageName);
+// oneway void requestNotificationAccess(String packageName);
+}
diff --git a/core/java/android/companion/ICompanionDeviceManagerService.aidl b/core/java/android/companion/ICompanionDeviceManagerService.aidl
new file mode 100644
index 000000000000..ff2a7eb957f0
--- /dev/null
+++ b/core/java/android/companion/ICompanionDeviceManagerService.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.companion.AssociationRequest;
+import android.companion.IOnAssociateCallback;
+
+
+/** @hide */
+interface ICompanionDeviceManagerService {
+ void startDiscovery(
+ in AssociationRequest request,
+ in IOnAssociateCallback callback,
+ in String callingPackage);
+}
diff --git a/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
new file mode 100644
index 000000000000..c9dd345341b2
--- /dev/null
+++ b/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing per missions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.bluetooth.BluetoothDevice;
+
+/** @hide */
+interface ICompanionDeviceManagerServiceCallback {
+ void onDeviceSelected(in BluetoothDevice device);
+}
diff --git a/core/java/android/companion/IOnAssociateCallback.aidl b/core/java/android/companion/IOnAssociateCallback.aidl
new file mode 100644
index 000000000000..4867eadd2577
--- /dev/null
+++ b/core/java/android/companion/IOnAssociateCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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 per missions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.app.PendingIntent;
+
+/** @hide */
+interface IOnAssociateCallback {
+ void onSuccess(in PendingIntent launcher);
+ void onFailure(in CharSequence reason);
+}
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index b33a915ad2a5..621136290fab 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -19,7 +19,9 @@ package android.content;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.SystemClock;
import android.text.TextUtils;
+import android.util.TimeUtils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -92,6 +94,7 @@ public class ClipDescription implements Parcelable {
final CharSequence mLabel;
private final ArrayList<String> mMimeTypes;
private PersistableBundle mExtras;
+ private long mTimeStamp;
/**
* Create a new clip.
@@ -113,6 +116,7 @@ public class ClipDescription implements Parcelable {
public ClipDescription(ClipDescription o) {
mLabel = o.mLabel;
mMimeTypes = new ArrayList<String>(o.mMimeTypes);
+ mTimeStamp = o.mTimeStamp;
}
/**
@@ -142,6 +146,29 @@ public class ClipDescription implements Parcelable {
}
/**
+ * Used for setting the timestamp at which the associated {@link ClipData} is copied to
+ * global clipboard.
+ *
+ * @param timeStamp at which the associated {@link ClipData} is copeid to clipboard in
+ * {@link SystemClock#elapsedRealtime()} time base.
+ * @hide
+ */
+ public void setTimestamp(long timeStamp) {
+ mTimeStamp = timeStamp;
+ }
+
+ /**
+ * Return the timestamp at which the associated {@link ClipData} is copied to global clipboard
+ * in the {@link SystemClock#elapsedRealtime()} time base.
+ *
+ * @return timestamp at which the associated {@link ClipData} is copied to global clipboard
+ * or {@code 0} if it is not copied to clipboard.
+ */
+ public long getTimestamp() {
+ return mTimeStamp;
+ }
+
+ /**
* Return the label for this clip.
*/
public CharSequence getLabel() {
@@ -285,6 +312,13 @@ public class ClipDescription implements Parcelable {
first = false;
b.append(mExtras.toString());
}
+ if (mTimeStamp > 0) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ TimeUtils.formatDuration(mTimeStamp, b);
+ }
return !first;
}
@@ -312,12 +346,14 @@ public class ClipDescription implements Parcelable {
TextUtils.writeToParcel(mLabel, dest, flags);
dest.writeStringList(mMimeTypes);
dest.writePersistableBundle(mExtras);
+ dest.writeLong(mTimeStamp);
}
ClipDescription(Parcel in) {
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mMimeTypes = in.createStringArrayList();
mExtras = in.readPersistableBundle();
+ mTimeStamp = in.readLong();
}
public static final Parcelable.Creator<ClipDescription> CREATOR =
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index 7ed827c00e65..3a87cb3e7a29 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -414,7 +414,11 @@ public final class ContentValues implements Parcelable {
return (Boolean) value;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
- return Boolean.valueOf(value.toString());
+ // Note that we also check against 1 here because SQLite's internal representation
+ // for booleans is an integer with a value of 0 or 1. Without this check, boolean
+ // values obtained via DatabaseUtils#cursorRowToContentValues will always return
+ // false.
+ return Boolean.valueOf(value.toString()) || "1".equals(value);
} else if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 38e6fbeb007f..06f73033acd5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -35,6 +35,7 @@ import android.annotation.UserIdInt;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.Notification;
+import android.app.VrManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -1672,7 +1673,7 @@ public abstract class Context {
*
* @param intents An array of Intents to be started.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws ActivityNotFoundException &nbsp;
@@ -1700,7 +1701,7 @@ public abstract class Context {
* @param intents An array of Intents to be started.
* @param options Additional options for how the Activity should be started.
* @param userHandle The user for whom to launch the activities
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
* @throws ActivityNotFoundException &nbsp;
@@ -1749,7 +1750,7 @@ public abstract class Context {
* <var>flagsMask</var>
* @param extraFlags Always set to 0.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details. If options
* have also been supplied by the IntentSender, options given here will
* override any that conflict with those given by the IntentSender.
@@ -3599,6 +3600,14 @@ public abstract class Context {
public static final String PRINT_SERVICE = "print";
/**
+ * {@link android.companion.CompanionDeviceManager} for managing companion devices
+ *
+ * @see #getSystemService
+ * @see android.companion.CompanionDeviceManager
+ */
+ public static final String COMPANION_DEVICE_SERVICE = "companion_device";
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* {@link android.hardware.ConsumerIrManager} for transmitting infrared
* signals from the device.
@@ -3754,6 +3763,26 @@ public abstract class Context {
public static final String INCIDENT_SERVICE = "incident";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.content.om.OverlayManager} for managing overlay packages.
+ *
+ * @see #getSystemService
+ * @see android.content.om.OverlayManager
+ * @hide
+ */
+ public static final String OVERLAY_SERVICE = "overlay";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link VrManager} for accessing the VR service.
+ *
+ * @see #getSystemService
+ * @hide
+ */
+ @SystemApi
+ public static final String VR_SERVICE = "vrmanager";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
@@ -4253,6 +4282,20 @@ public abstract class Context {
int flags) throws PackageManager.NameNotFoundException;
/**
+ * Return a new Context object for the given split name. The new Context has a ClassLoader and
+ * Resources object that can access the split's and all of its dependencies' code/resources.
+ * Each call to this method returns a new instance of a Context object;
+ * Context objects are not shared, however common state (ClassLoader, other Resources for
+ * the same split) may be so the Context itself can be fairly lightweight.
+ *
+ * @param splitName The name of the split to include, as declared in the split's
+ * <code>AndroidManifest.xml</code>.
+ * @return A {@link Context} with the given split's code and/or resources loaded.
+ */
+ public abstract Context createContextForSplit(String splitName)
+ throws PackageManager.NameNotFoundException;
+
+ /**
* Get the userId associated with this context
* @return user id
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b131eccbe48a..546bfc404d56 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,7 +16,6 @@
package android.content;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -826,6 +825,13 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
+ public Context createContextForSplit(String splitName)
+ throws PackageManager.NameNotFoundException {
+ return mBase.createContextForSplit(splitName);
+ }
+
+ /** @hide */
+ @Override
public int getUserId() {
return mBase.getUserId();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 90f08cd8bc81..6a8141f865d9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -569,6 +569,7 @@ import static android.content.ContentProvider.maybeAddUserId;
* <li> {@link #CATEGORY_HE_DESK_DOCK}
* <li> {@link #CATEGORY_CAR_MODE}
* <li> {@link #CATEGORY_APP_MARKET}
+ * <li> {@link #CATEGORY_VR_HOME}
* </ul>
*
* <h3>Standard Extra Data</h3>
@@ -668,7 +669,14 @@ public class Intent implements Parcelable, Cloneable {
* preview. {@link #getClipData} contains an optional list of content URIs
* if there is more than one item to preview. {@link #EXTRA_INDEX} is an
* optional index of the URI in the clip data to show first.
+ * If {@link #EXTRA_QUICK_VIEW_PLAIN} is true, then the quick viewer should show
+ * basic UI without any extra features other than quick viewing the passed items.
+ * Especially, the quick viewer should not let users open the passed files
+ * in other apps, which includes sharing, opening, editing, printing, etc in the
+ * plain mode.
* <p>Output: nothing.
+ * @see #EXTRA_QUICK_VIEW_HIDE_DEFAULT_ACTIONS
+ * @see #EXTRA_INDEX
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
@@ -1628,6 +1636,19 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
/**
+ * Activity Action: Launch application uninstaller.
+ * <p>
+ * Input: The data must be a package: URI whose scheme specific part is
+ * the package name of the current installed package to be uninstalled.
+ * You can optionally supply {@link #EXTRA_RETURN_RESULT}.
+ * <p>
+ * Output: Nothing.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
+
+ /**
* Specify whether the package should be uninstalled for all users.
* @hide because these should not be part of normal application flow.
*/
@@ -1785,6 +1806,41 @@ public class Intent implements Parcelable, Cloneable {
@SystemApi
public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
+ /**
+ * Intent extra: An id if an autofill item ({@link
+ * android.view.autofill.Dataset} or {@link android.view.autofill.FillResponse}).
+ * <p>
+ * Type: String
+ * </p>
+ */
+ public static final String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
+
+ /**
+ * Intent extra: The assist structure which captures the filled screen.
+ * <p>
+ * Type: {@link android.app.assist.AssistStructure}
+ * </p>
+ */
+ public static final String EXTRA_AUTO_FILL_ASSIST_STRUCTURE =
+ "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+
+ /**
+ * Intent extra: The metadata associated with the authenticated entity ({@link
+ * android.view.autofill.Dataset} or {@link android.view.autofill.FillResponse}).
+ * <p>
+ * Type: {@link android.os.Bundle}
+ * </p>
+ */
+ public static final String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+
+ /**
+ * Intent extra: A callback to report an authentication result.
+ * <p>
+ * Type: {@link android.view.autofill.FillResponse}
+ * </p>
+ */
+ public static final String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
@@ -3120,6 +3176,40 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.MEDIA_RESOURCE_GRANTED";
/**
+ * Broadcast Action: An overlay package has been installed. The data
+ * contains the name of the added overlay package.
+ * @hide
+ */
+ public static final String ACTION_OVERLAY_ADDED = "android.intent.action.OVERLAY_ADDED";
+
+ /**
+ * Broadcast Action: An overlay package has changed. The data contains the
+ * name of the overlay package which has changed. This is broadcast on all
+ * changes to the OverlayInfo returned by {@link
+ * android.content.om.IOverlayManager#getOverlayInfo(String, int)}. The
+ * most common change is a state change that will change whether the
+ * overlay is enabled or not.
+ * @hide
+ */
+ public static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
+
+ /**
+ * Broadcast Action: An overlay package has been removed. The data contains
+ * the name of the overlay package which has been removed.
+ * @hide
+ */
+ public static final String ACTION_OVERLAY_REMOVED = "android.intent.action.OVERLAY_REMOVED";
+
+ /**
+ * Broadcast Action: The order of a package's list of overlay packages has
+ * changed. The data contains the package name of the overlay package that
+ * had its position in the list adjusted.
+ * @hide
+ */
+ public static final String
+ ACTION_OVERLAY_PRIORITY_CHANGED = "android.intent.action.OVERLAY_PRIORITY_CHANGED";
+
+ /**
* Activity Action: Allow the user to select and return one or more existing
* documents. When invoked, the system will display the various
* {@link DocumentsProvider} instances installed on the device, letting the
@@ -3596,6 +3686,13 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
+ /**
+ * An activity to use for the launcher when the device is placed in a VR Headset viewer.
+ * Used with {@link #ACTION_MAIN} to launch an activity. For more
+ * information, see {@link android.app.UiModeManager}.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Application launch intent categories (see addCategory()).
@@ -4346,10 +4443,26 @@ public class Intent implements Parcelable, Cloneable {
* Optional index with semantics depending on the intent action.
*
* <p>The value must be an integer greater or equal to 0.
+ * @see ACTION_QUICK_VIEW
*/
public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
/**
+ * Shows a plain quick viewer UI which doesn't provide any extra features other than
+ * quick viewing the items.
+ *
+ * <p>Especially, the quick viewer should not let users open the quick viewed files
+ * in other apps, which includes sharing, opening, editing, printing, etc.
+ *
+ * <p>This feature is optional, and may not be handled by all quick viewers.
+ *
+ * <p>The value is boolean. By default false.
+ * @see ACTION_QUICK_VIEW
+ */
+ public static final String EXTRA_QUICK_VIEW_PLAIN =
+ "android.intent.extra.QUICK_VIEW_PLAIN";
+
+ /**
* Optional boolean extra indicating whether quiet mode has been switched on or off.
* When a profile goes into quiet mode, all apps in the profile are killed and the
* profile user is stopped. Widgets originating from the profile are masked, and app
@@ -8344,7 +8457,7 @@ public class Intent implements Parcelable, Cloneable {
* @return Returns a bit mask of {@link #FILL_IN_ACTION},
* {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
* {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS},
- * {@link #FILL_IN_SELECTOR} and {@link #FILL_IN_CLIP_DATA indicating which fields were
+ * {@link #FILL_IN_SELECTOR} and {@link #FILL_IN_CLIP_DATA} indicating which fields were
* changed.
*/
@FillInFlags
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 541ebbd32f11..74d2f114aae5 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -175,7 +175,7 @@ public class SyncRequest implements Parcelable {
}
/**
- * Builder class for a @link SyncRequest. As you build your SyncRequest this class will also
+ * Builder class for a {@link SyncRequest}. As you build your SyncRequest this class will also
* perform validation.
*/
public static class Builder {
@@ -351,7 +351,7 @@ public class SyncRequest implements Parcelable {
* @param requiresCharging true if sync requires the phone to be plugged in. Default false.
*/
public Builder setRequiresCharging(boolean requiresCharging) {
- mRequiresCharging = true;
+ mRequiresCharging = requiresCharging;
return this;
}
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
new file mode 100644
index 000000000000..4f5d96038d1e
--- /dev/null
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+import android.content.om.OverlayInfo;
+
+/**
+ * Api for getting information about overlay packages.
+ *
+ * {@hide}
+ */
+interface IOverlayManager {
+ /**
+ * Returns information about all installed overlay packages for the
+ * specified user. If there are no installed overlay packages for this user,
+ * an empty map is returned (i.e. null is never returned). The returned map is a
+ * mapping of target package names to lists of overlays. Each list for a
+ * given target package is sorted in priority order, with the overlay with
+ * the highest priority at the end of the list.
+ *
+ * @param userId The user to get the OverlayInfos for.
+ * @return A Map<String, List<OverlayInfo>> with target package names
+ * mapped to lists of overlays; if no overlays exist for the
+ * requested user, an empty map is returned.
+ */
+ Map getAllOverlays(in int userId);
+
+ /**
+ * Returns information about all overlays for the given target package for
+ * the specified user. The returned list is ordered according to the
+ * overlay priority with the highest priority at the end of the list.
+ *
+ * @param targetPackageName The name of the target package.
+ * @param userId The user to get the OverlayInfos for.
+ * @return A list of OverlayInfo objects; if no overlays exist for the
+ * requested package, an empty list is returned.
+ */
+ List getOverlayInfosForTarget(in String targetPackageName, in int userId);
+
+ /**
+ * Returns information about the overlay with the given package name for the
+ * specified user.
+ *
+ * @param packageName The name of the overlay package.
+ * @param userId The user to get the OverlayInfo for.
+ * @return The OverlayInfo for the overlay package; or null if no such
+ * overlay package exists.
+ */
+ OverlayInfo getOverlayInfo(in String packageName, in int userId);
+
+ /**
+ * Request that an overlay package be enabled or disabled when possible to
+ * do so.
+ *
+ * It is always possible to disable an overlay, but due to technical and
+ * security reasons it may not always be possible to enable an overlay. An
+ * example of the latter is when the related target package is not
+ * installed. If the technical obstacle is later overcome, the overlay is
+ * automatically enabled at that point in time.
+ *
+ * An enabled overlay is a part of target package's resources, i.e. it will
+ * be part of any lookups performed via {@link android.content.res.Resources}
+ * and {@link android.content.res.AssetManager}. A disabled overlay will no
+ * longer affect the resources of the target package. If the target is
+ * currently running, its outdated resources will be replaced by new ones.
+ * This happens the same way as when an application enters or exits split
+ * window mode.
+ *
+ * @param packageName The name of the overlay package.
+ * @param enable true to enable the overlay, false to disable it.
+ * @param userId The user for which to change the overlay.
+ * @return true if the system successfully registered the request, false
+ * otherwise.
+ */
+ boolean setEnabled(in String packageName, in boolean enable, in int userId);
+
+ /**
+ * Change the priority of the given overlay to be just higher than the
+ * overlay with package name newParentPackageName. Both overlay packages
+ * must have the same target and user.
+ *
+ * @see getOverlayInfosForTarget
+ *
+ * @param packageName The name of the overlay package whose priority should
+ * be adjusted.
+ * @param newParentPackageName The name of the overlay package the newly
+ * adjusted overlay package should just outrank.
+ * @param userId The user for which to change the overlay.
+ */
+ boolean setPriority(in String packageName, in String newParentPackageName, in int userId);
+
+ /**
+ * Change the priority of the given overlay to the highest priority relative to
+ * the other overlays with the same target and user.
+ *
+ * @see getOverlayInfosForTarget
+ *
+ * @param packageName The name of the overlay package whose priority should
+ * be adjusted.
+ * @param userId The user for which to change the overlay.
+ */
+ boolean setHighestPriority(in String packageName, in int userId);
+
+ /**
+ * Change the priority of the overlay to the lowest priority relative to
+ * the other overlays for the same target and user.
+ *
+ * @see getOverlayInfosForTarget
+ *
+ * @param packageName The name of the overlay package whose priority should
+ * be adjusted.
+ * @param userId The user for which to change the overlay.
+ */
+ boolean setLowestPriority(in String packageName, in int userId);
+}
diff --git a/core/java/android/content/om/OverlayInfo.aidl b/core/java/android/content/om/OverlayInfo.aidl
new file mode 100644
index 000000000000..e7d413d07756
--- /dev/null
+++ b/core/java/android/content/om/OverlayInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+parcelable OverlayInfo;
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
new file mode 100644
index 000000000000..1a207ba055fc
--- /dev/null
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Immutable overlay information about a package. All PackageInfos that
+ * represent an overlay package will have a corresponding OverlayInfo.
+ *
+ * @hide
+ */
+public final class OverlayInfo implements Parcelable {
+ /**
+ * An internal state used as the initial state of an overlay. OverlayInfo
+ * objects exposed outside the {@link
+ * com.android.server.om.OverlayManagerService} should never have this
+ * state.
+ */
+ public static final int STATE_UNKNOWN = -1;
+
+ /**
+ * The target package of the overlay is not installed. The overlay cannot be enabled.
+ */
+ public static final int STATE_MISSING_TARGET = 0;
+
+ /**
+ * Creation of idmap file failed (e.g. no matching resources). The overlay
+ * cannot be enabled.
+ */
+ public static final int STATE_NO_IDMAP = 1;
+
+ /**
+ * The overlay is currently disabled. It can be enabled.
+ *
+ * @see IOverlayManager.setEnabled
+ */
+ public static final int STATE_DISABLED = 2;
+
+ /**
+ * The overlay is currently enabled. It can be disabled.
+ *
+ * @see IOverlayManager.setEnabled
+ */
+ public static final int STATE_ENABLED = 3;
+
+ /**
+ * Package name of the overlay package
+ */
+ public final String packageName;
+
+ /**
+ * Package name of the target package
+ */
+ public final String targetPackageName;
+
+ /**
+ * Full path to the base APK for this overlay package
+ */
+ public final String baseCodePath;
+
+ /**
+ * The state of this OverlayInfo as defined by the STATE_* constants in this class.
+ *
+ * @see #STATE_MISSING_TARGET
+ * @see #STATE_NO_IDMAP
+ * @see #STATE_DISABLED
+ * @see #STATE_ENABLED
+ */
+ public final int state;
+
+ /**
+ * User handle for which this overlay applies
+ */
+ public final int userId;
+
+ /**
+ * Create a new OverlayInfo based on source with an updated state.
+ *
+ * @param source the source OverlayInfo to base the new instance on
+ * @param state the new state for the source OverlayInfo
+ */
+ public OverlayInfo(@NonNull OverlayInfo source, int state) {
+ this(source.packageName, source.targetPackageName, source.baseCodePath, state,
+ source.userId);
+ }
+
+ public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
+ @NonNull String baseCodePath, int state, int userId) {
+ this.packageName = packageName;
+ this.targetPackageName = targetPackageName;
+ this.baseCodePath = baseCodePath;
+ this.state = state;
+ this.userId = userId;
+ ensureValidState();
+ }
+
+ public OverlayInfo(Parcel source) {
+ packageName = source.readString();
+ targetPackageName = source.readString();
+ baseCodePath = source.readString();
+ state = source.readInt();
+ userId = source.readInt();
+ ensureValidState();
+ }
+
+ private void ensureValidState() {
+ if (packageName == null) {
+ throw new IllegalArgumentException("packageName must not be null");
+ }
+ if (targetPackageName == null) {
+ throw new IllegalArgumentException("targetPackageName must not be null");
+ }
+ if (baseCodePath == null) {
+ throw new IllegalArgumentException("baseCodePath must not be null");
+ }
+ switch (state) {
+ case STATE_UNKNOWN:
+ case STATE_MISSING_TARGET:
+ case STATE_NO_IDMAP:
+ case STATE_DISABLED:
+ case STATE_ENABLED:
+ break;
+ default:
+ throw new IllegalArgumentException("State " + state + " is not a valid state");
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(packageName);
+ dest.writeString(targetPackageName);
+ dest.writeString(baseCodePath);
+ dest.writeInt(state);
+ dest.writeInt(userId);
+ }
+
+ public static final Parcelable.Creator<OverlayInfo> CREATOR = new Parcelable.Creator<OverlayInfo>() {
+ @Override
+ public OverlayInfo createFromParcel(Parcel source) {
+ return new OverlayInfo(source);
+ }
+
+ @Override
+ public OverlayInfo[] newArray(int size) {
+ return new OverlayInfo[size];
+ }
+ };
+
+ /**
+ * Return true if this overlay is enabled, i.e. should be used to overlay
+ * the resources in the target package.
+ *
+ * Disabled overlay packages are installed but are currently not in use.
+ *
+ * @return true if the overlay is enabled, else false.
+ */
+ public boolean isEnabled() {
+ switch (state) {
+ case STATE_ENABLED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Translate a state to a human readable string. Only intended for
+ * debugging purposes.
+ *
+ * @see #STATE_MISSING_TARGET
+ * @see #STATE_NO_IDMAP
+ * @see #STATE_DISABLED
+ * @see #STATE_ENABLED
+ *
+ * @return a human readable String representing the state.
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_UNKNOWN:
+ return "STATE_UNKNOWN";
+ case STATE_MISSING_TARGET:
+ return "STATE_MISSING_TARGET";
+ case STATE_NO_IDMAP:
+ return "STATE_NO_IDMAP";
+ case STATE_DISABLED:
+ return "STATE_DISABLED";
+ case STATE_ENABLED:
+ return "STATE_ENABLED";
+ default:
+ return "<unknown state>";
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + userId;
+ result = prime * result + state;
+ result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
+ result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode());
+ result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ OverlayInfo other = (OverlayInfo) obj;
+ if (userId != other.userId) {
+ return false;
+ }
+ if (state != other.state) {
+ return false;
+ }
+ if (!packageName.equals(other.packageName)) {
+ return false;
+ }
+ if (!targetPackageName.equals(other.targetPackageName)) {
+ return false;
+ }
+ if (!baseCodePath.equals(other.baseCodePath)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "OverlayInfo { overlay=" + packageName + ", target=" + targetPackageName + ", state="
+ + state + " (" + stateToString(state) + "), userId=" + userId + " }";
+ }
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4bd091dae77e..9a8eff098c1e 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -177,10 +177,14 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int RESIZE_MODE_RESIZEABLE = 2;
/**
- * Activity is resizeable and supported picture-in-picture mode.
+ * Activity is resizeable and supported picture-in-picture mode. This flag is now deprecated
+ * since activities do not need to be resizeable to support picture-in-picture.
+ * See {@link #FLAG_SUPPORTS_PICTURE_IN_PICTURE}.
+ *
* @hide
+ * @deprecated
*/
- public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
+ public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED = 3;
/**
* Activity does not support resizing, but we are forcing it to be resizeable. Only affects
* certain pre-N apps where we force them to be resizeable.
@@ -220,6 +224,44 @@ public class ActivityInfo extends ComponentInfo
public String requestedVrComponent;
/**
+ * Value for {@link #colorMode} indicating that the activity should use the
+ * default color mode (sRGB, low dynamic range).
+ *
+ * @see android.R.attr#colorMode
+ */
+ public static final int COLOR_MODE_DEFAULT = 0;
+ /**
+ * Value of {@link #colorMode} indicating that the activity should use a
+ * wide color gamut if the presentation display supports it.
+ *
+ * @see android.R.attr#colorMode
+ */
+ public static final int COLOR_MODE_WIDE_COLOR_GAMUT = 1;
+ /**
+ * Value of {@link #colorMode} indicating that the activity should use a
+ * high dynamic range if the presentation display supports it.
+ *
+ * @see android.R.attr#colorMode
+ */
+ public static final int COLOR_MODE_HDR = 2;
+
+ /** @hide */
+ @IntDef({
+ COLOR_MODE_DEFAULT,
+ COLOR_MODE_WIDE_COLOR_GAMUT,
+ COLOR_MODE_HDR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ColorMode {}
+
+ /**
+ * The color mode requested by this activity. The target display may not be
+ * able to honor the request.
+ */
+ @ColorMode
+ public int colorMode = COLOR_MODE_DEFAULT;
+
+ /**
* Bit in {@link #flags} indicating whether this activity is able to
* run in multiple processes. If
* true, the system may instantiate it in the some process as the
@@ -355,18 +397,17 @@ public class ActivityInfo extends ComponentInfo
public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
/**
- * Bit in {@link #flags} indicating if the activity is a launcher activity which should always
- * show up on the top of others.
- * See android.R.attr#onTopLauncher.
+ * Bit in {@link #flags} indicating if the activity is visible to ephemeral applications.
* @hide
*/
- public static final int FLAG_ON_TOP_LAUNCHER = 0x80000;
+ public static final int FLAG_VISIBLE_TO_EPHEMERAL = 0x100000;
/**
- * Bit in {@link #flags} indicating if the activity is visible to ephemeral applications.
+ * Bit in {@link #flags} indicating if the activity supports picture-in-picture mode.
+ * See {@link android.R.attr#supportsPictureInPicture}.
* @hide
*/
- public static final int FLAG_VISIBLE_TO_EPHEMERAL = 0x100000;
+ public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x200000;
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
@@ -566,7 +607,7 @@ public class ActivityInfo extends ComponentInfo
CONFIG_SMALLEST_SCREEN_SIZE,
CONFIG_DENSITY,
CONFIG_LAYOUT_DIRECTION,
- CONFIG_COLORIMETRY,
+ CONFIG_COLOR_MODE,
CONFIG_FONT_SCALE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -675,7 +716,7 @@ public class ActivityInfo extends ComponentInfo
* can itself handle the change to the display color gamut or dynamic
* range. Set from the {@link android.R.attr#configChanges} attribute.
*/
- public static final int CONFIG_COLORIMETRY = 0x4000;
+ public static final int CONFIG_COLOR_MODE = 0x4000;
/**
* Bit in {@link #configChanges} that indicates that the activity
* can itself handle asset path changes. Set from the {@link android.R.attr#configChanges}
@@ -713,7 +754,7 @@ public class ActivityInfo extends ComponentInfo
Configuration.NATIVE_CONFIG_SMALLEST_SCREEN_SIZE, // SMALLEST SCREEN SIZE
Configuration.NATIVE_CONFIG_DENSITY, // DENSITY
Configuration.NATIVE_CONFIG_LAYOUTDIR, // LAYOUT DIRECTION
- Configuration.NATIVE_CONFIG_COLORIMETRY, // COLORIMETRY
+ Configuration.NATIVE_CONFIG_COLOR_MODE, // COLOR_MODE
};
/**
@@ -770,7 +811,7 @@ public class ActivityInfo extends ComponentInfo
* {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION},
* {@link #CONFIG_ORIENTATION}, {@link #CONFIG_SCREEN_LAYOUT},
* {@link #CONFIG_DENSITY}, {@link #CONFIG_LAYOUT_DIRECTION} and
- * {@link #CONFIG_COLORIMETRY}.
+ * {@link #CONFIG_COLOR_MODE}.
* Set from the {@link android.R.attr#configChanges} attribute.
*/
public int configChanges;
@@ -873,6 +914,7 @@ public class ActivityInfo extends ComponentInfo
resizeMode = orig.resizeMode;
requestedVrComponent = orig.requestedVrComponent;
rotationAnimation = orig.rotationAnimation;
+ colorMode = orig.colorMode;
}
/**
@@ -926,10 +968,17 @@ public class ActivityInfo extends ComponentInfo
|| screenOrientation == SCREEN_ORIENTATION_USER_PORTRAIT;
}
+ /**
+ * Returns true if the activity supports picture-in-picture.
+ * @hide
+ */
+ public boolean supportsPictureInPicture() {
+ return (flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+ }
+
/** @hide */
public static boolean isResizeableMode(int mode) {
return mode == RESIZE_MODE_RESIZEABLE
- || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
|| mode == RESIZE_MODE_FORCE_RESIZEABLE
|| mode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
|| mode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
@@ -953,8 +1002,6 @@ public class ActivityInfo extends ComponentInfo
return "RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION";
case RESIZE_MODE_RESIZEABLE:
return "RESIZE_MODE_RESIZEABLE";
- case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
- return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE";
case RESIZE_MODE_FORCE_RESIZEABLE:
return "RESIZE_MODE_FORCE_RESIZEABLE";
case RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY:
@@ -1055,6 +1102,7 @@ public class ActivityInfo extends ComponentInfo
dest.writeInt(resizeMode);
dest.writeString(requestedVrComponent);
dest.writeInt(rotationAnimation);
+ dest.writeInt(colorMode);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -1090,6 +1138,7 @@ public class ActivityInfo extends ComponentInfo
resizeMode = source.readInt();
requestedVrComponent = source.readString();
rotationAnimation = source.readInt();
+ colorMode = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 04ab2394b0d1..8465f0fd5571 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -31,6 +31,7 @@ import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Printer;
+import android.util.SparseIntArray;
import com.android.internal.util.ArrayUtils;
@@ -558,6 +559,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int PRIVATE_FLAG_STATIC_SHARED_LIBRARY = 1 << 13;
/**
+ * Value for {@linl #privateFlags}: When set, the application will only have its splits loaded
+ * if they are required to load a component. Splits can be loaded on demand using the
+ * {@link Context#createContextForSplit(String)} API.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ISOLATED_SPLIT_LOADING = 1 << 14;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -587,8 +596,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int largestWidthLimitDp = 0;
- /** {@hide} */
+ /**
+ * UUID of the storage volume on which this application is being hosted. For
+ * apps hosted on the default internal storage at
+ * {@link Environment#getDataDirectory()}, the UUID value is {@code null}.
+ */
public String volumeUuid;
+
/** {@hide} */
public String scanSourceDir;
/** {@hide} */
@@ -607,8 +621,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public String publicSourceDir;
/**
- * Full paths to zero or more split APKs that, when combined with the base
- * APK defined in {@link #sourceDir}, form a complete application.
+ * The names of all installed split APKs, ordered lexicographically.
+ */
+ public String[] splitNames;
+
+ /**
+ * Full paths to zero or more split APKs, indexed by the same order as {@link #splitNames}.
*/
public String[] splitSourceDirs;
@@ -616,14 +634,35 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* Full path to the publicly available parts of {@link #splitSourceDirs},
* including resources and manifest. This may be different from
* {@link #splitSourceDirs} if an application is forward locked.
+ *
+ * @see #splitSourceDirs
*/
public String[] splitPublicSourceDirs;
/**
- * Full paths to the locations of extra resource packages this application
- * uses. This field is only used if there are extra resource packages,
- * otherwise it is null.
- *
+ * Maps the dependencies between split APKs. All splits implicitly depend on the base APK.
+ *
+ * Available since platform version O.
+ *
+ * Only populated if the application opts in to isolated split loading via the
+ * {@link android.R.attr.isolatedSplits} attribute in the &lt;manifest&gt; tag of the app's
+ * AndroidManifest.xml.
+ *
+ * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs},
+ * and {@link #splitPublicSourceDirs} arrays.
+ * Each key represents a split and its value is its parent split.
+ * Cycles do not exist because they are illegal and screened for during installation.
+ *
+ * May be null if no splits are installed, or if no dependencies exist between them.
+ * @hide
+ */
+ public SparseIntArray splitDependencies;
+
+ /**
+ * Full paths to the locations of extra resource packages (runtime overlays)
+ * this application uses. This field is only used if there are extra resource
+ * packages, otherwise it is null.
+ *
* {@hide}
*/
public String[] resourceDirs;
@@ -793,6 +832,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int networkSecurityConfigRes;
/**
+ * Version of the sandbox the application wants to run in.
+ * @hide
+ */
+ public int targetSandboxVersion;
+
+ /**
* The category of this app. Categories are used to cluster multiple apps
* together into meaningful groups, such as when summarizing battery,
* network, or disk usage. Apps should only define this value when they fit
@@ -973,7 +1018,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
pw.println(prefix + "enabled=" + enabled
+ " minSdkVersion=" + minSdkVersion
+ " targetSdkVersion=" + targetSdkVersion
- + " versionCode=" + versionCode);
+ + " versionCode=" + versionCode
+ + " targetSandboxVersion=" + targetSandboxVersion);
if ((flags&DUMP_FLAG_DETAILS) != 0) {
if (manageSpaceActivityName != null) {
pw.println(prefix + "manageSpaceActivityName=" + manageSpaceActivityName);
@@ -1058,8 +1104,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
scanPublicSourceDir = orig.scanPublicSourceDir;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
+ splitNames = orig.splitNames;
splitSourceDirs = orig.splitSourceDirs;
splitPublicSourceDirs = orig.splitPublicSourceDirs;
+ splitDependencies = orig.splitDependencies;
nativeLibraryDir = orig.nativeLibraryDir;
secondaryNativeLibraryDir = orig.secondaryNativeLibraryDir;
nativeLibraryRootDir = orig.nativeLibraryRootDir;
@@ -1086,6 +1134,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
fullBackupContent = orig.fullBackupContent;
networkSecurityConfigRes = orig.networkSecurityConfigRes;
category = orig.category;
+ targetSandboxVersion = orig.targetSandboxVersion;
}
public String toString() {
@@ -1098,6 +1147,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return 0;
}
+ @SuppressWarnings("unchecked")
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeString(taskAffinity);
@@ -1115,8 +1165,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(scanPublicSourceDir);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
+ dest.writeStringArray(splitNames);
dest.writeStringArray(splitSourceDirs);
dest.writeStringArray(splitPublicSourceDirs);
+ dest.writeSparseIntArray(splitDependencies);
dest.writeString(nativeLibraryDir);
dest.writeString(secondaryNativeLibraryDir);
dest.writeString(nativeLibraryRootDir);
@@ -1143,6 +1195,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(fullBackupContent);
dest.writeInt(networkSecurityConfigRes);
dest.writeInt(category);
+ dest.writeInt(targetSandboxVersion);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1155,6 +1208,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
};
+ @SuppressWarnings("unchecked")
private ApplicationInfo(Parcel source) {
super(source);
taskAffinity = source.readString();
@@ -1172,8 +1226,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
scanPublicSourceDir = source.readString();
sourceDir = source.readString();
publicSourceDir = source.readString();
+ splitNames = source.readStringArray();
splitSourceDirs = source.readStringArray();
splitPublicSourceDirs = source.readStringArray();
+ splitDependencies = source.readSparseIntArray();
nativeLibraryDir = source.readString();
secondaryNativeLibraryDir = source.readString();
nativeLibraryRootDir = source.readString();
@@ -1200,6 +1256,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
fullBackupContent = source.readInt();
networkSecurityConfigRes = source.readInt();
category = source.readInt();
+ targetSandboxVersion = source.readInt();
}
/**
@@ -1268,6 +1325,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
} else {
dataDir = credentialProtectedDataDir;
}
+ // TODO: modify per-user ephemerality
}
/**
@@ -1351,7 +1409,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* @hide
*/
- public boolean isEphemeralApp() {
+ public boolean isInstantApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0;
}
@@ -1363,6 +1421,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/**
+ * Returns true if the app has declared in its manifest that it wants its split APKs to be
+ * loaded into isolated Contexts, with their own ClassLoaders and Resources objects.
+ * @hide
+ */
+ public boolean requestsIsolatedSplitLoading() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0;
+ }
+
+ /**
* @hide
*/
public boolean isStaticSharedLibrary() {
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index b091d7ed4168..53be9537d00d 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -45,6 +45,12 @@ public class ComponentInfo extends PackageItemInfo {
public String processName;
/**
+ * The name of the split in which this component is declared.
+ * Null if the component was declared in the base APK.
+ */
+ public String splitName;
+
+ /**
* A string resource identifier (in the package's resources) containing
* a user-readable description of the component. From the "description"
* attribute or, if not set, 0.
@@ -53,7 +59,7 @@ public class ComponentInfo extends PackageItemInfo {
/**
* Indicates whether or not this component may be instantiated. Note that this value can be
- * overriden by the one in its parent {@link ApplicationInfo}.
+ * overridden by the one in its parent {@link ApplicationInfo}.
*/
public boolean enabled = true;
@@ -72,11 +78,6 @@ public class ComponentInfo extends PackageItemInfo {
*/
public boolean directBootAware = false;
- /**
- * The name of the split that contains the code for this component.
- */
- public String splitName;
-
/** @removed */
@Deprecated
public boolean encryptionAware = false;
@@ -88,6 +89,7 @@ public class ComponentInfo extends PackageItemInfo {
super(orig);
applicationInfo = orig.applicationInfo;
processName = orig.processName;
+ splitName = orig.splitName;
descriptionRes = orig.descriptionRes;
enabled = orig.enabled;
exported = orig.exported;
@@ -168,6 +170,9 @@ public class ComponentInfo extends PackageItemInfo {
if (processName != null && !packageName.equals(processName)) {
pw.println(prefix + "processName=" + processName);
}
+ if (splitName != null) {
+ pw.println(prefix + "splitName=" + splitName);
+ }
pw.println(prefix + "enabled=" + enabled + " exported=" + exported
+ " directBootAware=" + directBootAware);
if (descriptionRes != 0) {
@@ -200,6 +205,7 @@ public class ComponentInfo extends PackageItemInfo {
applicationInfo.writeToParcel(dest, parcelableFlags);
}
dest.writeString(processName);
+ dest.writeString(splitName);
dest.writeInt(descriptionRes);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(exported ? 1 : 0);
@@ -213,6 +219,7 @@ public class ComponentInfo extends PackageItemInfo {
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
}
processName = source.readString();
+ splitName = source.readString();
descriptionRes = source.readInt();
enabled = (source.readInt() != 0);
exported = (source.readInt() != 0);
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 51524164538a..c08bd1db8302 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -38,15 +38,21 @@ import java.util.List;
interface ILauncherApps {
void addOnAppsChangedListener(String callingPackage, in IOnAppsChangedListener listener);
void removeOnAppsChangedListener(in IOnAppsChangedListener listener);
- ParceledListSlice getLauncherActivities(String packageName, in UserHandle user);
- ActivityInfo resolveActivity(in ComponentName component, in UserHandle user);
- void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
+ ParceledListSlice getLauncherActivities(
+ String callingPackage, String packageName, in UserHandle user);
+ ActivityInfo resolveActivity(
+ String callingPackage, in ComponentName component, in UserHandle user);
+ void startActivityAsUser(String callingPackage,
+ in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds,
+ void showAppDetailsAsUser(
+ String callingPackage, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- boolean isPackageEnabled(String packageName, in UserHandle user);
- boolean isActivityEnabled(in ComponentName component, in UserHandle user);
- ApplicationInfo getApplicationInfo(String packageName, int flags, in UserHandle user);
+ boolean isPackageEnabled(String callingPackage, String packageName, in UserHandle user);
+ boolean isActivityEnabled(
+ String callingPackage, in ComponentName component, in UserHandle user);
+ ApplicationInfo getApplicationInfo(
+ String callingPackage, String packageName, int flags, in UserHandle user);
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
@@ -62,7 +68,8 @@ interface ILauncherApps {
boolean hasShortcutHostPermission(String callingPackage);
- ParceledListSlice getShortcutConfigActivities(String packageName, in UserHandle user);
+ ParceledListSlice getShortcutConfigActivities(
+ String callingPackage, String packageName, in UserHandle user);
IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component,
in UserHandle user);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ab9af5abdb67..3fb46cfab791 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -23,7 +23,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ContainerEncryptionParams;
-import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstaller;
@@ -490,6 +490,7 @@ interface IPackageManager {
*/
boolean performDexOpt(String packageName, boolean checkProfiles,
int compileReason, boolean force);
+
/**
* Ask the package manager to perform a dex-opt with the given compiler filter.
*
@@ -500,6 +501,16 @@ interface IPackageManager {
String targetCompilerFilter, boolean force);
/**
+ * Ask the package manager to perform a dex-opt with the given compiler filter on the
+ * secondary dex files belonging to the given package.
+ *
+ * Note: exposed only for the shell command to allow moving packages explicitly to a
+ * definite state.
+ */
+ boolean performDexOptSecondary(String packageName,
+ String targetCompilerFilter, boolean force);
+
+ /**
* Ask the package manager to dump profiles associated with a package.
*/
void dumpProfiles(String packageName);
@@ -507,6 +518,18 @@ interface IPackageManager {
void forceDexOpt(String packageName);
/**
+ * Execute the background dexopt job immediately.
+ */
+ boolean runBackgroundDexoptJob();
+
+ /**
+ * Reconcile the information we have about the secondary dex files belonging to
+ * {@code packagName} and the actual dex files. For all dex files that were
+ * deleted, update the internal records and delete the generated oat files.
+ */
+ void reconcileSecondaryDexFiles(String packageName);
+
+ /**
* Update status of external media on the package manager to scan and
* install packages installed on the external media. Like say the
* StorageManagerService uses this to call into the package manager to update
@@ -571,16 +594,17 @@ interface IPackageManager {
void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
+ void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
String getPermissionControllerPackageName();
- ParceledListSlice getEphemeralApplications(int userId);
- byte[] getEphemeralApplicationCookie(String packageName, int userId);
- boolean setEphemeralApplicationCookie(String packageName, in byte[] cookie, int userId);
- Bitmap getEphemeralApplicationIcon(String packageName, int userId);
- boolean isEphemeralApplication(String packageName, int userId);
+ ParceledListSlice getInstantApps(int userId);
+ byte[] getInstantAppCookie(String packageName, int userId);
+ boolean setInstantAppCookie(String packageName, in byte[] cookie, int userId);
+ Bitmap getInstantAppIcon(String packageName, int userId);
+ boolean isInstantApp(String packageName, int userId);
boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
@@ -594,4 +618,6 @@ interface IPackageManager {
int getInstallReason(String packageName, int userId);
ParceledListSlice getSharedLibraries(int flags, int userId);
+
+ boolean canRequestPackageInstalls(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index c90134a04830..03124be7ab7d 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -71,5 +71,5 @@ interface IShortcutService {
void applyRestore(in byte[] payload, int user);
- boolean isRequestPinShortcutSupported(int user);
+ boolean isRequestPinItemSupported(int user, int requestType);
} \ No newline at end of file
diff --git a/core/java/android/content/pm/EphemeralApplicationInfo.aidl b/core/java/android/content/pm/InstantAppInfo.aidl
index 5aaae7847c7e..a35892f9e0b0 100644
--- a/core/java/android/content/pm/EphemeralApplicationInfo.aidl
+++ b/core/java/android/content/pm/InstantAppInfo.aidl
@@ -16,4 +16,4 @@
package android.content.pm;
-parcelable EphemeralApplicationInfo;
+parcelable InstantAppInfo; \ No newline at end of file
diff --git a/core/java/android/content/pm/EphemeralApplicationInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 87663f12e637..898ee1101c07 100644
--- a/core/java/android/content/pm/EphemeralApplicationInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -23,11 +23,15 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * This class represents the state of an ephemeral app.
+ * This class represents the state of an instant app. Instant apps can
+ * be installed or uninstalled. If the app is installed you can call
+ * {@link #getApplicationInfo()} to get the app info, otherwise this
+ * class provides APIs to get basic app info for showing it in the UI,
+ * such as permissions, label, package name.
*
* @hide
*/
-public final class EphemeralApplicationInfo implements Parcelable {
+public final class InstantAppInfo implements Parcelable {
private final ApplicationInfo mApplicationInfo;
private final String mPackageName;
@@ -36,7 +40,7 @@ public final class EphemeralApplicationInfo implements Parcelable {
private final String[] mRequestedPermissions;
private final String[] mGrantedPermissions;
- public EphemeralApplicationInfo(ApplicationInfo appInfo,
+ public InstantAppInfo(ApplicationInfo appInfo,
String[] requestedPermissions, String[] grantedPermissions) {
mApplicationInfo = appInfo;
mPackageName = null;
@@ -45,7 +49,7 @@ public final class EphemeralApplicationInfo implements Parcelable {
mGrantedPermissions = grantedPermissions;
}
- public EphemeralApplicationInfo(String packageName, CharSequence label,
+ public InstantAppInfo(String packageName, CharSequence label,
String[] requestedPermissions, String[] grantedPermissions) {
mApplicationInfo = null;
mPackageName = packageName;
@@ -54,7 +58,7 @@ public final class EphemeralApplicationInfo implements Parcelable {
mGrantedPermissions = grantedPermissions;
}
- private EphemeralApplicationInfo(Parcel parcel) {
+ private InstantAppInfo(Parcel parcel) {
mPackageName = parcel.readString();
mLabelText = parcel.readCharSequence();
mRequestedPermissions = parcel.readStringArray();
@@ -62,6 +66,17 @@ public final class EphemeralApplicationInfo implements Parcelable {
mApplicationInfo = parcel.readParcelable(null);
}
+ /**
+ * @return The application info if the app is installed,
+ * <code>null</code> otherwise,
+ */
+ public @Nullable ApplicationInfo getApplicationInfo() {
+ return mApplicationInfo;
+ }
+
+ /**
+ * @return The pakcage name.
+ */
public @NonNull String getPackageName() {
if (mApplicationInfo != null) {
return mApplicationInfo.packageName;
@@ -69,6 +84,10 @@ public final class EphemeralApplicationInfo implements Parcelable {
return mPackageName;
}
+ /**
+ * @param packageManager Package manager for loading resources.
+ * @return Loads the label if the app is installed or returns the cached one otherwise.
+ */
public @NonNull CharSequence loadLabel(@NonNull PackageManager packageManager) {
if (mApplicationInfo != null) {
return mApplicationInfo.loadLabel(packageManager);
@@ -76,17 +95,27 @@ public final class EphemeralApplicationInfo implements Parcelable {
return mLabelText;
}
+ /**
+ * @param packageManager Package manager for loading resources.
+ * @return Loads the icon if the app is installed or returns the cached one otherwise.
+ */
public @NonNull Drawable loadIcon(@NonNull PackageManager packageManager) {
if (mApplicationInfo != null) {
return mApplicationInfo.loadIcon(packageManager);
}
- return packageManager.getEphemeralApplicationIcon(mPackageName);
+ return packageManager.getInstantAppIcon(mPackageName);
}
+ /**
+ * @return The requested permissions.
+ */
public @Nullable String[] getRequestedPermissions() {
return mRequestedPermissions;
}
+ /**
+ * @return The granted permissions.
+ */
public @Nullable String[] getGrantedPermissions() {
return mGrantedPermissions;
}
@@ -105,16 +134,16 @@ public final class EphemeralApplicationInfo implements Parcelable {
parcel.writeParcelable(mApplicationInfo, flags);
}
- public static final Creator<EphemeralApplicationInfo> CREATOR =
- new Creator<EphemeralApplicationInfo>() {
+ public static final Creator<InstantAppInfo> CREATOR =
+ new Creator<InstantAppInfo>() {
@Override
- public EphemeralApplicationInfo createFromParcel(Parcel parcel) {
- return new EphemeralApplicationInfo(parcel);
+ public InstantAppInfo createFromParcel(Parcel parcel) {
+ return new InstantAppInfo(parcel);
}
@Override
- public EphemeralApplicationInfo[] newArray(int size) {
- return new EphemeralApplicationInfo[0];
+ public InstantAppInfo[] newArray(int size) {
+ return new InstantAppInfo[0];
}
};
}
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index 9d88cdd8d484..59c530730170 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -18,6 +18,8 @@ package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
/**
* Information you can retrieve about a particular piece of test
@@ -32,6 +34,13 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
public String targetPackage;
/**
+ * Names of the process(es) this instrumentation will run in. If not specified, only
+ * runs in the main process of the targetPackage. Can either be a comma-separated list
+ * of process names or '*' for any process that launches to run targetPackage code.
+ */
+ public String targetProcess;
+
+ /**
* Full path to the base APK for this application.
*/
public String sourceDir;
@@ -44,8 +53,12 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
public String publicSourceDir;
/**
- * Full paths to zero or more split APKs that, when combined with the base
- * APK defined in {@link #sourceDir}, form a complete application.
+ * The names of all installed split APKs, ordered lexicographically.
+ */
+ public String[] splitNames;
+
+ /**
+ * Full paths to zero or more split APKs, indexed by the same order as {@link #splitNames}.
*/
public String[] splitSourceDirs;
@@ -53,10 +66,31 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
* Full path to the publicly available parts of {@link #splitSourceDirs},
* including resources and manifest. This may be different from
* {@link #splitSourceDirs} if an application is forward locked.
+ *
+ * @see #splitSourceDirs
*/
public String[] splitPublicSourceDirs;
/**
+ * Maps the dependencies between split APKs. All splits implicitly depend on the base APK.
+ *
+ * Available since platform version O.
+ *
+ * Only populated if the application opts in to isolated split loading via the
+ * {@link android.R.attr.isolatedSplits} attribute in the &lt;manifest&gt; tag of the app's
+ * AndroidManifest.xml.
+ *
+ * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs},
+ * and {@link #splitPublicSourceDirs} arrays.
+ * Each key represents a split and its value is its parent split.
+ * Cycles do not exist because they are illegal and screened for during installation.
+ *
+ * May be null if no splits are installed, or if no dependencies exist between them.
+ * @hide
+ */
+ public SparseIntArray splitDependencies;
+
+ /**
* Full path to a directory assigned to the package for its persistent data.
*/
public String dataDir;
@@ -86,10 +120,13 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
public InstrumentationInfo(InstrumentationInfo orig) {
super(orig);
targetPackage = orig.targetPackage;
+ targetProcess = orig.targetProcess;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
+ splitNames = orig.splitNames;
splitSourceDirs = orig.splitSourceDirs;
splitPublicSourceDirs = orig.splitPublicSourceDirs;
+ splitDependencies = orig.splitDependencies;
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -112,10 +149,13 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeString(targetPackage);
+ dest.writeString(targetProcess);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
+ dest.writeStringArray(splitNames);
dest.writeStringArray(splitSourceDirs);
dest.writeStringArray(splitPublicSourceDirs);
+ dest.writeSparseIntArray(splitDependencies);
dest.writeString(dataDir);
dest.writeString(deviceProtectedDataDir);
dest.writeString(credentialProtectedDataDir);
@@ -135,13 +175,17 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
}
};
+ @SuppressWarnings("unchecked")
private InstrumentationInfo(Parcel source) {
super(source);
targetPackage = source.readString();
+ targetProcess = source.readString();
sourceDir = source.readString();
publicSourceDir = source.readString();
+ splitNames = source.readStringArray();
splitSourceDirs = source.readStringArray();
splitPublicSourceDirs = source.readStringArray();
+ splitDependencies = source.readSparseIntArray();
dataDir = source.readString();
deviceProtectedDataDir = source.readString();
credentialProtectedDataDir = source.readString();
@@ -156,8 +200,10 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
ai.packageName = packageName;
ai.sourceDir = sourceDir;
ai.publicSourceDir = publicSourceDir;
+ ai.splitNames = splitNames;
ai.splitSourceDirs = splitSourceDirs;
ai.splitPublicSourceDirs = splitPublicSourceDirs;
+ ai.splitDependencies = splitDependencies;
ai.dataDir = dataDir;
ai.deviceProtectedDataDir = deviceProtectedDataDir;
ai.credentialProtectedDataDir = credentialProtectedDataDir;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index c6a86748bfe8..999b34f8a930 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -93,22 +93,40 @@ public class LauncherApps {
* @see #EXTRA_PIN_ITEM_REQUEST
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CONFIRM_PIN_ITEM =
- "android.content.pm.action.CONFIRM_PIN_ITEM";
+ public static final String ACTION_CONFIRM_PIN_SHORTCUT =
+ "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
/**
- * An extra for {@link #ACTION_CONFIRM_PIN_ITEM} containing a
- * {@link ShortcutInfo} of the shortcut the publisher app asked to pin.
+ * Activity Action: For the default launcher to show the confirmation dialog to create
+ * a pinned app widget.
+ *
+ * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
+ * details.
+ *
+ * <p>
+ * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
+ * and call {@link PinItemRequest#accept(Bundle)}
+ * if the user accepts. If the user doesn't accept, no further action is required.
+ *
+ * @see #EXTRA_PIN_ITEM_REQUEST
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONFIRM_PIN_APPWIDGET =
+ "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
+
+ /**
+ * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
+ * containing a {@link PinItemRequest} of appropriate type asked to pin.
*
* <p>A helper function {@link #getPinItemRequest(Intent)} can be used
* instead of using this constant directly.
*
- * @see #ACTION_CONFIRM_PIN_ITEM
+ * @see #ACTION_CONFIRM_PIN_SHORTCUT
+ * @see #ACTION_CONFIRM_PIN_APPWIDGET
*/
public static final String EXTRA_PIN_ITEM_REQUEST =
"android.content.pm.extra.PIN_ITEM_REQUEST";
-
private Context mContext;
private ILauncherApps mService;
private PackageManager mPm;
@@ -407,7 +425,8 @@ public class LauncherApps {
*/
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
try {
- return convertToActivityList(mService.getLauncherActivities(packageName, user), user);
+ return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
+ packageName, user), user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -423,7 +442,8 @@ public class LauncherApps {
*/
public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
try {
- ActivityInfo ai = mService.resolveActivity(intent.getComponent(), user);
+ ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
+ intent.getComponent(), user);
if (ai != null) {
LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
return info;
@@ -448,7 +468,8 @@ public class LauncherApps {
Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
}
try {
- mService.startActivityAsUser(component, sourceBounds, opts, user);
+ mService.startActivityAsUser(mContext.getPackageName(),
+ component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -466,7 +487,8 @@ public class LauncherApps {
public void startAppDetailsActivity(ComponentName component, UserHandle user,
Rect sourceBounds, Bundle opts) {
try {
- mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
+ mService.showAppDetailsAsUser(mContext.getPackageName(),
+ component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -486,7 +508,8 @@ public class LauncherApps {
public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
@NonNull UserHandle user) {
try {
- return convertToActivityList(mService.getShortcutConfigActivities(packageName, user),
+ return convertToActivityList(mService.getShortcutConfigActivities(
+ mContext.getPackageName(), packageName, user),
user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -549,7 +572,7 @@ public class LauncherApps {
*/
public boolean isPackageEnabled(String packageName, UserHandle user) {
try {
- return mService.isPackageEnabled(packageName, user);
+ return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -569,7 +592,7 @@ public class LauncherApps {
public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
UserHandle user) {
try {
- return mService.getApplicationInfo(packageName, flags, user);
+ return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -585,7 +608,7 @@ public class LauncherApps {
*/
public boolean isActivityEnabled(ComponentName component, UserHandle user) {
try {
- return mService.isActivityEnabled(component, user);
+ return mService.isActivityEnabled(mContext.getPackageName(), component, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1203,8 +1226,9 @@ public class LauncherApps {
}
/**
- * Represents a "pin shortcut" request made by an app, which is sent with
- * an {@link #ACTION_CONFIRM_PIN_ITEM} intent to the default launcher app.
+ * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
+ * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
+ * respectively to the default launcher app.
*
* <p>Note the launcher may receive a request to pin a shortcut that is already pinned, because
* the user may actually want to have multiple icons of the same shortcut on the launcher.
@@ -1213,6 +1237,9 @@ public class LauncherApps {
* even if the launcher does not call it, the shortcut is already pinned. Also in this case,
* the {@code options} argument to {@link #accept(Bundle)} will be ignored.
*
+ * <p>For AppWidget pin requests launcher should send back the appwidget id as an extra for
+ * {@link #accept(Bundle)} as {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}.
+ *
* @see #EXTRA_PIN_ITEM_REQUEST
* @see #getPinItemRequest(Intent)
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 98edbf817519..b20b5e2e9d96 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -20,7 +20,6 @@ import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -1742,6 +1741,22 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan native API
+ * will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
+ * what level of optional compute features are supported beyond the Vulkan 1.0 requirements.
+ * <p>
+ * Compute level 0 indicates support for:
+ * <ul>
+ * <li>Ability to use pointers to buffer data from shaders</li>
+ * <li>Ability to load/store 16-bit values from buffers</li>
+ * <li>Ability to control shader floating point rounding mode</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature(String, int)}: The version of this feature indicates the highest
* {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices that support
* the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The feature version
@@ -2162,6 +2177,15 @@ public abstract class PackageManager {
public static final String FEATURE_WATCH = "android.hardware.type.watch";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: This is a device for IoT and may not have an UI. An embedded
+ * device is defined as a full stack Android device with or without a display and no
+ * user-installable apps.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/
@@ -2960,6 +2984,14 @@ public abstract class PackageManager {
@PermissionInfoFlags int flags) throws NameNotFoundException;
/**
+ * Returns true if Permission Review Mode is enabled, false otherwise.
+ *
+ * @hide
+ */
+ @TestApi
+ public abstract boolean isPermissionReviewModeEnabled();
+
+ /**
* Retrieve all of the information we know about a particular group of
* permissions.
*
@@ -3405,7 +3437,6 @@ public abstract class PackageManager {
*/
public abstract void removePermission(String name);
-
/**
* Permission flags set when granting or revoking a permission.
*
@@ -3681,89 +3712,86 @@ public abstract class PackageManager {
@ApplicationInfoFlags int flags, @UserIdInt int userId);
/**
- * Gets the ephemeral applications the user recently used. Requires
- * holding "android.permission.ACCESS_EPHEMERAL_APPS".
+ * Gets the instant applications the user recently used. Requires
+ * holding "android.permission.ACCESS_INSTANT_APPS".
*
- * @return The ephemeral app list.
+ * @return The instant app list.
*
* @hide
*/
- @RequiresPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS)
- public abstract List<EphemeralApplicationInfo> getEphemeralApplications();
+ @RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
+ public abstract @NonNull List<InstantAppInfo> getInstantApps();
/**
- * Gets the icon for an ephemeral application.
+ * Gets the icon for an instant application.
*
* @param packageName The app package name.
*
* @hide
*/
- public abstract Drawable getEphemeralApplicationIcon(String packageName);
+ @RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
+ public abstract @Nullable Drawable getInstantAppIcon(String packageName);
/**
- * Gets whether the caller is an ephemeral app.
- *
- * @return Whether caller is an ephemeral app.
+ * Gets whether the caller is an instant app.
*
- * @see #setEphemeralCookie(byte[])
- * @see #getEphemeralCookie()
- * @see #getEphemeralCookieMaxSizeBytes()
+ * @return Whether caller is an instant app.
*
- * @hide
+ * @see #setInstantAppCookie(byte[])
+ * @see #getInstantAppCookie()
+ * @see #getInstantAppCookieMaxSize()
*/
- public abstract boolean isEphemeralApplication();
+ public abstract boolean isInstantApp();
/**
- * Gets the maximum size in bytes of the cookie data an ephemeral app
+ * Gets the maximum size in bytes of the cookie data an instant app
* can store on the device.
*
* @return The max cookie size in bytes.
*
- * @see #isEphemeralApplication()
- * @see #setEphemeralCookie(byte[])
- * @see #getEphemeralCookie()
- *
- * @hide
+ * @see #isInstantApp()
+ * @see #setInstantAppCookie(byte[])
+ * @see #getInstantAppCookie()
*/
- public abstract int getEphemeralCookieMaxSizeBytes();
+ public abstract int getInstantAppCookieMaxSize();
/**
- * Gets the ephemeral application cookie for this app. Non
- * ephemeral apps and apps that were ephemeral but were upgraded
- * to non-ephemeral can still access this API. For ephemeral apps
+ * Gets the instant application cookie for this app. Non
+ * instant apps and apps that were instant but were upgraded
+ * to normal apps can still access this API. For instant apps
* this cooke is cached for some time after uninstall while for
* normal apps the cookie is deleted after the app is uninstalled.
* The cookie is always present while the app is installed.
*
* @return The cookie.
*
- * @see #isEphemeralApplication()
- * @see #setEphemeralCookie(byte[])
- * @see #getEphemeralCookieMaxSizeBytes()
- *
- * @hide
+ * @see #isInstantApp()
+ * @see #setInstantAppCookie(byte[])
+ * @see #getInstantAppCookieMaxSize()
*/
- public abstract @NonNull byte[] getEphemeralCookie();
+ public abstract @NonNull byte[] getInstantAppCookie();
/**
- * Sets the ephemeral application cookie for the calling app. Non
- * ephemeral apps and apps that were ephemeral but were upgraded
- * to non-ephemeral can still access this API. For ephemeral apps
+ * Sets the instant application cookie for the calling app. Non
+ * instant apps and apps that were instant but were upgraded
+ * to normal apps can still access this API. For instant apps
* this cooke is cached for some time after uninstall while for
* normal apps the cookie is deleted after the app is uninstalled.
* The cookie is always present while the app is installed. The
- * cookie size is limited by {@link #getEphemeralCookieMaxSizeBytes()}.
+ * cookie size is limited by {@link #getInstantAppCookieMaxSize()}.
+ * If the provided cookie size is over the limit this method
+ * returns <code>false</code>. Passing <code>null</code> or an empty
+ * array clears the cookie.
+ * </p>
*
* @param cookie The cookie data.
- * @return True if the cookie was set.
+ * @return Whether the cookie was set.
*
- * @see #isEphemeralApplication()
- * @see #getEphemeralCookieMaxSizeBytes()
- * @see #getEphemeralCookie()
- *
- * @hide
+ * @see #isInstantApp()
+ * @see #getInstantAppCookieMaxSize()
+ * @see #getInstantAppCookie()
*/
- public abstract boolean setEphemeralCookie(@NonNull byte[] cookie);
+ public abstract boolean setInstantAppCookie(@Nullable byte[] cookie);
/**
* Get a list of shared libraries that are available on the
@@ -6050,4 +6078,21 @@ public abstract class PackageManager {
@TestApi
public abstract @InstallReason int getInstallReason(String packageName,
@NonNull UserHandle user);
+
+ /**
+ * Checks whether the calling package is allowed to request package installs through package
+ * installer. Apps are encouraged to call this api before launching the package installer via
+ * intent {@link android.content.Intent#ACTION_INSTALL_PACKAGE}. Starting from Android O, the
+ * user can explicitly choose what external sources they trust to install apps on the device.
+ * If this api returns false, the install request will be blocked by the package installer and
+ * a dialog will be shown to the user with an option to launch settings to change their
+ * preference. An application must target Android O or higher and declare permission
+ * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES} in order to use this api.
+ *
+ * @return true if the calling package is trusted by the user to request install packages on
+ * the device, false otherwise.
+ * @see {@link android.content.Intent#ACTION_INSTALL_PACKAGE}
+ * @see {@link android.provider.Settings#ACTION_MANAGE_EXTERNAL_SOURCES}
+ */
+ public abstract boolean canRequestPackageInstalls();
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index a1747c7d22b9..e4e0a195cb8d 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -243,7 +243,63 @@ public abstract class PackageManagerInternal {
int targetAppId, int ephemeralAppId);
/**
+ * Prunes instant apps and state associated with uninstalled
+ * instant apps according to the current platform policy.
+ */
+ public abstract void pruneInstantApps();
+
+ /**
* @return The SetupWizard package name.
*/
public abstract String getSetupWizardPackageName();
+
+ public interface ExternalSourcesPolicy {
+
+ int USER_TRUSTED = 0; // User has trusted the package to install apps
+ int USER_BLOCKED = 1; // User has blocked the package to install apps
+ int USER_DEFAULT = 2; // Default code to use when user response is unavailable
+
+ /**
+ * Checks the user preference for whether a package is trusted to request installs through
+ * package installer
+ *
+ * @param packageName The package to check for
+ * @param uid the uid in which the package is running
+ * @return {@link USER_TRUSTED} if the user has trusted the package, {@link USER_BLOCKED}
+ * if user has blocked requests from the package, {@link USER_DEFAULT} if the user response
+ * is not yet available
+ */
+ int getPackageTrustedToInstallApps(String packageName, int uid);
+ }
+
+ public abstract void setExternalSourcesPolicy(ExternalSourcesPolicy policy);
+
+ /**
+ * Get all overlay packages for a user.
+ * @param userId The user for which to get the overlays.
+ * @return A list of overlay packages. An empty list is returned if the
+ * user has no installed overlay packages.
+ */
+ public abstract List<PackageInfo> getOverlayPackages(int userId);
+
+ /**
+ * Get the names of all target packages for a user.
+ * @param userId The user for which to get the package names.
+ * @return A list of target package names. This list includes the "android" package.
+ */
+ public abstract List<String> getTargetPackageNames(int userId);
+
+ /**
+ * Set which overlay to use for a package.
+ * @param userId The user for which to update the overlays.
+ * @param targetPackageName The package name of the package for which to update the overlays.
+ * @param overlayPackageNames The complete list of overlay packages that should be enabled for
+ * the target. Previously enabled overlays not specified in the list
+ * will be disabled. Pass in null or an empty list to disable
+ * all overlays. The order of the items is significant if several
+ * overlays modify the same resource.
+ * @return true if all packages names were known by the package manager, false otherwise
+ */
+ public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
+ List<String> overlayPackageNames);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ca3011e0c7fb..7cef781607af 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -17,13 +17,12 @@
package android.content.pm;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -49,6 +48,9 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.split.SplitAssetDependencyLoader;
+import android.content.pm.split.SplitAssetLoader;
+import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -74,6 +76,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.apk.ApkSignatureSchemeV2Verifier;
import android.util.jar.StrictJarFile;
@@ -106,6 +109,7 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
@@ -155,6 +159,7 @@ public class PackageParser {
private static final String TAG_MANIFEST = "manifest";
private static final String TAG_APPLICATION = "application";
+ private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
private static final String TAG_OVERLAY = "overlay";
private static final String TAG_KEY_SETS = "key-sets";
private static final String TAG_PERMISSION_GROUP = "permission-group";
@@ -178,6 +183,7 @@ public class PackageParser {
private static final String TAG_EAT_COMMENT = "eat-comment";
private static final String TAG_PACKAGE = "package";
private static final String TAG_RESTRICT_UPDATE = "restrict-update";
+ private static final String TAG_USES_SPLIT = "uses-split";
/**
* Bit mask of all the valid bits that can be set in restartOnConfigChanges.
@@ -289,6 +295,7 @@ public class PackageParser {
private static boolean sCompatibilityModeEnabled = true;
private static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
static class ParsePackageItemArgs {
final Package owner;
@@ -352,6 +359,9 @@ public class PackageParser {
/** Names of any split APKs, ordered by parsed splitName */
public final String[] splitNames;
+ /** Dependencies of any split APKs, ordered by parsed splitName */
+ public final String[] usesSplitNames;
+
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
@@ -374,14 +384,17 @@ public class PackageParser {
public final boolean multiArch;
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
+ public final boolean isolatedSplits;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
- String[] splitCodePaths, int[] splitRevisionCodes) {
+ String[] usesSplitNames, String[] splitCodePaths,
+ int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode;
this.installLocation = baseApk.installLocation;
this.verifiers = baseApk.verifiers;
this.splitNames = splitNames;
+ this.usesSplitNames = usesSplitNames;
this.codePath = codePath;
this.baseCodePath = baseApk.codePath;
this.splitCodePaths = splitCodePaths;
@@ -392,6 +405,7 @@ public class PackageParser {
this.multiArch = baseApk.multiArch;
this.use32bitAbi = baseApk.use32bitAbi;
this.extractNativeLibs = baseApk.extractNativeLibs;
+ this.isolatedSplits = baseApk.isolatedSplits;
}
public List<String> getAllCodePaths() {
@@ -411,6 +425,7 @@ public class PackageParser {
public final String codePath;
public final String packageName;
public final String splitName;
+ public final String usesSplitName;
public final int versionCode;
public final int revisionCode;
public final int installLocation;
@@ -422,15 +437,17 @@ public class PackageParser {
public final boolean multiArch;
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
+ public final boolean isolatedSplits;
- public ApkLite(String codePath, String packageName, String splitName, int versionCode,
- int revisionCode, int installLocation, List<VerifierInfo> verifiers,
+ public ApkLite(String codePath, String packageName, String splitName, String usesSplitName,
+ int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers,
Signature[] signatures, Certificate[][] certificates, boolean coreApp,
boolean debuggable, boolean multiArch, boolean use32bitAbi,
- boolean extractNativeLibs) {
+ boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
+ this.usesSplitName = usesSplitName;
this.versionCode = versionCode;
this.revisionCode = revisionCode;
this.installLocation = installLocation;
@@ -442,6 +459,7 @@ public class PackageParser {
this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi;
this.extractNativeLibs = extractNativeLibs;
+ this.isolatedSplits = isolatedSplits;
}
}
@@ -492,7 +510,7 @@ public class PackageParser {
return isApkPath(file.getName());
}
- private static boolean isApkPath(String path) {
+ public static boolean isApkPath(String path) {
return path.endsWith(".apk");
}
@@ -738,23 +756,23 @@ public class PackageParser {
public static PackageLite parsePackageLite(File packageFile, int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
- return parseClusterPackageLite(packageFile, flags, null);
+ return parseClusterPackageLite(packageFile, flags);
} else {
- return parseMonolithicPackageLite(packageFile, flags, null);
+ return parseMonolithicPackageLite(packageFile, flags);
}
}
- private static PackageLite parseMonolithicPackageLite(File packageFile, int flags,
- AssetManager cachedAssetManager) throws PackageParserException {
+ private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
+ throws PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
- final ApkLite baseApk = parseApkLite(packageFile, flags, cachedAssetManager);
+ final ApkLite baseApk = parseApkLite(packageFile, flags);
final String packagePath = packageFile.getAbsolutePath();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- return new PackageLite(packagePath, baseApk, null, null, null);
+ return new PackageLite(packagePath, baseApk, null, null, null, null);
}
- private static PackageLite parseClusterPackageLite(File packageDir, int flags,
- AssetManager cachedAssetManager) throws PackageParserException {
+ private static PackageLite parseClusterPackageLite(File packageDir, int flags)
+ throws PackageParserException {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
@@ -768,7 +786,7 @@ public class PackageParser {
final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
for (File file : files) {
if (isApkFile(file)) {
- final ApkLite lite = parseApkLite(file, flags, cachedAssetManager);
+ final ApkLite lite = parseApkLite(file, flags);
// Assert that all package names and version codes are
// consistent with the first one we encounter.
@@ -808,10 +826,12 @@ public class PackageParser {
final int size = apks.size();
String[] splitNames = null;
+ String[] usesSplitNames = null;
String[] splitCodePaths = null;
int[] splitRevisionCodes = null;
if (size > 0) {
splitNames = new String[size];
+ usesSplitNames = new String[size];
splitCodePaths = new String[size];
splitRevisionCodes = new int[size];
@@ -819,13 +839,15 @@ public class PackageParser {
Arrays.sort(splitNames, sSplitNameComparator);
for (int i = 0; i < size; i++) {
- splitCodePaths[i] = apks.get(splitNames[i]).codePath;
- splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
+ final ApkLite apk = apks.get(splitNames[i]);
+ usesSplitNames[i] = apk.usesSplitName;
+ splitCodePaths[i] = apk.codePath;
+ splitRevisionCodes[i] = apk.revisionCode;
}
}
final String codePath = packageDir.getAbsolutePath();
- return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
+ return new PackageLite(codePath, baseApk, splitNames, usesSplitNames, splitCodePaths,
splitRevisionCodes);
}
@@ -1004,6 +1026,42 @@ public class PackageParser {
}
}
+ private static SparseIntArray buildSplitDependencyTree(PackageLite pkg)
+ throws PackageParserException {
+ SparseIntArray splitDependencies = new SparseIntArray();
+ for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) {
+ final String splitDependency = pkg.usesSplitNames[splitIdx];
+ if (splitDependency != null) {
+ final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency);
+ if (depIdx < 0) {
+ throw new PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split '" + pkg.splitNames[splitIdx] + "' requires split '"
+ + splitDependency + "', which is missing.");
+ }
+ splitDependencies.put(splitIdx, depIdx);
+ }
+ }
+
+ // Verify that there are no cycles.
+ final BitSet bitset = new BitSet();
+ for (int i = 0; i < splitDependencies.size(); i++) {
+ int splitIdx = splitDependencies.keyAt(i);
+
+ bitset.clear();
+ while (splitIdx != -1) {
+ if (bitset.get(splitIdx)) {
+ throw new PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Cycle detected in split dependencies.");
+ }
+ bitset.set(splitIdx);
+ splitIdx = splitDependencies.get(splitIdx, -1);
+ }
+ }
+ return splitDependencies.size() != 0 ? splitDependencies : null;
+ }
+
/**
* Parse all APKs contained in the given directory, treating them as a
* single package. This also performs sanity checking, such as requiring
@@ -1014,25 +1072,24 @@ public class PackageParser {
* must be done separately in {@link #collectCertificates(Package, int)}.
*/
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
- final AssetManager assets = newConfiguredAssetManager();
- final PackageLite lite = parseClusterPackageLite(packageDir, 0, assets);
-
+ final PackageLite lite = parseClusterPackageLite(packageDir, 0);
if (mOnlyCoreApps && !lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + packageDir);
}
- try {
- // Load all splits into the AssetManager (base has already been loaded earlier)
- // so that resources can be overriden when parsing the manifests.
- loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
-
- if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
- for (String path : lite.splitCodePaths) {
- loadApkIntoAssetManager(assets, path, flags);
- }
- }
+ // Build the split dependency tree.
+ SparseIntArray splitDependencies = null;
+ final SplitAssetLoader assetLoader;
+ if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
+ splitDependencies = buildSplitDependencyTree(lite);
+ assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+ } else {
+ assetLoader = new DefaultSplitAssetLoader(lite, flags);
+ }
+ try {
+ final AssetManager assets = assetLoader.getBaseAssetManager();
final File baseApk = new File(lite.baseCodePath);
final Package pkg = parseBaseApk(baseApk, assets, flags);
if (pkg == null) {
@@ -1047,9 +1104,12 @@ public class PackageParser {
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
pkg.splitPrivateFlags = new int[num];
+ pkg.applicationInfo.splitNames = pkg.splitNames;
+ pkg.applicationInfo.splitDependencies = splitDependencies;
for (int i = 0; i < num; i++) {
- parseSplitApk(pkg, i, assets, flags);
+ final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
+ parseSplitApk(pkg, i, splitAssets, flags);
}
}
@@ -1057,7 +1117,7 @@ public class PackageParser {
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
- IoUtils.closeQuietly(assets);
+ IoUtils.closeQuietly(assetLoader);
}
}
@@ -1074,7 +1134,7 @@ public class PackageParser {
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final AssetManager assets = newConfiguredAssetManager();
- final PackageLite lite = parseMonolithicPackageLite(apkFile, flags, assets);
+ final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (mOnlyCoreApps) {
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -1168,11 +1228,11 @@ public class PackageParser {
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
- Resources res = null;
+ final Resources res;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
@@ -1225,7 +1285,7 @@ public class PackageParser {
}
String tagName = parser.getName();
- if (tagName.equals("application")) {
+ if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
@@ -1508,7 +1568,7 @@ public class PackageParser {
private static AssetManager newConfiguredAssetManager() {
AssetManager assetManager = new AssetManager();
- assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
return assetManager;
}
@@ -1523,17 +1583,12 @@ public class PackageParser {
*/
public static ApkLite parseApkLite(File apkFile, int flags)
throws PackageParserException {
- return parseApkLite(apkFile, flags, null);
- }
-
- private static ApkLite parseApkLite(File apkFile, int flags,
- @Nullable AssetManager cachedAssetManager) throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
AssetManager assets = null;
XmlResourceParser parser = null;
try {
- assets = cachedAssetManager == null ? newConfiguredAssetManager() : cachedAssetManager;
+ assets = newConfiguredAssetManager();
int cookie = assets.addAssetPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
@@ -1543,7 +1598,6 @@ public class PackageParser {
final DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- final Resources res = new Resources(assets, metrics, null);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Signature[] signatures;
@@ -1565,16 +1619,15 @@ public class PackageParser {
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, res, parser, attrs, flags, signatures, certificates);
+ return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
} catch (XmlPullParserException | IOException | RuntimeException e) {
+ Slog.w(TAG, "Failed to parse " + apkPath, e);
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
- if (cachedAssetManager == null) {
- IoUtils.closeQuietly(assets);
- }
+ IoUtils.closeQuietly(assets);
}
}
@@ -1652,9 +1705,9 @@ public class PackageParser {
(splitName != null) ? splitName.intern() : splitName);
}
- private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
- AttributeSet attrs, int flags, Signature[] signatures, Certificate[][] certificates)
- throws IOException, XmlPullParserException, PackageParserException {
+ private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
+ int flags, Signature[] signatures, Certificate[][] certificates)
+ throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
@@ -1665,6 +1718,8 @@ public class PackageParser {
boolean multiArch = false;
boolean use32bitAbi = false;
boolean extractNativeLibs = true;
+ boolean isolatedSplits = false;
+ String usesSplitName = null;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
final String attr = attrs.getAttributeName(i);
@@ -1677,6 +1732,8 @@ public class PackageParser {
revisionCode = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("coreApp")) {
coreApp = attrs.getAttributeBooleanValue(i, false);
+ } else if (attr.equals("isolatedSplits")) {
+ isolatedSplits = attrs.getAttributeBooleanValue(i, false);
}
}
@@ -1691,14 +1748,16 @@ public class PackageParser {
continue;
}
- if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {
- final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags);
+ if (parser.getDepth() != searchDepth) {
+ continue;
+ }
+
+ if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
+ final VerifierInfo verifier = parseVerifier(attrs);
if (verifier != null) {
verifiers.add(verifier);
}
- }
-
- if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {
+ } else if (TAG_APPLICATION.equals(parser.getName())) {
for (int i = 0; i < attrs.getAttributeCount(); ++i) {
final String attr = attrs.getAttributeName(i);
if ("debuggable".equals(attr)) {
@@ -1714,12 +1773,25 @@ public class PackageParser {
extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
}
+ } else if (TAG_USES_SPLIT.equals(parser.getName())) {
+ if (usesSplitName != null) {
+ Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
+ continue;
+ }
+
+ usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");
+ if (usesSplitName == null) {
+ throw new PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<uses-split> tag requires 'android:name' attribute");
+ }
}
}
- return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
- revisionCode, installLocation, verifiers, signatures, certificates, coreApp,
- debuggable, multiArch, use32bitAbi, extractNativeLibs);
+ return new ApkLite(codePath, packageSplit.first, packageSplit.second, usesSplitName,
+ versionCode, revisionCode, installLocation, verifiers, signatures,
+ certificates, coreApp, debuggable, multiArch, use32bitAbi, extractNativeLibs,
+ isolatedSplits);
}
/**
@@ -1925,6 +1997,10 @@ public class PackageParser {
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
+ final int targetSandboxVersion = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
+ PARSE_DEFAULT_TARGET_SANDBOX);
+ pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
@@ -1940,6 +2016,10 @@ public class PackageParser {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
}
+ if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+ }
+
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
@@ -2402,7 +2482,7 @@ public class PackageParser {
// cannot be windowed / resized. Note that an SDK version of 0 is common for
// pre-Doughnut applications.
if (pkg.applicationInfo.usesCompatibilityMode()) {
- adjustPackageToBeUnresizeable(pkg);
+ adjustPackageToBeUnresizeableAndUnpipable(pkg);
}
return pkg;
}
@@ -2413,9 +2493,10 @@ public class PackageParser {
*
* @param pkg The package which needs to be marked as unresizable.
*/
- private void adjustPackageToBeUnresizeable(Package pkg) {
+ private void adjustPackageToBeUnresizeableAndUnpipable(Package pkg) {
for (Activity a : pkg.activities) {
a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ a.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
}
}
@@ -2666,15 +2747,15 @@ public class PackageParser {
String cls = clsSeq.toString();
char c = cls.charAt(0);
if (c == '.') {
- return (pkg + cls).intern();
+ return pkg + cls;
}
if (cls.indexOf('.') < 0) {
StringBuilder b = new StringBuilder(pkg);
b.append('.');
b.append(cls);
- return b.toString().intern();
+ return b.toString();
}
- return cls.intern();
+ return cls;
}
private static String buildCompoundName(String pkg,
@@ -2694,7 +2775,7 @@ public class PackageParser {
+ pkg + ": " + nameError;
return null;
}
- return (pkg + proc).intern();
+ return pkg + proc;
}
String nameError = validateName(proc, true, false);
if (nameError != null && !"system".equals(proc)) {
@@ -2702,7 +2783,7 @@ public class PackageParser {
+ pkg + ": " + nameError;
return null;
}
- return proc.intern();
+ return proc;
}
private static String buildProcessName(String pkg, String defProc,
@@ -3079,6 +3160,10 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
a.info.targetPackage = str != null ? str.intern() : null;
+ str = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcess);
+ a.info.targetProcess = str != null ? str.intern() : null;
+
a.info.handleProfiling = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
false);
@@ -3656,6 +3741,8 @@ public class PackageParser {
continue;
}
+ ComponentInfo parsedComponent = null;
+
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, false,
@@ -3666,6 +3753,7 @@ public class PackageParser {
}
owner.activities.add(a);
+ parsedComponent = a.info;
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
@@ -3675,6 +3763,7 @@ public class PackageParser {
}
owner.receivers.add(a);
+ parsedComponent = a.info;
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError);
@@ -3684,6 +3773,7 @@ public class PackageParser {
}
owner.services.add(s);
+ parsedComponent = s.info;
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError);
@@ -3693,6 +3783,7 @@ public class PackageParser {
}
owner.providers.add(p);
+ parsedComponent = p.info;
} else if (tagName.equals("activity-alias")) {
Activity a = parseActivityAlias(owner, res, parser, flags, outError);
@@ -3702,6 +3793,7 @@ public class PackageParser {
}
owner.activities.add(a);
+ parsedComponent = a.info;
} else if (parser.getName().equals("meta-data")) {
// note: application meta-data is stored off to the side, so it can
@@ -3768,6 +3860,14 @@ public class PackageParser {
return false;
}
}
+
+ if (parsedComponent != null && parsedComponent.splitName == null) {
+ // If the loaded component did not specify a split, inherit the split name
+ // based on the split it is defined in.
+ // This is used to later load the correct split when starting this
+ // component.
+ parsedComponent.splitName = owner.splitNames[splitIndex];
+ }
}
return true;
@@ -4000,12 +4100,13 @@ public class PackageParser {
setActivityResizeMode(a.info, sa, owner);
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
- a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+ false)) {
+ a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
}
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_onTopLauncher, false)) {
- a.info.flags |= FLAG_ON_TOP_LAUNCHER;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+ a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
}
a.info.lockTaskLaunchMode =
@@ -4020,6 +4121,9 @@ public class PackageParser {
a.info.rotationAnimation =
sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_ROTATE);
+
+ a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
+ ActivityInfo.COLOR_MODE_DEFAULT);
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -4161,16 +4265,13 @@ public class PackageParser {
private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) {
final boolean appExplicitDefault = (owner.applicationInfo.privateFlags
& PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET) != 0;
- final boolean supportsPip =
- sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, false);
if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
|| appExplicitDefault) {
// Activity or app explicitly set if it is resizeable or not;
if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
appExplicitDefault)) {
- aInfo.resizeMode =
- supportsPip ? RESIZE_MODE_RESIZEABLE_AND_PIPABLE : RESIZE_MODE_RESIZEABLE;
+ aInfo.resizeMode = RESIZE_MODE_RESIZEABLE;
} else {
aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE;
}
@@ -4932,9 +5033,7 @@ public class PackageParser {
}
private boolean isWebBrowsableIntent(IntentInfo intent) {
- return intent.hasAction(Intent.ACTION_VIEW)
- && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
- && (intent.hasDataScheme("http") || intent.hasDataScheme("https"));
+ return intent.hasCategory(Intent.CATEGORY_BROWSABLE);
}
private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
@@ -5002,7 +5101,7 @@ public class PackageParser {
if (v != null) {
if (v.type == TypedValue.TYPE_STRING) {
CharSequence cs = v.coerceToString();
- data.putString(name, cs != null ? cs.toString().intern() : null);
+ data.putString(name, cs != null ? cs.toString() : null);
} else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
data.putBoolean(name, v.data != 0);
} else if (v.type >= TypedValue.TYPE_FIRST_INT
@@ -5033,18 +5132,23 @@ public class PackageParser {
return data;
}
- private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
- AttributeSet attrs, int flags) {
- final TypedArray sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.AndroidManifestPackageVerifier);
-
- final String packageName = sa.getNonResourceString(
- com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
+ private static VerifierInfo parseVerifier(AttributeSet attrs) {
+ String packageName = null;
+ String encodedPublicKey = null;
- final String encodedPublicKey = sa.getNonResourceString(
- com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
+ final int attrCount = attrs.getAttributeCount();
+ for (int i = 0; i < attrCount; i++) {
+ final int attrResId = attrs.getAttributeNameResource(i);
+ switch (attrResId) {
+ case com.android.internal.R.attr.name:
+ packageName = attrs.getAttributeValue(i);
+ break;
- sa.recycle();
+ case com.android.internal.R.attr.publicKey:
+ encodedPublicKey = attrs.getAttributeValue(i);
+ break;
+ }
+ }
if (packageName == null || packageName.length() == 0) {
Slog.i(TAG, "verifier package name was null; skipping");
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 6901ba1a21b6..0703138287ba 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -120,7 +120,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PROTECTION_FLAG_SETUP = 0x800;
-
/**
* Additional flag for {@link #protectionLevel}, corresponding
* to the <code>ephemeral</code> value of
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 805054fad389..fb280a1db28c 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -830,7 +830,8 @@ public class ShortcutManager {
*/
public boolean isRequestPinShortcutSupported() {
try {
- return mService.isRequestPinShortcutSupported(injectMyUserId());
+ return mService.isRequestPinItemSupported(injectMyUserId(),
+ LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 4773c730406f..87a6d4a5fa09 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -74,4 +74,6 @@ public abstract class ShortcutServiceInternal {
public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
@NonNull AppWidgetProviderInfo appWidget, @Nullable IntentSender resultIntent,
int userId);
+
+ public abstract boolean isRequestPinItemSupported(int callingUserId, int requestType);
}
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 8766508a5c89..3c3b84d7b2a3 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -25,5 +25,4 @@ import android.os.RemoteCallback;
*/
oneway interface IRuntimePermissionPresenter {
void getAppPermissions(String packageName, in RemoteCallback callback);
- void getAppsUsingPermissions(boolean system, in RemoteCallback callback);
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
index 2e39926422fe..6d55d2f7a860 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -72,15 +72,6 @@ public final class RuntimePermissionPresenter {
List<RuntimePermissionPresentationInfo> permissions) {
/* do nothing - stub */
}
-
- /**
- * The result for {@link #getAppsUsingPermissions(boolean, List)}.
- * @param system Whether to return only the system apps or only the non-system ones.
- * @param apps The apps using runtime permissions.
- */
- public void getAppsUsingPermissions(boolean system, @NonNull List<ApplicationInfo> apps) {
- /* do nothing - stub */
- }
}
private static final Object sLock = new Object();
@@ -127,29 +118,6 @@ public final class RuntimePermissionPresenter {
mRemoteService.processMessage(message);
}
- /**
- * Gets the system apps that use runtime permissions. System apps are ones
- * that are considered system for presentation purposes instead of ones
- * that are preinstalled on the system image. System apps are ones that
- * are on the system image, haven't been updated (a.k.a factory apps)
- * that do not have a launcher icon.
- *
- * @param system If true only system apps are returned otherwise only
- * non-system ones are returned.
- * @param callback Callback to receive the result.
- * @param handler Handler on which to invoke the callback.
- */
- public void getAppsUsingPermissions(boolean system, @NonNull OnResultCallback callback,
- @Nullable Handler handler) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = callback;
- args.arg2 = handler;
- args.argi1 = system ? 1 : 0;
- Message message = mRemoteService.obtainMessage(
- RemoteService.MSG_GET_APPS_USING_PERMISSIONS, args);
- mRemoteService.processMessage(message);
- }
-
private static final class RemoteService
extends Handler implements ServiceConnection {
private static final long UNBIND_TIMEOUT_MILLIS = 10000;
@@ -254,51 +222,6 @@ public final class RuntimePermissionPresenter {
scheduleUnbind();
} break;
- case MSG_GET_APPS_USING_PERMISSIONS: {
- SomeArgs args = (SomeArgs) msg.obj;
- final OnResultCallback callback = (OnResultCallback) args.arg1;
- final Handler handler = (Handler) args.arg2;
- final boolean system = args.argi1 == 1;
- args.recycle();
- final IRuntimePermissionPresenter remoteInstance;
- synchronized (mLock) {
- remoteInstance = mRemoteInstance;
- }
- if (remoteInstance == null) {
- return;
- }
- try {
- remoteInstance.getAppsUsingPermissions(system, new RemoteCallback(
- new RemoteCallback.OnResultListener() {
- @Override
- public void onResult(Bundle result) {
- final List<ApplicationInfo> reportedApps;
- List<ApplicationInfo> apps = null;
- if (result != null) {
- apps = result.getParcelableArrayList(KEY_RESULT);
- }
- if (apps == null) {
- apps = Collections.emptyList();
- }
- reportedApps = apps;
- if (handler != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.getAppsUsingPermissions(system, reportedApps);
- }
- });
- } else {
- callback.getAppsUsingPermissions(system, reportedApps);
- }
- }
- }, this));
- } catch (RemoteException re) {
- Log.e(TAG, "Error getting apps using permissions", re);
- }
- scheduleUnbind();
- } break;
-
case MSG_UNBIND: {
synchronized (mLock) {
if (mBound) {
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
new file mode 100644
index 000000000000..99eb4702d32e
--- /dev/null
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.split;
+
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+
+import android.content.pm.PackageParser;
+import android.content.res.AssetManager;
+import android.os.Build;
+
+import com.android.internal.util.ArrayUtils;
+
+import libcore.io.IoUtils;
+
+/**
+ * Loads the base and split APKs into a single AssetManager.
+ * @hide
+ */
+public class DefaultSplitAssetLoader implements SplitAssetLoader {
+ private final String mBaseCodePath;
+ private final String[] mSplitCodePaths;
+ private final int mFlags;
+
+ private AssetManager mCachedAssetManager;
+
+ public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
+ mBaseCodePath = pkg.baseCodePath;
+ mSplitCodePaths = pkg.splitCodePaths;
+ mFlags = flags;
+ }
+
+ private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+ throws PackageParser.PackageParserException {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
+ throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + apkPath);
+ }
+
+ if (assets.addAssetPath(apkPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
+ }
+
+ @Override
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
+ if (mCachedAssetManager != null) {
+ return mCachedAssetManager;
+ }
+
+ AssetManager assets = new AssetManager();
+ try {
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
+
+ if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+ for (String apkPath : mSplitCodePaths) {
+ loadApkIntoAssetManager(assets, apkPath, mFlags);
+ }
+ }
+
+ mCachedAssetManager = assets;
+ assets = null;
+ return mCachedAssetManager;
+ } finally {
+ if (assets != null) {
+ IoUtils.closeQuietly(assets);
+ }
+ }
+ }
+
+ @Override
+ public AssetManager getSplitAssetManager(int splitIdx)
+ throws PackageParser.PackageParserException {
+ return getBaseAssetManager();
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (mCachedAssetManager != null) {
+ IoUtils.closeQuietly(mCachedAssetManager);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
new file mode 100644
index 000000000000..4df90eb9f53e
--- /dev/null
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.split;
+
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+
+import android.content.pm.PackageParser;
+import android.content.res.AssetManager;
+import android.os.Build;
+import android.util.SparseIntArray;
+
+import libcore.io.IoUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation
+ * is to be used when an application opts-in to isolated split loading.
+ * @hide
+ */
+public class SplitAssetDependencyLoader
+ extends SplitDependencyLoaderHelper<PackageParser.PackageParserException>
+ implements SplitAssetLoader {
+ private static final int BASE_ASSET_PATH_IDX = -1;
+ private final String mBasePath;
+ private final String[] mSplitNames;
+ private final String[] mSplitPaths;
+ private final int mFlags;
+
+ private String[] mCachedBasePaths;
+ private AssetManager mCachedBaseAssetManager;
+
+ private String[][] mCachedSplitPaths;
+ private AssetManager[] mCachedAssetManagers;
+
+ public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, SparseIntArray dependencies,
+ int flags) {
+ super(dependencies);
+ mBasePath = pkg.baseCodePath;
+ mSplitNames = pkg.splitNames;
+ mSplitPaths = pkg.splitCodePaths;
+ mFlags = flags;
+ mCachedBasePaths = null;
+ mCachedBaseAssetManager = null;
+ mCachedSplitPaths = new String[mSplitNames.length][];
+ mCachedAssetManagers = new AssetManager[mSplitNames.length];
+ }
+
+ @Override
+ protected boolean isSplitCached(int splitIdx) {
+ if (splitIdx != -1) {
+ return mCachedAssetManagers[splitIdx] != null;
+ }
+ return mCachedBaseAssetManager != null;
+ }
+
+ // Adds all non-code configuration splits for this split name. The split name is expected
+ // to represent a feature split.
+ private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) {
+ for (int i = 0; i < mSplitNames.length; i++) {
+ if (isConfigurationSplitOf(mSplitNames[i], splitName)) {
+ outAssetPaths.add(mSplitPaths[i]);
+ }
+ }
+ }
+
+ private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
+ throws PackageParser.PackageParserException {
+ final AssetManager assets = new AssetManager();
+ try {
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+
+ for (String assetPath : assetPaths) {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
+ !PackageParser.isApkPath(assetPath)) {
+ throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + assetPath);
+ }
+
+ if (assets.addAssetPath(assetPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + assetPath);
+ }
+ }
+ return assets;
+ } catch (Throwable e) {
+ IoUtils.closeQuietly(assets);
+ throw e;
+ }
+ }
+
+ @Override
+ protected void constructSplit(int splitIdx, int parentSplitIdx) throws
+ PackageParser.PackageParserException {
+ final ArrayList<String> assetPaths = new ArrayList<>();
+ if (splitIdx == BASE_ASSET_PATH_IDX) {
+ assetPaths.add(mBasePath);
+ addAllConfigSplits(null, assetPaths);
+ mCachedBasePaths = assetPaths.toArray(new String[assetPaths.size()]);
+ mCachedBaseAssetManager = createAssetManagerWithPaths(mCachedBasePaths, mFlags);
+ return;
+ }
+
+ if (parentSplitIdx == BASE_ASSET_PATH_IDX) {
+ Collections.addAll(assetPaths, mCachedBasePaths);
+ } else {
+ Collections.addAll(assetPaths, mCachedSplitPaths[parentSplitIdx]);
+ }
+
+ assetPaths.add(mSplitPaths[splitIdx]);
+ addAllConfigSplits(mSplitNames[splitIdx], assetPaths);
+ mCachedSplitPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+ mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedSplitPaths[splitIdx],
+ mFlags);
+ }
+
+ @Override
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
+ loadDependenciesForSplit(BASE_ASSET_PATH_IDX);
+ return mCachedBaseAssetManager;
+ }
+
+ @Override
+ public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
+ loadDependenciesForSplit(idx);
+ return mCachedAssetManagers[idx];
+ }
+
+ @Override
+ public void close() throws Exception {
+ IoUtils.closeQuietly(mCachedBaseAssetManager);
+ for (AssetManager assets : mCachedAssetManagers) {
+ IoUtils.closeQuietly(assets);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/split/SplitAssetLoader.java b/core/java/android/content/pm/split/SplitAssetLoader.java
new file mode 100644
index 000000000000..108fb95a150d
--- /dev/null
+++ b/core/java/android/content/pm/split/SplitAssetLoader.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.split;
+
+import android.content.pm.PackageParser;
+import android.content.res.AssetManager;
+
+/**
+ * Simple interface for loading base Assets and Splits. Used by PackageParser when parsing
+ * split APKs.
+ *
+ * @hide
+ */
+public interface SplitAssetLoader extends AutoCloseable {
+ AssetManager getBaseAssetManager() throws PackageParser.PackageParserException;
+ AssetManager getSplitAssetManager(int splitIdx) throws PackageParser.PackageParserException;
+}
diff --git a/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java b/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java
new file mode 100644
index 000000000000..b49348000449
--- /dev/null
+++ b/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.split;
+
+import android.annotation.Nullable;
+import android.util.IntArray;
+import android.util.SparseIntArray;
+
+/**
+ * A helper class that implements the dependency tree traversal for splits. Callbacks
+ * are implemented by subclasses to notify whether a split has already been constructed
+ * and is cached, and to actually create the split requested.
+ *
+ * This helper is meant to be subclassed so as to reduce the number of allocations
+ * needed to make use of it.
+ *
+ * All inputs and outputs are assumed to be indices into an array of splits.
+ *
+ * @hide
+ */
+public abstract class SplitDependencyLoaderHelper<E extends Exception> {
+ @Nullable private final SparseIntArray mDependencies;
+
+ /**
+ * Construct a new SplitDependencyLoaderHelper. Meant to be called from the
+ * subclass constructor.
+ * @param dependencies The dependency tree of splits. Can be null, which leads to
+ * just the implicit dependency of all splits on the base.
+ */
+ protected SplitDependencyLoaderHelper(@Nullable SparseIntArray dependencies) {
+ mDependencies = dependencies;
+ }
+
+ /**
+ * Traverses the dependency tree and constructs any splits that are not already
+ * cached. This routine short-circuits and skips the creation of splits closer to the
+ * root if they are cached, as reported by the subclass implementation of
+ * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass
+ * implementation of {@link #constructSplit(int, int)}.
+ * @param splitIdx The index of the split to load. Can be -1, which represents the
+ * base Application.
+ */
+ protected void loadDependenciesForSplit(int splitIdx) throws E {
+ // Quick check before any allocations are done.
+ if (isSplitCached(splitIdx)) {
+ return;
+ }
+
+ final IntArray linearDependencies = new IntArray();
+ linearDependencies.add(splitIdx);
+
+ // Collect all the dependencies that need to be constructed.
+ // They will be listed from leaf to root.
+ while (splitIdx >= 0) {
+ splitIdx = mDependencies != null ? mDependencies.get(splitIdx, -1) : -1;
+ if (isSplitCached(splitIdx)) {
+ break;
+ }
+ linearDependencies.add(splitIdx);
+ }
+
+ // Visit each index, from right to left (root to leaf).
+ int parentIdx = splitIdx;
+ for (int i = linearDependencies.size() - 1; i >= 0; i--) {
+ final int idx = linearDependencies.get(i);
+ constructSplit(idx, parentIdx);
+ parentIdx = idx;
+ }
+ }
+
+ /**
+ * Subclass to report whether the split at `splitIdx` is cached and need not be constructed.
+ * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached.
+ * @param splitIdx The index of the split to check for in the cache.
+ * @return true if the split is cached and does not need to be constructed.
+ */
+ protected abstract boolean isSplitCached(int splitIdx);
+
+ /**
+ * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`.
+ * The result is expected to be cached by the subclass in its own structures.
+ * @param splitIdx The index of the split to construct. Can be -1, which represents the
+ * base Application.
+ * @param parentSplitIdx The index of the parent split. Can be -1, which represents the
+ * base Application.
+ * @throws E
+ */
+ protected abstract void constructSplit(int splitIdx, int parentSplitIdx) throws E;
+
+ /**
+ * Returns true if `splitName` represents a Configuration split of `featureSplitName`.
+ *
+ * A Configuration split's name is prefixed with the associated Feature split's name
+ * or the empty string if the split is for the base Application APK. It is then followed by the
+ * dollar sign character "$" and some unique string that should represent the configurations
+ * the split contains.
+ *
+ * Example:
+ * <table>
+ * <tr>
+ * <th>Feature split name</th>
+ * <th>Configuration split name: xhdpi</th>
+ * <th>Configuration split name: fr-rFR</th>
+ * </tr>
+ * <tr>
+ * <td>(base APK)</td>
+ * <td><code>$xhdpi</code></td>
+ * <td><code>$fr-rFR</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>Extras</code></td>
+ * <td><code>Extras$xhdpi</code></td>
+ * <td><code>Extras$fr-rFR</code></td>
+ * </tr>
+ * </table>
+ *
+ * @param splitName The name of the split to check.
+ * @param featureSplitName The name of the Feature split. May be null or "" if checking
+ * the base Application APK.
+ * @return true if the splitName represents a Configuration split of featureSplitName.
+ */
+ protected static boolean isConfigurationSplitOf(String splitName, String featureSplitName) {
+ if (featureSplitName == null || featureSplitName.length() == 0) {
+ // We are looking for configuration splits of the base, which have some legacy support.
+ if (splitName.startsWith("config_")) {
+ return true;
+ } else if (splitName.startsWith("$")) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return splitName.startsWith(featureSplitName + "$");
+ }
+ }
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index db24ffef99cf..37e32ff2130a 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -21,6 +21,7 @@ import android.annotation.ArrayRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration.NativeConfig;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -183,6 +184,11 @@ public final class AssetManager implements AutoCloseable {
if (block < 0) {
return null;
}
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
if (outValue.type == TypedValue.TYPE_STRING) {
return mStringBlocks[block].get(outValue.data);
}
@@ -220,6 +226,11 @@ public final class AssetManager implements AutoCloseable {
if (block < 0) {
return false;
}
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = mStringBlocks[block].get(outValue.data);
}
@@ -266,6 +277,11 @@ public final class AssetManager implements AutoCloseable {
if (block < 0) {
return false;
}
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
if (outValue.type == TypedValue.TYPE_STRING) {
final StringBlock[] blocks = ensureStringBlocks();
outValue.string = blocks[block].get(outValue.data);
@@ -759,7 +775,7 @@ public final class AssetManager implements AutoCloseable {
int orientation, int touchscreen, int density, int keyboard,
int keyboardHidden, int navigation, int screenWidth, int screenHeight,
int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
- int screenLayout, int uiMode, int majorVersion);
+ int screenLayout, int uiMode, int colorMode, int majorVersion);
/**
* Retrieve the resource identifier for the given resource name.
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a81329d9ee67..99fbee1ea3cc 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -102,66 +102,66 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public boolean userSetLocale;
- /** Constant for {@link #colorimetry}: bits that encode whether the screen is wide gamut. */
- public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 0x3;
+ /** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
+ public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
* indicating that it is unknown whether or not the screen is wide gamut.
*/
- public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
+ public static final int COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
* indicating that the screen is not wide gamut.
* <p>Corresponds to the <code>-nowidecg</code> resource qualifier.</p>
*/
- public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 0x1;
+ public static final int COLOR_MODE_WIDE_COLOR_GAMUT_NO = 0x1;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} value
* indicating that the screen is wide gamut.
* <p>Corresponds to the <code>-widecg</code> resource qualifier.</p>
*/
- public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 0x2;
+ public static final int COLOR_MODE_WIDE_COLOR_GAMUT_YES = 0x2;
- /** Constant for {@link #colorimetry}: bits that encode whether the dynamic range of the screen. */
- public static final int COLORIMETRY_HDR_MASK = 0xc;
- /** Constant for {@link #colorimetry}: bits shift to get the screen dynamic range. */
- public static final int COLORIMETRY_HDR_SHIFT = 2;
+ /** Constant for {@link #colorMode}: bits that encode whether the dynamic range of the screen. */
+ public static final int COLOR_MODE_HDR_MASK = 0xc;
+ /** Constant for {@link #colorMode}: bits shift to get the screen dynamic range. */
+ public static final int COLOR_MODE_HDR_SHIFT = 2;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
* indicating that it is unknown whether or not the screen is HDR.
*/
- public static final int COLORIMETRY_HDR_UNDEFINED = 0x0;
+ public static final int COLOR_MODE_HDR_UNDEFINED = 0x0;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
* indicating that the screen is not HDR (low/standard dynamic range).
* <p>Corresponds to the <code>-lowdr</code> resource qualifier.</p>
*/
- public static final int COLORIMETRY_HDR_NO = 0x1 << COLORIMETRY_HDR_SHIFT;
+ public static final int COLOR_MODE_HDR_NO = 0x1 << COLOR_MODE_HDR_SHIFT;
/**
- * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+ * Constant for {@link #colorMode}: a {@link #COLOR_MODE_HDR_MASK} value
* indicating that the screen is HDR (dynamic range).
* <p>Corresponds to the <code>-highdr</code> resource qualifier.</p>
*/
- public static final int COLORIMETRY_HDR_YES = 0x2 << COLORIMETRY_HDR_SHIFT;
+ public static final int COLOR_MODE_HDR_YES = 0x2 << COLOR_MODE_HDR_SHIFT;
- /** Constant for {@link #colorimetry}: a value indicating that colorimetry is undefined */
+ /** Constant for {@link #colorMode}: a value indicating that the color mode is undefined */
@SuppressWarnings("PointlessBitwiseExpression")
- public static final int COLORIMETRY_UNDEFINED = COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED |
- COLORIMETRY_HDR_UNDEFINED;
+ public static final int COLOR_MODE_UNDEFINED = COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED |
+ COLOR_MODE_HDR_UNDEFINED;
/**
* Bit mask of for color capabilities of the screen. Currently there are two fields:
- * <p>The {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of
+ * <p>The {@link #COLOR_MODE_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of
* the screen. They may be one of
- * {@link #COLORIMETRY_WIDE_COLOR_GAMUT_NO} or {@link #COLORIMETRY_WIDE_COLOR_GAMUT_YES}.</p>
+ * {@link #COLOR_MODE_WIDE_COLOR_GAMUT_NO} or {@link #COLOR_MODE_WIDE_COLOR_GAMUT_YES}.</p>
*
- * <p>The {@link #COLORIMETRY_HDR_MASK} defines the dynamic range of the screen. They may be
- * one of {@link #COLORIMETRY_HDR_NO} or {@link #COLORIMETRY_HDR_YES}.</p>
+ * <p>The {@link #COLOR_MODE_HDR_MASK} defines the dynamic range of the screen. They may be
+ * one of {@link #COLOR_MODE_HDR_NO} or {@link #COLOR_MODE_HDR_YES}.</p>
*
* <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
* Multiple Screens</a> for more information.</p>
*/
- public int colorimetry;
+ public int colorMode;
/** Constant for {@link #screenLayout}: bits that encode the size. */
public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
@@ -393,8 +393,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
list.add("CONFIG_SCREEN_LAYOUT");
}
- if ((diff & ActivityInfo.CONFIG_COLORIMETRY) != 0) {
- list.add("CONFIG_COLORIMETRY");
+ if ((diff & ActivityInfo.CONFIG_COLOR_MODE) != 0) {
+ list.add("CONFIG_COLOR_MODE");
}
if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) {
list.add("CONFIG_UI_MODE");
@@ -776,7 +776,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
NATIVE_CONFIG_UI_MODE,
NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
NATIVE_CONFIG_LAYOUTDIR,
- NATIVE_CONFIG_COLORIMETRY,
+ NATIVE_CONFIG_COLOR_MODE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface NativeConfig {}
@@ -813,8 +813,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
/** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
- /** @hide Native-specific bit mask for COLORIMETRY config ; DO NOT USE UNLESS YOU ARE SURE.*/
- public static final int NATIVE_CONFIG_COLORIMETRY = 0x10000;
+ /** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/
+ public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000;
/**
* <p>Construct an invalid Configuration. This state is only suitable for constructing a
@@ -873,7 +873,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = o.navigationHidden;
orientation = o.orientation;
screenLayout = o.screenLayout;
- colorimetry = o.colorimetry;
+ colorMode = o.colorMode;
uiMode = o.uiMode;
screenWidthDp = o.screenWidthDp;
screenHeightDp = o.screenHeightDp;
@@ -954,19 +954,19 @@ public final class Configuration implements Parcelable, Comparable<Configuration
default: sb.append(" layoutLong=");
sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
}
- switch ((colorimetry&COLORIMETRY_HDR_MASK)) {
- case COLORIMETRY_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
- case COLORIMETRY_HDR_NO: /* ldr is not interesting to print */ break;
- case COLORIMETRY_HDR_YES: sb.append(" hdr"); break;
+ switch ((colorMode &COLOR_MODE_HDR_MASK)) {
+ case COLOR_MODE_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
+ case COLOR_MODE_HDR_NO: /* ldr is not interesting to print */ break;
+ case COLOR_MODE_HDR_YES: sb.append(" hdr"); break;
default: sb.append(" dynamicRange=");
- sb.append(colorimetry&COLORIMETRY_HDR_MASK); break;
+ sb.append(colorMode &COLOR_MODE_HDR_MASK); break;
}
- switch ((colorimetry&COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
- case COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
- case COLORIMETRY_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
- case COLORIMETRY_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
+ switch ((colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
+ case COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
+ case COLOR_MODE_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
+ case COLOR_MODE_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
default: sb.append(" wideColorGamut=");
- sb.append(colorimetry&COLORIMETRY_WIDE_COLOR_GAMUT_MASK); break;
+ sb.append(colorMode &COLOR_MODE_WIDE_COLOR_GAMUT_MASK); break;
}
switch (orientation) {
case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
@@ -1059,7 +1059,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
orientation = ORIENTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_UNDEFINED;
- colorimetry = COLORIMETRY_UNDEFINED;
+ colorMode = COLOR_MODE_UNDEFINED;
uiMode = UI_MODE_TYPE_UNDEFINED;
screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
@@ -1195,21 +1195,21 @@ public final class Configuration implements Parcelable, Comparable<Configuration
| (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED);
}
- if (((delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
- COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED)
- && (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)
- != (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
- changed |= ActivityInfo.CONFIG_COLORIMETRY;
- colorimetry = (colorimetry & ~COLORIMETRY_WIDE_COLOR_GAMUT_MASK)
- | (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK);
+ if (((delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
+ COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
+ && (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
+ != (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
+ changed |= ActivityInfo.CONFIG_COLOR_MODE;
+ colorMode = (colorMode & ~COLOR_MODE_WIDE_COLOR_GAMUT_MASK)
+ | (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK);
}
- if (((delta.colorimetry & COLORIMETRY_HDR_MASK) != COLORIMETRY_HDR_UNDEFINED)
- && (delta.colorimetry & COLORIMETRY_HDR_MASK)
- != (colorimetry & COLORIMETRY_HDR_MASK)) {
- changed |= ActivityInfo.CONFIG_COLORIMETRY;
- colorimetry = (colorimetry & ~COLORIMETRY_HDR_MASK)
- | (delta.colorimetry & COLORIMETRY_HDR_MASK);
+ if (((delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
+ && (delta.colorMode & COLOR_MODE_HDR_MASK)
+ != (colorMode & COLOR_MODE_HDR_MASK)) {
+ changed |= ActivityInfo.CONFIG_COLOR_MODE;
+ colorMode = (colorMode & ~COLOR_MODE_HDR_MASK)
+ | (delta.colorMode & COLOR_MODE_HDR_MASK);
}
if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
@@ -1362,17 +1362,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
}
if ((compareUndefined ||
- (delta.colorimetry & COLORIMETRY_HDR_MASK) != COLORIMETRY_HDR_UNDEFINED)
- && (colorimetry & COLORIMETRY_HDR_MASK) !=
- (delta.colorimetry & COLORIMETRY_HDR_MASK)) {
- changed |= ActivityInfo.CONFIG_COLORIMETRY;
+ (delta.colorMode & COLOR_MODE_HDR_MASK) != COLOR_MODE_HDR_UNDEFINED)
+ && (colorMode & COLOR_MODE_HDR_MASK) !=
+ (delta.colorMode & COLOR_MODE_HDR_MASK)) {
+ changed |= ActivityInfo.CONFIG_COLOR_MODE;
}
if ((compareUndefined ||
- (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
- COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED)
- && (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
- (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
- changed |= ActivityInfo.CONFIG_COLORIMETRY;
+ (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
+ COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED)
+ && (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
+ (delta.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
+ changed |= ActivityInfo.CONFIG_COLOR_MODE;
}
if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED))
&& uiMode != delta.uiMode) {
@@ -1485,7 +1485,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(navigationHidden);
dest.writeInt(orientation);
dest.writeInt(screenLayout);
- dest.writeInt(colorimetry);
+ dest.writeInt(colorMode);
dest.writeInt(uiMode);
dest.writeInt(screenWidthDp);
dest.writeInt(screenHeightDp);
@@ -1520,7 +1520,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigationHidden = source.readInt();
orientation = source.readInt();
screenLayout = source.readInt();
- colorimetry = source.readInt();
+ colorMode = source.readInt();
uiMode = source.readInt();
screenWidthDp = source.readInt();
screenHeightDp = source.readInt();
@@ -1602,7 +1602,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.orientation - that.orientation;
if (n != 0) return n;
- n = this.colorimetry - that.colorimetry;
+ n = this.colorMode - that.colorMode;
if (n != 0) return n;
n = this.screenLayout - that.screenLayout;
if (n != 0) return n;
@@ -1649,7 +1649,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
result = 31 * result + navigationHidden;
result = 31 * result + orientation;
result = 31 * result + screenLayout;
- result = 31 * result + colorimetry;
+ result = 31 * result + colorMode;
result = 31 * result + uiMode;
result = 31 * result + screenWidthDp;
result = 31 * result + screenHeightDp;
@@ -1763,7 +1763,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @return true if the screen has a wide color gamut, false otherwise
*/
public boolean isScreenWideColorGamut() {
- return (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) == COLORIMETRY_WIDE_COLOR_GAMUT_YES;
+ return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES;
}
/**
@@ -1772,7 +1772,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @return true if the screen has a high dynamic range, false otherwise
*/
public boolean isScreenHdr() {
- return (colorimetry & COLORIMETRY_HDR_MASK) == COLORIMETRY_HDR_YES;
+ return (colorMode & COLOR_MODE_HDR_MASK) == COLOR_MODE_HDR_YES;
}
/**
@@ -1907,22 +1907,22 @@ public final class Configuration implements Parcelable, Comparable<Configuration
break;
}
- switch (config.colorimetry & Configuration.COLORIMETRY_HDR_MASK) {
- case Configuration.COLORIMETRY_HDR_YES:
+ switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) {
+ case Configuration.COLOR_MODE_HDR_YES:
parts.add("highdr");
break;
- case Configuration.COLORIMETRY_HDR_NO:
+ case Configuration.COLOR_MODE_HDR_NO:
parts.add("lowdr");
break;
default:
break;
}
- switch (config.colorimetry & Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_MASK) {
- case Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_YES:
+ switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) {
+ case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES:
parts.add("widecg");
break;
- case Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_NO:
+ case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO:
parts.add("nowidecg");
break;
default:
@@ -2154,14 +2154,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
}
- if ((base.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
- (change.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
- delta.colorimetry |= change.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK;
+ if ((base.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) !=
+ (change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK)) {
+ delta.colorMode |= change.colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK;
}
- if ((base.colorimetry & COLORIMETRY_HDR_MASK) !=
- (change.colorimetry & COLORIMETRY_HDR_MASK)) {
- delta.colorimetry |= change.colorimetry & COLORIMETRY_HDR_MASK;
+ if ((base.colorMode & COLOR_MODE_HDR_MASK) !=
+ (change.colorMode & COLOR_MODE_HDR_MASK)) {
+ delta.colorMode |= change.colorMode & COLOR_MODE_HDR_MASK;
}
if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
@@ -2206,7 +2206,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
private static final String XML_ATTR_ORIENTATION = "ori";
private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
- private static final String XML_ATTR_COLORIMETRY = "clrMtry";
+ private static final String XML_ATTR_COLOR_MODE = "clrMod";
private static final String XML_ATTR_UI_MODE = "ui";
private static final String XML_ATTR_SCREEN_WIDTH = "width";
private static final String XML_ATTR_SCREEN_HEIGHT = "height";
@@ -2249,8 +2249,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
ORIENTATION_UNDEFINED);
configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT,
SCREENLAYOUT_UNDEFINED);
- configOut.colorimetry = XmlUtils.readIntAttribute(parser, XML_ATTR_COLORIMETRY,
- COLORIMETRY_UNDEFINED);
+ configOut.colorMode = XmlUtils.readIntAttribute(parser, XML_ATTR_COLOR_MODE,
+ COLOR_MODE_UNDEFINED);
configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0);
configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH,
SCREEN_WIDTH_DP_UNDEFINED);
@@ -2313,8 +2313,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (config.screenLayout != SCREENLAYOUT_UNDEFINED) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout);
}
- if (config.colorimetry != COLORIMETRY_UNDEFINED) {
- XmlUtils.writeIntAttribute(xml, XML_ATTR_COLORIMETRY, config.colorimetry);
+ if (config.colorMode != COLOR_MODE_UNDEFINED) {
+ XmlUtils.writeIntAttribute(xml, XML_ATTR_COLOR_MODE, config.colorMode);
}
if (config.uiMode != 0) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode);
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
new file mode 100644
index 000000000000..7ea62db3b1f0
--- /dev/null
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -0,0 +1,107 @@
+/*
+ * 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.content.res;
+
+import com.android.internal.R;
+import android.text.FontConfig;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parser for xml type font resources.
+ * @hide
+ */
+public class FontResourcesParser {
+ private static final int NORMAL_WEIGHT = 400;
+ private static final int ITALIC = 1;
+
+ public static FontConfig parse(XmlPullParser parser, Resources resources)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+ return readFamilies(parser, resources);
+ }
+
+ private static FontConfig readFamilies(XmlPullParser parser, Resources resources)
+ throws XmlPullParserException, IOException {
+ FontConfig config = new FontConfig();
+ parser.require(XmlPullParser.START_TAG, null, "font-family");
+ String tag = parser.getName();
+ if (tag.equals("font-family")) {
+ config.getFamilies().add(readFamily(parser, resources));
+ } else {
+ skip(parser);
+ }
+ return config;
+ }
+
+ private static FontConfig.Family readFamily(XmlPullParser parser, Resources resources)
+ throws XmlPullParserException, IOException {
+ List<FontConfig.Font> fonts = new ArrayList<>();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ String tag = parser.getName();
+ if (tag.equals("font")) {
+ fonts.add(readFont(parser, resources));
+ } else {
+ skip(parser);
+ }
+ }
+ return new FontConfig.Family(null, fonts, null, null);
+ }
+
+ private static FontConfig.Font readFont(XmlPullParser parser, Resources resources)
+ throws XmlPullParserException, IOException {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+ TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamilyFont);
+ int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight, NORMAL_WEIGHT);
+ boolean isItalic = ITALIC == array.getInt(R.styleable.FontFamilyFont_fontStyle, 0);
+ String filename = array.getString(R.styleable.FontFamilyFont_font);
+ array.recycle();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ skip(parser);
+ }
+ return new FontConfig.Font(filename, 0, null, weight, isItalic);
+ }
+
+ private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ int depth = 1;
+ while (depth > 0) {
+ switch (parser.next()) {
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c3185a7cad05..04e4454a95c4 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -27,6 +27,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorRes;
import android.annotation.DimenRes;
import android.annotation.DrawableRes;
+import android.annotation.FontRes;
import android.annotation.FractionRes;
import android.annotation.IntegerRes;
import android.annotation.LayoutRes;
@@ -39,6 +40,7 @@ import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.Config;
import android.graphics.Movie;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -349,12 +351,12 @@ public class Resources {
*
* @return Typeface The Typeface data associated with the resource.
*/
- @NonNull public Typeface getFont(@StringRes int id) throws NotFoundException {
+ @NonNull public Typeface getFont(@FontRes int id) throws NotFoundException {
final TypedValue value = obtainTempTypedValue();
try {
final ResourcesImpl impl = mResourcesImpl;
impl.getValue(id, value, true);
- Typeface typeface = impl.loadFont(value, id);
+ Typeface typeface = impl.loadFont(this, value, id);
if (typeface != null) {
return typeface;
}
@@ -365,6 +367,11 @@ public class Resources {
+ Integer.toHexString(id));
}
+ @NonNull
+ Typeface getFont(@NonNull TypedValue value, @FontRes int id) throws NotFoundException {
+ return mResourcesImpl.loadFont(this, value, id);
+ }
+
/**
* Returns the character sequence necessary for grammatically correct pluralization
* of the given resource ID for the given quantity.
@@ -1604,7 +1611,7 @@ public class Resources {
* {@link ActivityInfo}
* @see ActivityInfo
*/
- public int getChangingConfigurations() {
+ public @Config int getChangingConfigurations() {
return mThemeImpl.getChangingConfigurations();
}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 05892e0ad660..bf8109627e7e 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -30,6 +30,7 @@ import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
+import android.content.res.Configuration.NativeConfig;
import android.content.res.Resources.NotFoundException;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
@@ -38,6 +39,7 @@ import android.icu.text.PluralRules;
import android.os.Build;
import android.os.LocaleList;
import android.os.Trace;
+import android.text.FontConfig;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -45,7 +47,6 @@ import android.util.LongSparseArray;
import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
-import android.view.Display;
import android.view.DisplayAdjustments;
import java.io.IOException;
@@ -420,7 +421,7 @@ public class ResourcesImpl {
mConfiguration.smallestScreenWidthDp,
mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
mConfiguration.screenLayout, mConfiguration.uiMode,
- Build.VERSION.RESOURCES_SDK_INT);
+ mConfiguration.colorMode, Build.VERSION.RESOURCES_SDK_INT);
if (DEBUG_CONFIG) {
Slog.i(TAG, "**** Updating config of " + this + ": final config is "
@@ -745,13 +746,17 @@ public class ResourcesImpl {
* Loads a font from XML or resources stream.
*/
@Nullable
- public Typeface loadFont(TypedValue value, int id) {
+ public Typeface loadFont(Resources wrapper, TypedValue value, int id) {
if (value.string == null) {
throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+ Integer.toHexString(id) + ") is not a Font: " + value);
}
final String file = value.string.toString();
+ Typeface cached = Typeface.findFromCache(mAssets, file);
+ if (cached != null) {
+ return cached;
+ }
if (DEBUG_LOAD) {
Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file);
@@ -759,12 +764,17 @@ public class ResourcesImpl {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
try {
- if (file.endsWith(".xml")) {
- // TODO handle xml type font definitions
- } else {
- return Typeface.createFromResources(
- mAssets, value.string.toString(), value.assetCookie);
+ if (file.endsWith("xml")) {
+ final XmlResourceParser rp = loadXmlResourceParser(
+ file, id, value.assetCookie, "font");
+ final FontConfig config = FontResourcesParser.parse(rp, wrapper);
+ return Typeface.createFromResources(config, mAssets, file);
}
+ return Typeface.createFromResources(mAssets, file, value.assetCookie);
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Failed to parse xml resource " + file, e);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to read xml resource " + file, e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
@@ -1197,7 +1207,7 @@ public class ResourcesImpl {
@Config int getChangingConfigurations() {
synchronized (mKey) {
- final int nativeChangingConfig =
+ final @NativeConfig int nativeChangingConfig =
AssetManager.getThemeChangingConfigurations(mTheme);
return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 391220134ade..f48afb55c58a 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.StrictMode;
import android.util.AttributeSet;
@@ -937,6 +938,36 @@ public class TypedArray {
}
/**
+ * Retrieve the Typeface for the attribute at <var>index</var>.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a font.
+ *
+ * @param index Index of attribute to retrieve.
+ *
+ * @return Typeface for the attribute, or {@code null} if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not a font resource.
+ */
+ @Nullable
+ public Typeface getFont(@StyleableRes int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
+ final TypedValue value = mValue;
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index + ": " + value);
+ }
+ return mResources.getFont(value, value.resourceId);
+ }
+ return null;
+ }
+
+ /**
* Retrieve the CharSequence[] for the attribute at <var>index</var>.
* This gets the resource ID of the selected attribute, and uses
* {@link Resources#getTextArray Resources.getTextArray} of the owning
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 227066ddc571..8cd3d7b5bc68 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -728,13 +728,10 @@ public class DatabaseUtils {
* @param values the {@link ContentValues} to put the row into.
*/
public static void cursorRowToContentValues(Cursor cursor, ContentValues values) {
- AbstractWindowedCursor awc =
- (cursor instanceof AbstractWindowedCursor) ? (AbstractWindowedCursor) cursor : null;
-
String[] columns = cursor.getColumnNames();
int length = columns.length;
for (int i = 0; i < length; i++) {
- if (awc != null && awc.isBlob(i)) {
+ if (cursor.getType(i) == Cursor.FIELD_TYPE_BLOB) {
values.put(columns[i], cursor.getBlob(i));
} else {
values.put(columns[i], cursor.getString(i));
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index fffb1d77d27c..e97bb2f79be8 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -40,7 +40,7 @@ import libcore.util.NativeAllocationRegistry;
public final class HardwareBuffer implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RGBA_8888, RGBA_FP16, RGBX_8888, RGB_888, RGB_565})
+ @IntDef({RGBA_8888, RGBA_FP16, RGBX_8888, RGB_888, RGB_565, BLOB})
public @interface Format {};
/** Format: 8 bits each red, green, blue, alpha */
@@ -52,7 +52,9 @@ public final class HardwareBuffer implements Parcelable {
/** Format: 5 bits each red and blue, 6 bits green, no alpha */
public static final int RGB_565 = 4;
/** Format: 16 bits each red, green, blue, alpha */
- public static final int RGBA_FP16 = 5;
+ public static final int RGBA_FP16 = 0x16;
+ /** Format: opaque format used for raw data transfer; must have a height of 1 */
+ public static final int BLOB = 0x21;
// Note: do not rename, this field is used by native code
private long mNativeObject;
@@ -135,6 +137,9 @@ public final class HardwareBuffer implements Parcelable {
if (layers <= 0) {
throw new IllegalArgumentException("Invalid layer count " + layers);
}
+ if (format == BLOB && height != 1) {
+ throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
+ }
long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
if (nativeObject == 0) {
throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
@@ -295,6 +300,7 @@ public final class HardwareBuffer implements Parcelable {
case RGBX_8888:
case RGB_565:
case RGB_888:
+ case BLOB:
return true;
}
return false;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 06ab13e9c0a5..d87c55e1c7c7 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -729,14 +729,22 @@ public final class Sensor {
private static final int DATA_INJECTION_MASK = 0x10;
private static final int DATA_INJECTION_SHIFT = 4;
- // MASK for dynamic sensor (sensor that added during runtime), bit 6.
+ // MASK for dynamic sensor (sensor that added during runtime), bit 5.
private static final int DYNAMIC_SENSOR_MASK = 0x20;
private static final int DYNAMIC_SENSOR_SHIFT = 5;
- // MASK for indication bit of sensor additional information support (bit 7).
+ // MASK for indication bit of sensor additional information support, bit 6.
private static final int ADDITIONAL_INFO_MASK = 0x40;
private static final int ADDITIONAL_INFO_SHIFT = 6;
+ // Mask for direct mode highest rate level, bit 7, 8, 9.
+ private static final int DIRECT_REPORT_MASK = 0x380;
+ private static final int DIRECT_REPORT_SHIFT = 7;
+
+ // Mask for supported direct channel, bit 10, 11
+ private static final int DIRECT_CHANNEL_MASK = 0xC00;
+ private static final int DIRECT_CHANNEL_SHIFT = 10;
+
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
// Note: This needs to be updated, whenever a new sensor is added.
@@ -796,6 +804,42 @@ public final class Sensor {
return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
}
+ /**
+ * Get the highest supported direct report mode rate level of the sensor.
+ *
+ * @return Highest direct report rate level of this sensor. If the sensor does not support
+ * direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}.
+ * @see SensorDirectChannel#RATE_STOP
+ * @see SensorDirectChannel#RATE_NORMAL
+ * @see SensorDirectChannel#RATE_FAST
+ * @see SensorDirectChannel#RATE_VERY_FAST
+ */
+ @SensorDirectChannel.RateLevel
+ public int getHighestDirectReportRateLevel() {
+ int rateLevel = ((mFlags & DIRECT_REPORT_MASK) >> DIRECT_REPORT_SHIFT);
+ return rateLevel <= SensorDirectChannel.RATE_VERY_FAST
+ ? rateLevel : SensorDirectChannel.RATE_VERY_FAST;
+ }
+
+ /**
+ * Test if sensor support direct channel backed by a specific type of shared memory.
+ *
+ * @param sharedMemType type of shared memory used by direct channel.
+ * @return <code>true</code> if the shared memory type is supported.
+ * @see SensorDirectChannel#TYPE_ASHMEM
+ * @see SensorDirectChannel#TYPE_HARDWARE_BUFFER
+ */
+ public boolean isDirectChannelTypeSupported(@SensorDirectChannel.MemoryType int sharedMemType) {
+ switch (sharedMemType) {
+ case SensorDirectChannel.TYPE_ASHMEM:
+ return (mFlags & (1 << DIRECT_CHANNEL_SHIFT)) > 0;
+ case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
+ return (mFlags & (1 << DIRECT_CHANNEL_SHIFT + 1)) > 0;
+ default:
+ return false;
+ }
+ }
+
static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
// RotationVector length has changed to 3 to 5 for API level 18
// Set it to 3 for backward compatibility.
diff --git a/core/java/android/hardware/SensorDirectChannel.java b/core/java/android/hardware/SensorDirectChannel.java
new file mode 100644
index 000000000000..0efd62b463f8
--- /dev/null
+++ b/core/java/android/hardware/SensorDirectChannel.java
@@ -0,0 +1,168 @@
+/*
+ * 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.hardware;
+
+import android.annotation.IntDef;
+import android.os.MemoryFile;
+
+import dalvik.system.CloseGuard;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class representing a sensor direct channel. Use {@link
+ * SensorManager#createDirectChannel(android.os.MemoryFile)} to obtain object.
+ */
+public final class SensorDirectChannel implements AutoCloseable {
+
+ // shared memory types
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {TYPE_ASHMEM, TYPE_HARDWARE_BUFFER})
+ public @interface MemoryType {};
+ /**
+ * Shared memory type ashmem, wrapped in MemoryFile object.
+ *
+ * @see SensorManager#createDirectChannel(MemoryFile)
+ */
+ public static final int TYPE_ASHMEM = 1;
+
+ /**
+ * Shared memory type wrapped by HardwareBuffer object.
+ *
+ * @see SensorManager#createDirectChannel(HardwareBuffer)
+ */
+ public static final int TYPE_HARDWARE_BUFFER = 2;
+
+ // sensor rate levels
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {RATE_STOP, RATE_NORMAL, RATE_FAST, RATE_VERY_FAST})
+ public @interface RateLevel {};
+
+ /**
+ * Sensor stopped (no event output).
+ *
+ * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public static final int RATE_STOP = 0;
+ /**
+ * Sensor operates at nominal rate of 50Hz.
+ *
+ * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 27.5Hz to
+ * 110Hz.
+ *
+ * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public static final int RATE_NORMAL = 1; //50Hz
+ /**
+ * Sensor operates at nominal rate of 200Hz.
+ *
+ * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 110Hz to
+ * 440Hz.
+ *
+ * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public static final int RATE_FAST = 2; // ~200Hz
+ /**
+ * Sensor operates at nominal rate of 800Hz.
+ *
+ * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 440Hz to
+ * 1760Hz.
+ *
+ * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public static final int RATE_VERY_FAST = 3; // ~800Hz
+
+ /**
+ * Determine if a channel is still valid. A channel is invalidated after {@link #close()} is
+ * called.
+ *
+ * @return <code>true</code> if channel is valid.
+ */
+ public boolean isValid() {
+ return !mClosed.get();
+ }
+
+ /**
+ * Close sensor direct channel.
+ *
+ * Stop all active sensor in the channel and free sensor system resource related to channel.
+ * Shared memory used for creating the direct channel need to be closed or freed separately.
+ *
+ * @see SensorManager#createDirectChannel(MemoryFile)
+ * @see SensorManager#createDirectChannel(HardwareBuffer)
+ */
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ // actual close action
+ mManager.destroyDirectChannel(this);
+ }
+ }
+
+ /** @hide */
+ SensorDirectChannel(SensorManager manager, int id, int type, long size) {
+ mManager = manager;
+ mNativeHandle = id;
+ mType = type;
+ mSize = size;
+ mCloseGuard.open("SensorDirectChannel");
+ }
+
+ /** @hide */
+ int getNativeHandle() {
+ return mNativeHandle;
+ }
+
+ /**
+ * This function encode handle information in {@link android.os.Memory} into a long array to be
+ * passed down to native methods.
+ *
+ * @hide */
+ static long[] encodeData(MemoryFile ashmem) {
+ int fd;
+ try {
+ fd = ashmem.getFileDescriptor().getInt$();
+ } catch (IOException e) {
+ fd = -1;
+ }
+ return new long[] { 1 /*numFds*/, 0 /*numInts*/, fd };
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final SensorManager mManager;
+ private final int mNativeHandle;
+ private final long mSize;
+ private final int mType;
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 3ccac692be91..cfda2f4fa8b4 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -19,6 +19,7 @@ package android.hardware;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.Handler;
+import android.os.MemoryFile;
import android.util.Log;
import android.util.SparseArray;
@@ -881,6 +882,104 @@ public abstract class SensorManager {
/**
+ * Create a sensor direct channel backed by shared memory wrapped by MemoryFile object.
+ *
+ * Use the returned {@link android.hardware.SensorDirectChannel} object to configure direct
+ * report of sensor events. After use, call {@link android.hardware.SensorDirectChannel#close()}
+ * to free up resource in sensor system associated with the direct channel.
+ *
+ * @param mem A {@link android.os.MemoryFile} shared memory object.
+ * @return A {@link android.hardware.SensorDirectChannel} object if successful, null otherwise.
+ * @throws IllegalArgumentException when mem is null.
+ * @see SensorDirectChannel#close()
+ * @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public SensorDirectChannel createDirectChannel(MemoryFile mem) {
+ return createDirectChannelImpl(mem.length(), mem, null);
+ }
+
+ /**
+ * Create a sensor direct channel backed by shared memory wrapped by HardwareBuffer object.
+ *
+ * Use the returned {@link android.hardware.SensorDirectChannel} object to configure direct
+ * report of sensor events. After use, call {@link android.hardware.SensorDirectChannel#close()}
+ * to free up resource in sensor system associated with the direct channel.
+ *
+ * @param mem A {@link android.hardware.HardwareBuffer} shared memory object.
+ * @return A {@link android.hardware.SensorDirectChannel} object if successful,
+ * null otherwise.
+ * @throws IllegalArgumentException when mem is null.
+ * @see SensorDirectChannel#close()
+ * @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
+ */
+ public SensorDirectChannel createDirectChannel(HardwareBuffer mem) {
+ return null;
+ }
+
+ /** @hide */
+ protected abstract SensorDirectChannel createDirectChannelImpl(long size,
+ MemoryFile ashmemFile, HardwareBuffer hardwareBuffer);
+
+ /** @hide */
+ void destroyDirectChannel(SensorDirectChannel channel) {
+ destroyDirectChannelImpl(channel);
+ }
+
+ /** @hide */
+ protected abstract void destroyDirectChannelImpl(SensorDirectChannel channel);
+
+ /**
+ * Configure sensor rate or stop sensor report on a direct report channel specified.
+ *
+ * To start event report of a sensor, or change rate of existing report, call this function with
+ * rateLevel other than {@link android.hardware.SensorDirectChannel#RATE_STOP}. Sensor events
+ * will be added into a queue formed by the shared memory used in creation of direction channel.
+ * Each element of the queue has size of 104 bytes and represents a sensor event. Data
+ * structure of an element (all fields in little-endian):
+ *
+ * offset type name
+ *- ---------------------------------------------
+ * 0x0000 int32_t size (always 104)
+ * 0x0004 int32_t sensor report token
+ * 0x0008 int32_t type (see SensorType)
+ * 0x000C uint32_t atomic counter
+ * 0x0010 int64_t timestamp (see Event)
+ * 0x0018 float[16]/int64_t[8] data (data type depends on sensor type)
+ * 0x0058 int32_t[4] reserved (set to zero)
+ *
+ * There is no head or tail pointers. The sequence and frontier of new sensor events is
+ * determined by the atomic counter, which counts from 1 after creation of direct channel and
+ * increments 1 for each new event. The writer in sensor system will wrap around from to
+ * start of shared memory region when it reaches the end. If size of memory region is not
+ * a multiple of size of element (104 bytes), the residual is not used at the end.
+ * Function returns a positive sensor report token on success. This token can be used for
+ * differentiate sensor events from multiple sensor of the same type. For example, if there are
+ * two accelerometer in the system A and B, it is guaranteed different report tokens will be
+ * returned when starting sensor A and B.
+ *
+ * To stop a sensor, call this function with rateLevel equal {@link
+ * android.hardware.SensorDirectChannel#RATE_STOP}. If the sensor parameter is left to be null,
+ * this will stop all active sensor report associated with the direct channel specified.
+ * Function return 1 on success or 0 on failure.
+ *
+ * @param channel A {@link android.hardware.SensorDirectChannel} object representing direct
+ * channel to be configured.
+ * @param sensor A {@link android.hardware.Sensor} object to denote sensor to be operated.
+ * @param rateLevel rate level defined in {@link android.hardware.SensorDirectChannel}.
+ * @return starting report or changing rate: positive sensor report token on success, 0 on failure;
+ * stopping report: 1 on success, 0 on failure.
+ * @throws IllegalArgumentException when SensorDirectChannel is null.
+ */
+ public int configureDirectChannel(SensorDirectChannel channel, Sensor sensor,
+ @SensorDirectChannel.RateLevel int rateLevel) {
+ return configureDirectChannelImpl(channel, sensor, rateLevel);
+ }
+
+ /** @hide */
+ protected abstract int configureDirectChannelImpl(
+ SensorDirectChannel channel, Sensor s, int rate);
+
+ /**
* Used for receiving notifications from the SensorManager when dynamic sensors are connected or
* disconnected.
*/
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 259ca032918b..4992def7de15 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
+import android.os.MemoryFile;
import android.os.MessageQueue;
import android.util.Log;
import android.util.SparseArray;
@@ -57,6 +58,13 @@ public class SystemSensorManager extends SensorManager {
private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
+ private static native int nativeCreateDirectChannel(
+ long nativeInstance, long size, int channelType, long [] channelData);
+ private static native void nativeDestroyDirectChannel(
+ long nativeInstance, int channelHandle);
+ private static native int nativeConfigDirectChannel(
+ long nativeInstance, int channelHandle, int sensorHandle, int rate);
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static boolean sNativeClassInited = false;
@@ -484,6 +492,71 @@ public class SystemSensorManager extends SensorManager {
return changed;
}
+ /** @hide */
+ protected int configureDirectChannelImpl(
+ SensorDirectChannel channel, Sensor sensor, int rate) {
+ if (channel == null) throw new IllegalArgumentException("channel cannot be null");
+
+ if (!channel.isValid()) {
+ throw new IllegalStateException("channel is invalid");
+ }
+
+ if (rate < SensorDirectChannel.RATE_STOP
+ || rate > SensorDirectChannel.RATE_VERY_FAST) {
+ throw new IllegalArgumentException("rate parameter invalid");
+ }
+
+ if (sensor == null && rate != SensorDirectChannel.RATE_STOP) {
+ // the stop all sensors case
+ throw new IllegalArgumentException(
+ "when sensor is null, rate can only be DIRECT_RATE_STOP");
+ }
+
+ int sensorHandle = (sensor == null) ? -1 : sensor.getHandle();
+
+ int ret = nativeConfigDirectChannel(
+ mNativeInstance, channel.getNativeHandle(), sensorHandle, rate);
+
+ if (rate == SensorDirectChannel.RATE_STOP) {
+ return (ret == 0) ? 1 : 0;
+ } else {
+ return (ret > 0) ? ret : 0;
+ }
+ }
+
+ /** @hide */
+ protected SensorDirectChannel createDirectChannelImpl(long size,
+ MemoryFile ashmemFile, HardwareBuffer grallocMemObject) {
+ SensorDirectChannel ch = null;
+
+ if (size <= 0) throw new IllegalArgumentException("size has to be greater than 0");
+
+ if (ashmemFile != null) {
+ if (size != ashmemFile.length()) {
+ throw new IllegalArgumentException("size has to match MemoryFile.length()");
+ }
+ int id = nativeCreateDirectChannel(
+ mNativeInstance, size, SensorDirectChannel.TYPE_ASHMEM,
+ SensorDirectChannel.encodeData(ashmemFile));
+ if (id > 0) {
+ ch = new SensorDirectChannel(this, id, SensorDirectChannel.TYPE_ASHMEM, size);
+ }
+ } else if (grallocMemObject != null) {
+ Log.wtf(TAG, "Implement GRALLOC or remove GRALLOC support entirely");
+ } else {
+ throw new IllegalArgumentException("Invalid parameter");
+ }
+
+ return ch;
+ }
+
+ /** @hide */
+ protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
+ if (channel != null) {
+ nativeDestroyDirectChannel(mNativeInstance, channel.getNativeHandle());
+ }
+ }
+
/*
* BaseEventQueue is the communication channel with the sensor service,
* SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 62b7f32c43c0..bcebb7dc594d 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -221,8 +221,8 @@ public abstract class CameraCaptureSession implements AutoCloseable {
public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
/**
- * <p>Finish the deferred output configurations where the output Surface was not configured
- * before.</p>
+ * <p>Finalize the output configurations that now have their deferred and/or extra Surfaces
+ * included.</p>
*
* <p>For camera use cases where a preview and other output configurations need to be
* configured, it can take some time for the preview Surface to be ready. For example, if the
@@ -235,22 +235,31 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* and defer the preview output configuration until the Surface is ready. After the
* {@link CameraCaptureSession} is created successfully with this deferred output and other
* normal outputs, the application can start submitting requests as long as they do not include
- * deferred output Surfaces. Once a deferred Surface is ready, the application can set the
- * Surface on the deferred output configuration with the
- * {@link OutputConfiguration#setDeferredSurface} method, and then finish the deferred output
+ * deferred output Surfaces. Once a deferred Surface is ready, the application can add the
+ * Surface to the deferred output configuration with the
+ * {@link OutputConfiguration#addSurface} method, and then update the deferred output
* configuration via this method, before it can submit capture requests with this output
* target.</p>
*
- * <p>The output Surfaces included by this list of deferred
+ * <p>This function can also be called in case where multiple surfaces share the same
+ * OutputConfiguration, and one of the surfaces becomes available after the {@link
+ * CameraCaptureSession} is created. In that case, the application must first create the
+ * OutputConfiguration with the available Surface, then enable furture surface sharing via
+ * {@link OutputConfiguration#enableSurfaceSharing}, before creating the CameraCaptureSession.
+ * After the CameraCaptureSession is created, and once the extra Surface becomes available, the
+ * application must then call {@link OutputConfiguration#addSurface} before finalizing the
+ * configuration with this method.</p>
+ *
+ * <p>The output Surfaces included by this list of
* {@link OutputConfiguration OutputConfigurations} can be used as {@link CaptureRequest}
* targets as soon as this call returns.</p>
*
* <p>This method is not supported by
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}-level devices.</p>
*
- * @param deferredOutputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
- * have had {@link OutputConfiguration#setDeferredSurface setDeferredSurface} invoked
- * with a valid output Surface.
+ * @param outputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
+ * have had {@link OutputConfiguration#addSurface addSurface} invoked with a valid
+ * output Surface after {@link CameraDevice#createCaptureSessionByOutputConfigurations}.
* @throws CameraAccessException if the camera device is no longer connected or has encountered
* a fatal error.
* @throws IllegalStateException if this session is no longer active, either because the session
@@ -261,8 +270,8 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* source. Or if one of the output configuration was already finished with an
* included surface in a prior call.
*/
- public abstract void finishDeferredConfiguration(
- List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException;
+ public abstract void finalizeOutputConfigurations(
+ List<OutputConfiguration> outputConfigs) throws CameraAccessException;
/**
* <p>Submit a request for an image to be captured by the camera device.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 98a89048ae12..12b46c1bf693 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1625,6 +1625,34 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
new Key<Integer>("android.control.postRawSensitivityBoost", int.class);
/**
+ * <p>Allow camera device to enable zero-shutter-lag mode for requests with
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} == STILL_CAPTURE.</p>
+ * <p>If enableZsl is <code>true</code>, the camera device may enable zero-shutter-lag mode for requests with
+ * STILL_CAPTURE capture intent. The camera device may use images captured in the past to
+ * produce output images for a zero-shutter-lag request. The result metadata including the
+ * {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} reflects the source frames used to produce output images.
+ * Therefore, the contents of the output images and the result metadata may be out of order
+ * compared to previous regular requests. enableZsl does not affect requests with other
+ * capture intents.</p>
+ * <p>For example, when requests are submitted in the following order:
+ * Request A: enableZsl is ON, {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} is PREVIEW
+ * Request B: enableZsl is ON, {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} is STILL_CAPTURE</p>
+ * <p>The output images for request B may have contents captured before the output images for
+ * request A, and the result metadata for request B may be older than the result metadata for
+ * request A.</p>
+ * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
+ * past for requests with STILL_CAPTURE capture intent.</p>
+ * <p>The value of enableZsl in capture templates is always <code>false</code> if present.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+ * @see CaptureResult#SENSOR_TIMESTAMP
+ */
+ @PublicKey
+ public static final Key<Boolean> CONTROL_ENABLE_ZSL =
+ new Key<Boolean>("android.control.enableZsl", boolean.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 23f4b9e6ce06..3f8b57a3498f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2132,6 +2132,34 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.control.postRawSensitivityBoost", int.class);
/**
+ * <p>Allow camera device to enable zero-shutter-lag mode for requests with
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} == STILL_CAPTURE.</p>
+ * <p>If enableZsl is <code>true</code>, the camera device may enable zero-shutter-lag mode for requests with
+ * STILL_CAPTURE capture intent. The camera device may use images captured in the past to
+ * produce output images for a zero-shutter-lag request. The result metadata including the
+ * {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} reflects the source frames used to produce output images.
+ * Therefore, the contents of the output images and the result metadata may be out of order
+ * compared to previous regular requests. enableZsl does not affect requests with other
+ * capture intents.</p>
+ * <p>For example, when requests are submitted in the following order:
+ * Request A: enableZsl is ON, {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} is PREVIEW
+ * Request B: enableZsl is ON, {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} is STILL_CAPTURE</p>
+ * <p>The output images for request B may have contents captured before the output images for
+ * request A, and the result metadata for request B may be older than the result metadata for
+ * request A.</p>
+ * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
+ * past for requests with STILL_CAPTURE capture intent.</p>
+ * <p>The value of enableZsl in capture templates is always <code>false</code> if present.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
+ * @see CaptureResult#SENSOR_TIMESTAMP
+ */
+ @PublicKey
+ public static final Key<Boolean> CONTROL_ENABLE_ZSL =
+ new Key<Boolean>("android.control.enableZsl", boolean.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 4befb29ae075..891df6362d29 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -151,9 +151,9 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
}
@Override
- public void finishDeferredConfiguration(
- List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException {
- mDeviceImpl.finishDeferredConfig(deferredOutputConfigs);
+ public void finalizeOutputConfigurations(
+ List<OutputConfiguration> outputConfigs) throws CameraAccessException {
+ mDeviceImpl.finalizeOutputConfigs(outputConfigs);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 01e58f450a4d..15dbf2620608 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -258,9 +258,9 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
}
@Override
- public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs)
+ public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs)
throws CameraAccessException {
- mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
+ mSessionImpl.finalizeOutputConfigurations(deferredOutputConfigs);
}
private class WrapperCallback extends StateCallback {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d2aeaea2b37d..2364ebe0f891 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -743,14 +743,14 @@ public class CameraDeviceImpl extends CameraDevice
}
}
- public void finishDeferredConfig(List<OutputConfiguration> deferredConfigs)
+ public void finalizeOutputConfigs(List<OutputConfiguration> outputConfigs)
throws CameraAccessException {
- if (deferredConfigs == null || deferredConfigs.size() == 0) {
+ if (outputConfigs == null || outputConfigs.size() == 0) {
throw new IllegalArgumentException("deferred config is null or empty");
}
synchronized(mInterfaceLock) {
- for (OutputConfiguration config : deferredConfigs) {
+ for (OutputConfiguration config : outputConfigs) {
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
// Have to use equal here, as createCaptureSessionByOutputConfigurations() and
@@ -765,11 +765,11 @@ public class CameraDeviceImpl extends CameraDevice
+ "session");
}
- if (config.getSurface() == null) {
- throw new IllegalArgumentException("The deferred config for stream " + streamId
- + " must have a non-null surface");
+ if (config.getSurfaces().size() == 0) {
+ throw new IllegalArgumentException("The final config for stream " + streamId
+ + " must have at least 1 surface");
}
- mRemoteDevice.setDeferredConfiguration(streamId, config);
+ mRemoteDevice.finalizeOutputConfigurations(streamId, config);
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 79eac262050b..0e450d76ea62 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -800,7 +800,8 @@ public class CameraMetadataNative implements Parcelable {
Location l = new Location(translateProcessToLocationProvider(processingMethod));
if (timeStamp != null) {
- l.setTime(timeStamp);
+ // Location expects timestamp in [ms.]
+ l.setTime(timeStamp * 1000);
} else {
Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
}
@@ -823,7 +824,8 @@ public class CameraMetadataNative implements Parcelable {
double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
String processMethod = translateLocationProviderToProcess(l.getProvider());
- long timestamp = l.getTime();
+ //JPEG_GPS_TIMESTAMP expects sec. instead of msec.
+ long timestamp = l.getTime() / 1000;
set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index d77f60bf0953..d9f666e54330 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -215,10 +215,10 @@ public class ICameraDeviceUserWrapper {
}
}
- public void setDeferredConfiguration(int streamId, OutputConfiguration deferredConfig)
+ public void finalizeOutputConfigurations(int streamId, OutputConfiguration deferredConfig)
throws CameraAccessException {
try {
- mRemoteDevice.setDeferredConfiguration(streamId, deferredConfig);
+ mRemoteDevice.finalizeOutputConfigurations(streamId, deferredConfig);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 2a9bf6bace95..d8ec4df504bb 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -578,8 +578,8 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
- public void setDeferredConfiguration(int steamId, OutputConfiguration config) {
- String err = "Set deferred configuration is not supported on legacy devices";
+ public void finalizeOutputConfigurations(int steamId, OutputConfiguration config) {
+ String err = "Finalizing output configuration is not supported on legacy devices";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 4654fc2b2524..d9512944d7ca 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -34,6 +34,7 @@ import android.view.Surface;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;
+import java.util.ArrayList;
import static com.android.internal.util.Preconditions.*;
@@ -116,6 +117,15 @@ public final class OutputConfiguration implements Parcelable {
private final int SURFACE_TYPE_SURFACE_TEXTURE = 1;
/**
+ * Maximum number of surfaces supported by one {@link OutputConfiguration}.
+ *
+ * <p>The combined number of surfaces added by the constructor and
+ * {@link OutputConfiguration#addSurface} should not exceed this value.</p>
+ *
+ */
+ private static final int MAX_SURFACES_COUNT = 2;
+
+ /**
* Create a new {@link OutputConfiguration} instance with a {@link Surface},
* with a surface group ID.
*
@@ -151,50 +161,6 @@ public final class OutputConfiguration implements Parcelable {
}
/**
- * Create a new {@link OutputConfiguration} instance with two surfaces sharing the same stream,
- * with a surface group ID.
- *
- * <p>For advanced use cases, a camera application may require more streams than the combination
- * guaranteed by {@link CameraDevice#createCaptureSession}. In this case, two compatible
- * surfaces can be attached to one OutputConfiguration so that they map to one camera stream,
- * and buffers are reference counted when being consumed by both surfaces. </p>
- *
- * <p>Two surfaces are compatible in below 2 cases:</p>
- *
- * <ol>
- * <li> Surfaces with the same size, format, dataSpace, and Surface source class. In this case,
- * {@link CameraDevice#createCaptureSessionByOutputConfigurations} is guaranteed to succeed.
- *
- * <li> Surfaces with the same size, format, and dataSpace, but different Surface
- * source classes. However, on some devices, the underlying camera device is able to use the
- * same buffer layout for both surfaces. The only way to discover if this is the case is to
- * create a capture session with that output configuration. For example, if the camera device
- * uses the same private buffer format between a SurfaceView/SurfaceTexture and a
- * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
- * will succeed. Otherwise, it throws {@code IllegalArgumentException}.
- * </ol>
- *
- * @param surfaceGroupId
- * A group ID for this output, used for sharing memory between multiple outputs.
- * @param surface
- * A Surface for camera to output to.
- * @param surface2
- * Second surface for camera to output to.
- * @throws IllegalArgumentException if the two surfaces have different size, format, or
- * dataSpace.
- *
- * @hide
- */
- public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface,
- @NonNull Surface surface2) {
- this(surfaceGroupId, surface, ROTATION_0, surface2);
-
- checkNotNull(surface2, "Surface must not be null");
- checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
- mConfiguredGenerationId, surface2);
- }
-
- /**
* Create a new {@link OutputConfiguration} instance.
*
* <p>This constructor takes an argument for desired camera rotation</p>
@@ -240,68 +206,19 @@ public final class OutputConfiguration implements Parcelable {
*/
@SystemApi
public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
- this(surfaceGroupId, surface, rotation, null /*surface2*/);
- }
-
- /**
- * Create a new {@link OutputConfiguration} instance, with rotation, a group ID, and a secondary
- * surface.
- *
- * <p>This constructor takes an argument for desired camera rotation, the surface group
- * ID, and a secondary surface. See {@link #OutputConfiguration(int, Surface)} for details
- * of the group ID.</p>
- *
- * <p>surface2 should be compatible with surface. See {@link #OutputConfiguration(int, Surface,
- * Surface} for details of compatibility between surfaces.</p>
- *
- * <p>Since the rotation is done by the CameraDevice, both surfaces will receive buffers with
- * the same rotation applied. This means that if the application needs two compatible surfaces
- * to have different rotations, these surfaces cannot be shared within one OutputConfiguration.
- * </p>
- *
- * @param surfaceGroupId
- * A group ID for this output, used for sharing memory between multiple outputs.
- * @param surface
- * A Surface for camera to output to.
- * @param rotation
- * The desired rotation to be applied on camera output. Value must be one of
- * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
- * application should make sure corresponding surface size has width and height
- * transposed relative to the width and height without rotation. For example,
- * if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
- * application should set rotation to {@code ROTATION_90} and make sure the
- * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
- * throw {@code IllegalArgumentException} if device cannot perform such rotation.
- * @param surface2
- * Second surface for camera to output to.
-
- * @throws IllegalArgumentException if the two surfaces are not compatible to be shared in
- * one OutputConfiguration.
- *
- * @hide
- */
- private OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation,
- @Nullable Surface surface2) {
checkNotNull(surface, "Surface must not be null");
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
-
mSurfaceGroupId = surfaceGroupId;
mSurfaceType = SURFACE_TYPE_UNKNOWN;
+ mSurfaces = new ArrayList<Surface>();
+ mSurfaces.add(surface);
mRotation = rotation;
mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
mConfiguredGenerationId = surface.getGenerationId();
mIsDeferredConfig = false;
-
- if (surface2 == null) {
- mSurfaces = new Surface[1];
- mSurfaces[0] = surface;
- } else {
- mSurfaces = new Surface[MAX_SURFACES_COUNT];
- mSurfaces[0] = surface;
- mSurfaces[1] = surface2;
- }
+ mIsShared = false;
}
/**
@@ -309,16 +226,16 @@ public final class OutputConfiguration implements Parcelable {
* source class.
* <p>
* This constructor takes an argument for desired Surface size and the Surface source class
- * without providing the actual output Surface. This is used to setup a output configuration
+ * without providing the actual output Surface. This is used to setup an output configuration
* with a deferred Surface. The application can use this output configuration to create a
* session.
* </p>
* <p>
- * However, the actual output Surface must be set via {@link #setDeferredSurface} and finish the
- * deferred Surface configuration via {@link CameraCaptureSession#finishDeferredConfiguration}
- * before submitting a request with this Surface target. The deferred Surface can only be
- * obtained from either from {@link android.view.SurfaceView} by calling
- * {@link android.view.SurfaceHolder#getSurface}, or from
+ * However, the actual output Surface must be set via {@link #addSurface} and the deferred
+ * Surface configuration must be finalized via {@link
+ * CameraCaptureSession#finalizeOutputConfigurations} before submitting a request with this
+ * Surface target. The deferred Surface can only be obtained either from {@link
+ * android.view.SurfaceView} by calling {@link android.view.SurfaceHolder#getSurface}, or from
* {@link android.graphics.SurfaceTexture} via
* {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).
* </p>
@@ -327,43 +244,73 @@ public final class OutputConfiguration implements Parcelable {
* @param klass a non-{@code null} {@link Class} object reference that indicates the source of
* this surface. Only {@link android.view.SurfaceHolder SurfaceHolder.class} and
* {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
+ * @throws IllegalArgumentException if the Surface source class is not supported, or Surface
+ * size is zero.
*/
public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass) {
- this(surfaceSize, klass, true /* dummy */);
+ checkNotNull(klass, "surfaceSize must not be null");
+ checkNotNull(klass, "klass must not be null");
+ if (klass == android.view.SurfaceHolder.class) {
+ mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
+ } else if (klass == android.graphics.SurfaceTexture.class) {
+ mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
+ } else {
+ mSurfaceType = SURFACE_TYPE_UNKNOWN;
+ throw new IllegalArgumentException("Unknow surface source class type");
+ }
- mSurfaces = new Surface[1];
+ mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
+ mSurfaces = new ArrayList<Surface>();
+ mRotation = ROTATION_0;
+ mConfiguredSize = surfaceSize;
+ mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+ mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+ mConfiguredGenerationId = 0;
+ mIsDeferredConfig = true;
+ mIsShared = false;
}
/**
- * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
- * source class for the deferred surface, and a secondary surface.
+ * Enable multiple surfaces sharing the same OutputConfiguration
*
- * <p>This constructor takes an argument for desired surface size and surface source class of
- * the deferred surface, and a secondary surface. See {@link #OutputConfiguration(Size, Class)}
- * for details of the surface size and surface source class.</p>
+ * <p>For advanced use cases, a camera application may require more streams than the combination
+ * guaranteed by {@link CameraDevice#createCaptureSession}. In this case, more than one
+ * compatible surface can be attached to an OutputConfiguration so that they map to one
+ * camera stream, and the outputs share memory buffers when possible. </p>
*
- * <p> The deferred surface and secondary surface should be compatible. See
- * {@link #OutputConfiguration(int, Surface, Surface)} for details of compatible surfaces.
+ * <p>Two surfaces are compatible in the below cases:</p>
*
- * @hide
+ * <li> Surfaces with the same size, format, dataSpace, and Surface source class. In this case,
+ * {@link CameraDevice#createCaptureSessionByOutputConfigurations} is guaranteed to succeed.
+ *
+ * <li> Surfaces with the same size, format, and dataSpace, but different Surface source classes
+ * that are generally not compatible. However, on some devices, the underlying camera device is
+ * able to use the same buffer layout for both surfaces. The only way to discover if this is the
+ * case is to create a capture session with that output configuration. For example, if the
+ * camera device uses the same private buffer format between a SurfaceView/SurfaceTexture and a
+ * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
+ * will succeed. Otherwise, it fails with {@link
+ * CameraCaptureSession.StateCallback#onConfigureFailed}.
+ * </ol>
+ *
+ * <p>To enable surface sharing, this function must be called before {@link
+ * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after {@link
+ * CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
+ *
+ * <p>Up to 2 surfaces can be shared for an OutputConfiguration. The supported surfaces for
+ * sharing must be of type SurfaceTexture, SurfaceView, MediaRecorder, MediaCodec, or
+ * implementation defined ImageReader.</p>
*/
- public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
- @NonNull Surface surface2) {
- this(surfaceSize, klass, true /* dummy */);
-
- checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
- mConfiguredGenerationId, surface2);
-
- mSurfaces = new Surface[MAX_SURFACES_COUNT];
- mSurfaces[0] = null;
- mSurfaces[1] = surface2;
+ public void enableSurfaceSharing() {
+ mIsShared = true;
}
/**
* Check if this configuration has deferred configuration.
*
- * <p>This will return true if the output configuration was constructed with surface deferred.
- * It will return true even after the deferred surface is set later.</p>
+ * <p>This will return true if the output configuration was constructed with surface deferred by
+ * {@link OutputConfiguration#OutputConfiguration(Size, Class)}. It will return true even after
+ * the deferred surface is added later by {@link OutputConfiguration#addSurface}.</p>
*
* @return true if this configuration has deferred surface.
* @hide
@@ -373,38 +320,63 @@ public final class OutputConfiguration implements Parcelable {
}
/**
- * Set the deferred surface to this OutputConfiguration.
+ * Add a surface to this OutputConfiguration.
*
- * <p>
- * The deferred surface must be obtained from either from {@link android.view.SurfaceView} by
- * calling {@link android.view.SurfaceHolder#getSurface}, or from
- * {@link android.graphics.SurfaceTexture} via
- * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}). After the deferred
- * surface is set, the application must finish the deferred surface configuration via
- * {@link CameraCaptureSession#finishDeferredConfiguration} before submitting a request with
- * this surface target.
+ * <p> This function can be called before or after {@link
+ * CameraDevice#createCaptureSessionByOutputConfigurations}. If it's called after,
+ * the application must finalize the capture session with
+ * {@link CameraCaptureSession#finalizeOutputConfigurations}.
* </p>
*
- * @param surface The deferred surface to be set.
- * @throws IllegalArgumentException if the Surface is invalid.
- * @throws IllegalStateException if a Surface was already set to this deferred
- * OutputConfiguration.
+ * <p> If the OutputConfiguration was constructed with a deferred surface by {@link
+ * OutputConfiguration#OutputConfiguration(Size, Class)}, the added surface must be obtained
+ * from {@link android.view.SurfaceView} by calling {@link android.view.SurfaceHolder#getSurface},
+ * or from {@link android.graphics.SurfaceTexture} via
+ * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).</p>
+ *
+ * <p> If the OutputConfiguration was constructed by other constructors, the added
+ * surface must be compatible with the existing surface. See {@link #enableSurfaceSharing} for
+ * details of compatible surfaces.</p>
+ *
+ * <p> If the OutputConfiguration already contains a Surface, {@link #enableSurfaceSharing} must
+ * be called before calling this function to add a new Surface.</p>
+ *
+ * @param surface The surface to be added.
+ * @throws IllegalArgumentException if the Surface is invalid, the Surface's
+ * dataspace/format doesn't match, or adding the Surface would exceed number of
+ * shared surfaces supported.
+ * @throws IllegalStateException if the Surface was already added to this OutputConfiguration,
+ * or if the OutputConfiguration is not shared and it already has a surface associated
+ * with it.
*/
- public void setDeferredSurface(@NonNull Surface surface) {
+ public void addSurface(@NonNull Surface surface) {
checkNotNull(surface, "Surface must not be null");
- if (mSurfaces[0] != null) {
- throw new IllegalStateException("Deferred surface is already set!");
+ if (mSurfaces.contains(surface)) {
+ throw new IllegalStateException("Surface is already added!");
+ }
+ if (mSurfaces.size() == 1 && !mIsShared) {
+ throw new IllegalStateException("Cannot have 2 surfaces for a non-sharing configuration");
+ }
+ if (mSurfaces.size() + 1 > MAX_SURFACES_COUNT) {
+ throw new IllegalArgumentException("Exceeds maximum number of surfaces");
}
// This will throw IAE is the surface was abandoned.
Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
if (!surfaceSize.equals(mConfiguredSize)) {
- Log.w(TAG, "Deferred surface size " + surfaceSize +
- " is different with pre-configured size " + mConfiguredSize +
+ Log.w(TAG, "Added surface size " + surfaceSize +
+ " is different than pre-configured size " + mConfiguredSize +
", the pre-configured size will be used.");
}
- mSurfaces[0] = surface;
+ if (mConfiguredDataspace != SurfaceUtils.getSurfaceDataspace(surface)) {
+ throw new IllegalArgumentException("The dataspace of added surface doesn't match");
+ }
+ if (mConfiguredFormat != SurfaceUtils.getSurfaceFormat(surface)) {
+ throw new IllegalArgumentException("The format of added surface format doesn't match");
+ }
+
+ mSurfaces.add(surface);
}
/**
@@ -432,49 +404,6 @@ public final class OutputConfiguration implements Parcelable {
}
/**
- * Private constructor to initialize Configuration based on surface size and class
- */
- private <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
- boolean dummy) {
- checkNotNull(surfaceSize, "surfaceSize must not be null");
- checkNotNull(klass, "klass must not be null");
- if (klass == android.view.SurfaceHolder.class) {
- mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
- } else if (klass == android.graphics.SurfaceTexture.class) {
- mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
- } else {
- mSurfaceType = SURFACE_TYPE_UNKNOWN;
- throw new IllegalArgumentException("Unknow surface source class type");
- }
-
- mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
- mRotation = ROTATION_0;
- mConfiguredSize = surfaceSize;
- mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
- mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
- mConfiguredGenerationId = 0;
- mIsDeferredConfig = true;
- }
-
- /**
- * Check if the surface properties match that of the given surface.
- *
- * @return true if the properties and the surface match.
- */
- private void checkMatchingSurfaces(Size size, int format, int dataSpace, int generationId,
- @NonNull Surface surface) {
- if (!size.equals(SurfaceUtils.getSurfaceSize(surface))) {
- throw new IllegalArgumentException("Secondary surface size doesn't match");
- }
- if (dataSpace != SurfaceUtils.getSurfaceDataspace(surface)) {
- throw new IllegalArgumentException("Secondary surface dataspace doesn't match");
- }
- if (format != SurfaceUtils.getSurfaceFormat(surface)) {
- throw new IllegalArgumentException("Secondary surface format doesn't match");
- }
- }
-
- /**
* Create an OutputConfiguration from Parcel.
*/
private OutputConfiguration(@NonNull Parcel source) {
@@ -483,27 +412,9 @@ public final class OutputConfiguration implements Parcelable {
int surfaceType = source.readInt();
int width = source.readInt();
int height = source.readInt();
- int surfaceCnt = source.readInt();
-
- if (surfaceCnt <= 0) {
- throw new IllegalArgumentException(
- "Surface count in OutputConfiguration must be greater than 0");
- }
- if (surfaceCnt > MAX_SURFACES_COUNT) {
- throw new IllegalArgumentException(
- "Surface count in OutputConfiguration must not be more than "
- + MAX_SURFACES_COUNT);
- }
-
- Surface[] surfaces = new Surface[surfaceCnt];
- for (int i = 0; i < surfaceCnt; i++) {
- Surface surface = Surface.CREATOR.createFromParcel(source);
- surfaces[i] = surface;
-
- if (surface == null && i > 0) {
- throw new IllegalArgumentException("Only the first surface can be deferred");
- }
- }
+ boolean isDeferred = source.readInt() == 1;
+ ArrayList<Surface> surfaces = new ArrayList<Surface>();
+ source.readTypedList(surfaces, Surface.CREATOR);
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
@@ -511,13 +422,13 @@ public final class OutputConfiguration implements Parcelable {
mRotation = rotation;
mSurfaces = surfaces;
mConfiguredSize = new Size(width, height);
- // First surface could be null (being deferred). Use last surface to look up surface
- // characteristics.
- if (mSurfaces[surfaceCnt-1] != null) {
+ mIsDeferredConfig = isDeferred;
+ mSurfaces = surfaces;
+ if (mSurfaces.size() > 0) {
mSurfaceType = SURFACE_TYPE_UNKNOWN;
- mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurfaces[surfaceCnt-1]);
- mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurfaces[surfaceCnt-1]);
- mConfiguredGenerationId = mSurfaces[surfaceCnt-1].getGenerationId();
+ mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurfaces.get(0));
+ mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurfaces.get(0));
+ mConfiguredGenerationId = mSurfaces.get(0).getGenerationId();
} else {
mSurfaceType = surfaceType;
mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
@@ -525,38 +436,31 @@ public final class OutputConfiguration implements Parcelable {
StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
mConfiguredGenerationId = 0;
}
-
- if (mSurfaces[0] == null) {
- mIsDeferredConfig = true;
- } else {
- mIsDeferredConfig = false;
- }
}
/**
* Get the {@link Surface} associated with this {@link OutputConfiguration}.
*
- * @return the {@link Surface} associated with this {@link OutputConfiguration}. If more than
- * one surface is associated with this {@link OutputConfiguration}, return the first one as
- * specified in the constructor. If there is a deferred surface, null will be returned.
+ * If more than one surface is associated with this {@link OutputConfiguration}, return the
+ * first one as specified in the constructor or {@link OutputConfiguration#addSurface}.
*/
public @Nullable Surface getSurface() {
- return mSurfaces[0];
+ if (mSurfaces.size() == 0) {
+ return null;
+ }
+
+ return mSurfaces.get(0);
}
/**
* Get the immutable list of surfaces associated with this {@link OutputConfiguration}.
*
- * @return the list of surfaces associated with this {@link OutputConfiguration} in the order
- * specified in the constructor. If there is a deferred surface in the {@link
- * OutputConfiguration}, it is returned as null as first element of the list. The list should
- * not be modified.
- *
- * @hide
+ * @return the list of surfaces associated with this {@link OutputConfiguration} as specified in
+ * the constructor and {@link OutputConfiguration#addSurface}. The list should not be modified.
*/
@NonNull
public List<Surface> getSurfaces() {
- return Collections.unmodifiableList(Arrays.asList(mSurfaces));
+ return Collections.unmodifiableList(mSurfaces);
}
/**
@@ -616,12 +520,9 @@ public final class OutputConfiguration implements Parcelable {
dest.writeInt(mSurfaceType);
dest.writeInt(mConfiguredSize.getWidth());
dest.writeInt(mConfiguredSize.getHeight());
- dest.writeInt(mSurfaces.length);
- for (int i = 0; i < mSurfaces.length; i++) {
- if (mSurfaces[i] != null) {
- mSurfaces[i].writeToParcel(dest, flags);
- }
- }
+ dest.writeInt(mIsDeferredConfig ? 1 : 0);
+ dest.writeInt(mIsShared ? 1 : 0);
+ dest.writeTypedList(mSurfaces);
}
/**
@@ -647,16 +548,15 @@ public final class OutputConfiguration implements Parcelable {
mSurfaceGroupId != other.mSurfaceGroupId ||
mSurfaceType != other.mSurfaceType ||
mIsDeferredConfig != other.mIsDeferredConfig ||
+ mIsShared != other.mIsShared ||
mConfiguredFormat != other.mConfiguredFormat ||
mConfiguredDataspace != other.mConfiguredDataspace ||
- mSurfaces.length != other.mSurfaces.length ||
mConfiguredGenerationId != other.mConfiguredGenerationId)
return false;
- // If deferred, skip the first surface of mSurfaces when comparing.
- int minIndex = (mIsDeferredConfig ? 1 : 0);
- for (int i = minIndex; i < mSurfaces.length; i++) {
- if (mSurfaces[i] != other.mSurfaces[i])
+ int minLen = Math.min(mSurfaces.size(), other.mSurfaces.size());
+ for (int i = 0; i < minLen; i++) {
+ if (mSurfaces.get(i) != other.mSurfaces.get(i))
return false;
}
@@ -670,23 +570,23 @@ public final class OutputConfiguration implements Parcelable {
*/
@Override
public int hashCode() {
- // Need ensure that the hashcode remains unchanged after set a deferred surface. Otherwise
+ // Need ensure that the hashcode remains unchanged after adding a deferred surface. Otherwise
// the deferred output configuration will be lost in the camera streammap after the deferred
// surface is set.
- int minIndex = (mIsDeferredConfig ? 1 : 0);
- Surface nonDeferredSurfaces[] = Arrays.copyOfRange(mSurfaces,
- minIndex, mSurfaces.length);
- int surfaceHash = HashCodeHelpers.hashCodeGeneric(nonDeferredSurfaces);
+ if (mIsDeferredConfig) {
+ return HashCodeHelpers.hashCode(
+ mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
+ mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0);
+ }
return HashCodeHelpers.hashCode(
- mRotation, surfaceHash, mConfiguredGenerationId,
+ mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
mConfiguredSize.hashCode(), mConfiguredFormat,
- mConfiguredDataspace, mSurfaceGroupId);
+ mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0);
}
private static final String TAG = "OutputConfiguration";
- private static final int MAX_SURFACES_COUNT = 2;
- private Surface mSurfaces[];
+ private ArrayList<Surface> mSurfaces;
private final int mRotation;
private final int mSurfaceGroupId;
// Surface source type, this is only used by the deferred surface configuration objects.
@@ -700,4 +600,6 @@ public final class OutputConfiguration implements Parcelable {
private final int mConfiguredGenerationId;
// Flag indicating if this config has deferred surface.
private final boolean mIsDeferredConfig;
+ // Flag indicating if this config has shared surfaces
+ private boolean mIsShared;
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 12e1963a2e3e..33a9f5eb67f0 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -108,13 +108,14 @@ public final class DisplayManager {
* </p>
*
* <p>
- * A private virtual display belongs to the application that created it.
- * Only the a owner of a private virtual display is allowed to place windows upon it.
- * The private virtual display also does not participate in display mirroring: it will
- * neither receive mirrored content from another display nor allow its own content to
- * be mirrored elsewhere. More precisely, the only processes that are allowed to
- * enumerate or interact with the private display are those that have the same UID as the
- * application that originally created the private virtual display.
+ * A private virtual display belongs to the application that created it. Only the a owner of a
+ * private virtual display and the apps that are already on that display are allowed to place
+ * windows upon it. The private virtual display also does not participate in display mirroring:
+ * it will neither receive mirrored content from another display nor allow its own content to be
+ * mirrored elsewhere. More precisely, the only processes that are allowed to enumerate or
+ * interact with the private display are those that have the same UID as the application that
+ * originally created the private virtual display or as the activities that are already on that
+ * display.
* </p>
*
* @see #createVirtualDisplay
@@ -234,6 +235,21 @@ public final class DisplayManager {
*/
public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
+ /**
+ * Virtual display flag: Allows content to be displayed on private virtual displays when
+ * keyguard is shown but is insecure.
+ *
+ * <p>
+ * This flag can only be applied to private displays as defined by the
+ * {@link Display#FLAG_PRIVATE} display flag. It is mutually exclusive with
+ * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. If both flags are specified then this flag's behavior
+ * will not be applied.
+ * </p>
+ *
+ * @see #createVirtualDisplay
+ */
+ public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 3eb584483911..98a57490d4c6 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -230,9 +230,6 @@ public abstract class DisplayManagerInternal {
public int dozeScreenBrightness;
public int dozeScreenState;
- // If true, use twilight to affect the brightness.
- public boolean useTwilight;
-
public DisplayPowerRequest() {
policy = POLICY_BRIGHT;
useProximitySensor = false;
@@ -268,7 +265,6 @@ public abstract class DisplayManagerInternal {
boostScreenBrightness = other.boostScreenBrightness;
dozeScreenBrightness = other.dozeScreenBrightness;
dozeScreenState = other.dozeScreenState;
- useTwilight = other.useTwilight;
}
@Override
@@ -289,8 +285,7 @@ public abstract class DisplayManagerInternal {
&& lowPowerMode == other.lowPowerMode
&& boostScreenBrightness == other.boostScreenBrightness
&& dozeScreenBrightness == other.dozeScreenBrightness
- && dozeScreenState == other.dozeScreenState
- && useTwilight == other.useTwilight;
+ && dozeScreenState == other.dozeScreenState;
}
@Override
@@ -310,8 +305,7 @@ public abstract class DisplayManagerInternal {
+ ", lowPowerMode=" + lowPowerMode
+ ", boostScreenBrightness=" + boostScreenBrightness
+ ", dozeScreenBrightness=" + dozeScreenBrightness
- + ", dozeScreenState=" + Display.stateToString(dozeScreenState)
- + ", useTwilight=" + useTwilight;
+ + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
}
public static String policyToString(int policy) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 4b5707890518..7947620d3a94 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -766,7 +766,7 @@ public class FingerprintManager {
/**
* Retrieves the authenticator token for binding keys to the lifecycle
- * of the current set of fingerprints. Used only by internal clients.
+ * of the calling user's fingerprints. Used only by internal clients.
*
* @hide
*/
@@ -1074,7 +1074,7 @@ public class FingerprintManager {
@Override // binder call
public void onAuthenticationFailed(long deviceId) {
- mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
+ mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
}
@Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl
new file mode 100644
index 000000000000..5bcf4769b16a
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.fingerprint;
+
+/**
+ * Callback when clients become active or inactive.
+ * @hide
+ */
+oneway interface IFingerprintClientActiveCallback {
+ void onClientActiveChanged(boolean isActive);
+} \ No newline at end of file
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index ae3fc374c9a5..4879d54768fb 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -16,6 +16,7 @@
package android.hardware.fingerprint;
import android.os.Bundle;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
@@ -82,4 +83,13 @@ interface IFingerprintService {
// Enumerate all fingerprints
void enumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver);
+
+ // Check if a client request is currently being handled
+ boolean isClientActive();
+
+ // Add a callback which gets notified when the service starts and stops handling client requests
+ void addClientActiveCallback(IFingerprintClientActiveCallback callback);
+
+ // Removes a callback set by addClientActiveCallback
+ void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index a9c09c4bb58a..bdb278bb8c34 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -81,4 +81,6 @@ interface IInputManager {
void setPointerIconType(int typeId);
void setCustomPointerIcon(in PointerIcon icon);
+
+ void requestPointerCapture(IBinder windowToken, boolean enabled);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2b0593fd3817..6e202b00274f 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -40,6 +40,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.InputEvent;
+import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -898,6 +899,25 @@ public final class InputManager {
}
}
+ /**
+ * Request or release pointer capture.
+ * <p>
+ * When in capturing mode, the pointer icon disappears and all mouse events are dispatched to
+ * the window which has requested the capture. Relative position changes are available through
+ * {@link MotionEvent#getX} and {@link MotionEvent#getY}.
+ *
+ * @param enable true when requesting pointer capture, false when releasing.
+ *
+ * @hide
+ */
+ public void requestPointerCapture(IBinder windowToken, boolean enable) {
+ try {
+ mIm.requestPointerCapture(windowToken, enable);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/hardware/usb/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java
index 708d651a58ae..c346700a979f 100644
--- a/core/java/android/hardware/usb/UsbEndpoint.java
+++ b/core/java/android/hardware/usb/UsbEndpoint.java
@@ -75,8 +75,8 @@ public class UsbEndpoint implements Parcelable {
* if the direction is host to device, and
* {@link UsbConstants#USB_DIR_IN} if the
* direction is device to host.
- * @see {@link UsbConstants#USB_DIR_IN}
- * @see {@link UsbConstants#USB_DIR_OUT}
+ * @see UsbConstants#USB_DIR_IN
+ * @see UsbConstants#USB_DIR_OUT
*
* @return the endpoint's direction
*/
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index c9a4e9b6015a..fea730e492c8 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,11 +16,12 @@
package android.hardware.usb;
-import com.android.internal.util.Preconditions;
-
+import android.hardware.usb.V1_0.Constants;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
/**
* Represents a physical USB port and describes its characteristics.
* <p>
@@ -33,6 +34,7 @@ public final class UsbPort implements Parcelable {
private final String mId;
private final int mSupportedModes;
+ public static final int MODE_NONE = Constants.PortMode.NONE;
/**
* Mode bit: This USB port can act as a downstream facing port (host).
* <p>
@@ -40,7 +42,7 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
* </p>
*/
- public static final int MODE_DFP = 1 << 0;
+ public static final int MODE_DFP = Constants.PortMode.DFP;
/**
* Mode bit: This USB port can act as an upstream facing port (device).
@@ -49,7 +51,7 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
* </p>
*/
- public static final int MODE_UFP = 1 << 1;
+ public static final int MODE_UFP = Constants.PortMode.UFP;
/**
* Mode bit: This USB port can act either as an downstream facing port (host) or as
@@ -60,29 +62,43 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
* </p>
*/
- public static final int MODE_DUAL = MODE_DFP | MODE_UFP;
+ public static final int MODE_DUAL = Constants.PortMode.DRP;
+
+ /**
+ * Power role: This USB port does not have a power role.
+ */
+ public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
/**
* Power role: This USB port can act as a source (provide power).
*/
- public static final int POWER_ROLE_SOURCE = 1;
+ public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
/**
* Power role: This USB port can act as a sink (receive power).
*/
- public static final int POWER_ROLE_SINK = 2;
+ public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+
+ /**
+ * Power role: This USB port does not have a data role.
+ */
+ public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
/**
* Data role: This USB port can act as a host (access data services).
*/
- public static final int DATA_ROLE_HOST = 1;
+ public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
/**
* Data role: This USB port can act as a device (offer data services).
*/
- public static final int DATA_ROLE_DEVICE = 2;
+ public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
- private static final int NUM_DATA_ROLES = 3;
+ private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
+ /**
+ * Points to the first power role in the IUsb HAL.
+ */
+ private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
/** @hide */
public UsbPort(String id, int supportedModes) {
@@ -126,14 +142,14 @@ public final class UsbPort implements Parcelable {
*/
public static int combineRolesAsBit(int powerRole, int dataRole) {
checkRoles(powerRole, dataRole);
- final int index = powerRole * NUM_DATA_ROLES + dataRole;
+ final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole;
return 1 << index;
}
/** @hide */
public static String modeToString(int mode) {
switch (mode) {
- case 0:
+ case MODE_NONE:
return "none";
case MODE_DFP:
return "dfp";
@@ -149,7 +165,7 @@ public final class UsbPort implements Parcelable {
/** @hide */
public static String powerRoleToString(int role) {
switch (role) {
- case 0:
+ case POWER_ROLE_NONE:
return "no-power";
case POWER_ROLE_SOURCE:
return "source";
@@ -163,7 +179,7 @@ public final class UsbPort implements Parcelable {
/** @hide */
public static String dataRoleToString(int role) {
switch (role) {
- case 0:
+ case DATA_ROLE_NONE:
return "no-data";
case DATA_ROLE_HOST:
return "host";
@@ -183,7 +199,7 @@ public final class UsbPort implements Parcelable {
while (combo != 0) {
final int index = Integer.numberOfTrailingZeros(combo);
combo &= ~(1 << index);
- final int powerRole = index / NUM_DATA_ROLES;
+ final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET);
final int dataRole = index % NUM_DATA_ROLES;
if (first) {
first = false;
@@ -200,9 +216,28 @@ public final class UsbPort implements Parcelable {
}
/** @hide */
+ public static void checkMode(int powerRole) {
+ Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
+ Constants.PortMode.NUM_MODES - 1, "portMode");
+ }
+
+ /** @hide */
+ public static void checkPowerRole(int dataRole) {
+ Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE,
+ Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole");
+ }
+
+ /** @hide */
+ public static void checkDataRole(int mode) {
+ Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE,
+ Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole");
+ }
+
+ /** @hide */
public static void checkRoles(int powerRole, int dataRole) {
- Preconditions.checkArgumentInRange(powerRole, 0, POWER_ROLE_SINK, "powerRole");
- Preconditions.checkArgumentInRange(dataRole, 0, DATA_ROLE_DEVICE, "dataRole");
+ Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK,
+ "powerRole");
+ Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole");
}
@Override
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c6338cb53c76..5996fe2b14a3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1084,8 +1084,10 @@ public class InputMethodService extends AbstractInputMethodService {
final int currentHeight = mWindow.getWindow().getAttributes().height;
final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
if (mIsInputViewShown && currentHeight != newHeight) {
- Log.w(TAG, "Window size has been changed. This may cause jankiness of resizing window: "
- + currentHeight + " -> " + newHeight);
+ if (DEBUG) {
+ Log.w(TAG,"Window size has been changed. This may cause jankiness of resizing "
+ + "window: " + currentHeight + " -> " + newHeight);
+ }
}
mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
}
@@ -2367,16 +2369,16 @@ public class InputMethodService extends AbstractInputMethodService {
}
return true;
}
-
+
/**
* Return text that can be used as a button label for the given
* {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
* if there is no action requested. Note that there is no guarantee that
* the returned text will be relatively short, so you probably do not
* want to use it as text on a soft keyboard key label.
- *
- * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
- *
+ *
+ * @param imeOptions The value from {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
+ *
* @return Returns a label to use, or null if there is no action.
*/
public CharSequence getTextForImeAction(int imeOptions) {
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 0aef532cdb37..0ee25744488c 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -102,11 +102,14 @@ public class LogMaker {
/**
* @param tag From your MetricsEvent enum.
- * @param value One of Integer, Long, Float, String
- * @return
+ * @param value One of Integer, Long, Float, or String; or null to clear the tag.
+ * @return modified LogMaker
*/
public LogMaker addTaggedData(int tag, Object value) {
- if (isValidValue(value)) {
+ if (value == null) {
+ return clearTaggedData(tag);
+ }
+ if (!isValidValue(value)) {
throw new IllegalArgumentException(
"Value must be loggable type - int, long, float, String");
}
@@ -118,11 +121,25 @@ public class LogMaker {
return this;
}
+ /**
+ * Remove a value from the LogMaker.
+ *
+ * @param tag From your MetricsEvent enum.
+ * @return modified LogMaker
+ */
+ public LogMaker clearTaggedData(int tag) {
+ entries.delete(tag);
+ return this;
+ }
+
+ /**
+ * @return true if this object may be added to a LogMaker as a value.
+ */
public boolean isValidValue(Object value) {
- return !(value instanceof Integer ||
+ return value instanceof Integer ||
value instanceof String ||
value instanceof Long ||
- value instanceof Float);
+ value instanceof Float;
}
public Object getTaggedData(int tag) {
@@ -223,6 +240,9 @@ public class LogMaker {
return out;
}
+ /**
+ * Reconstitute an object from the output of {@link #serialize()}.
+ */
public void deserialize(Object[] items) {
int i = 0;
while (i < items.length) {
@@ -235,4 +255,22 @@ public class LogMaker {
}
}
}
+
+ /**
+ * @param that the object to compare to.
+ * @return true if values in that equal values in this, for tags that exist in this.
+ */
+ public boolean isSubsetOf(LogMaker that) {
+ if (that == null) {
+ return false;
+ }
+ for (int i = 0; i < entries.size(); i++) {
+ int key = this.entries.keyAt(i);
+ Object thisValue = this.entries.valueAt(i);
+ Object thatValue = that.entries.get(key);
+ if ((thisValue == null && thatValue != null) || !thisValue.equals(thatValue))
+ return false;
+ }
+ return true;
+ }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ac0c0dc5a916..dc5750d55066 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -46,6 +46,7 @@ import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
@@ -1240,36 +1241,27 @@ public class ConnectivityManager {
private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
if (networkType == TYPE_MOBILE) {
- int cap = -1;
- if ("enableMMS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_MMS;
- } else if ("enableSUPL".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_SUPL;
- } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_DUN;
- } else if ("enableHIPRI".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_INTERNET;
- } else if ("enableFOTA".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_FOTA;
- } else if ("enableIMS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_IMS;
- } else if ("enableCBS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_CBS;
- } else {
- return null;
- }
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
- netCap.maybeMarkCapabilitiesRestricted();
- return netCap;
- } else if (networkType == TYPE_WIFI) {
- if ("p2p".equals(feature)) {
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
- netCap.maybeMarkCapabilitiesRestricted();
- return netCap;
+ switch (feature) {
+ case "enableCBS":
+ return networkCapabilitiesForType(TYPE_MOBILE_CBS);
+ case "enableDUN":
+ case "enableDUNAlways":
+ return networkCapabilitiesForType(TYPE_MOBILE_DUN);
+ case "enableFOTA":
+ return networkCapabilitiesForType(TYPE_MOBILE_FOTA);
+ case "enableHIPRI":
+ return networkCapabilitiesForType(TYPE_MOBILE_HIPRI);
+ case "enableIMS":
+ return networkCapabilitiesForType(TYPE_MOBILE_IMS);
+ case "enableMMS":
+ return networkCapabilitiesForType(TYPE_MOBILE_MMS);
+ case "enableSUPL":
+ return networkCapabilitiesForType(TYPE_MOBILE_SUPL);
+ default:
+ return null;
}
+ } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) {
+ return networkCapabilitiesForType(TYPE_WIFI_P2P);
}
return null;
}
@@ -1477,6 +1469,59 @@ public class ConnectivityManager {
return true;
}
+ private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
+ static {
+ sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_CBS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_IMS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_MMS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI);
+ sLegacyTypeToTransport.put(TYPE_WIFI_P2P, NetworkCapabilities.TRANSPORT_WIFI);
+ sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH);
+ sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+
+ private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray();
+ static {
+ sLegacyTypeToCapability.put(TYPE_MOBILE_CBS, NetworkCapabilities.NET_CAPABILITY_CBS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_DUN, NetworkCapabilities.NET_CAPABILITY_DUN);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_IMS, NetworkCapabilities.NET_CAPABILITY_IMS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_MMS, NetworkCapabilities.NET_CAPABILITY_MMS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL);
+ sLegacyTypeToCapability.put(TYPE_WIFI_P2P, NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+ }
+
+ /**
+ * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities
+ * instance suitable for registering a request or callback. Throws an
+ * IllegalArgumentException if no mapping from the legacy type to
+ * NetworkCapabilities is known.
+ *
+ * @hide
+ */
+ public static NetworkCapabilities networkCapabilitiesForType(int type) {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+
+ // Map from type to transports.
+ final int NOT_FOUND = -1;
+ final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
+ if (transport == NOT_FOUND) {
+ throw new IllegalArgumentException("unknown legacy type: " + type);
+ }
+ nc.addTransportType(transport);
+
+ // Map from type to capabilities.
+ nc.addCapability(sLegacyTypeToCapability.get(
+ type, NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ nc.maybeMarkCapabilitiesRestricted();
+ return nc;
+ }
+
/** @hide */
public static class PacketKeepaliveCallback {
/** The requested keepalive was successfully started. */
@@ -3264,6 +3309,75 @@ public class ConnectivityManager {
}
/**
+ * It is acceptable to briefly use multipath data to provide seamless connectivity for
+ * time-sensitive user-facing operations when the system default network is temporarily
+ * unresponsive. The amount of data should be limited (less than one megabyte), and the
+ * operation should be infrequent to ensure that data usage is limited.
+ *
+ * An example of such an operation might be a time-sensitive foreground activity, such as a
+ * voice command, that the user is performing while walking out of range of a Wi-Fi network.
+ */
+ public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0;
+
+ /**
+ * It is acceptable to use small amounts of multipath data on an ongoing basis to provide
+ * a backup channel for traffic that is primarily going over another network.
+ *
+ * An example might be maintaining backup connections to peers or servers for the purpose of
+ * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic
+ * on backup paths should be negligible compared to the traffic on the main path.
+ */
+ public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1;
+
+ /**
+ * It is acceptable to use metered data to improve network latency and performance.
+ */
+ public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2;
+
+ /**
+ * Return value to use for unmetered networks. On such networks we currently set all the flags
+ * to true.
+ * @hide
+ */
+ public static final int MULTIPATH_PREFERENCE_UNMETERED =
+ MULTIPATH_PREFERENCE_HANDOVER |
+ MULTIPATH_PREFERENCE_RELIABILITY |
+ MULTIPATH_PREFERENCE_PERFORMANCE;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ MULTIPATH_PREFERENCE_HANDOVER,
+ MULTIPATH_PREFERENCE_RELIABILITY,
+ MULTIPATH_PREFERENCE_PERFORMANCE,
+ })
+ public @interface MultipathPreference {
+ }
+
+ /**
+ * Provides a hint to the calling application on whether it is desirable to use the
+ * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
+ * for multipath data transfer on this network when it is not the system default network.
+ * Applications desiring to use multipath network protocols should call this method before
+ * each such operation.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param network The network on which the application desires to use multipath data.
+ * If {@code null}, this method will return the a preference that will generally
+ * apply to metered networks.
+ * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
+ */
+ public @MultipathPreference int getMultipathPreference(Network network) {
+ try {
+ return mService.getMultipathPreference(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4aabda9eb09d..117fa0b476f4 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -163,6 +163,8 @@ interface IConnectivityManager
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network);
+ int getMultipathPreference(in Network Network);
+
int getRestoreDefaultNetworkDelay(int networkType);
boolean addVpnAddress(String address, int prefixLength);
diff --git a/core/java/android/net/IpPrefix.aidl b/core/java/android/net/IpPrefix.aidl
index 9e552c72c64d..837db5f1ef37 100644
--- a/core/java/android/net/IpPrefix.aidl
+++ b/core/java/android/net/IpPrefix.aidl
@@ -17,4 +17,4 @@
package android.net;
-parcelable IpPrefix;
+parcelable IpPrefix cpp_header "binder/IpPrefix.h";
diff --git a/core/java/android/net/NetworkBadging.java b/core/java/android/net/NetworkBadging.java
new file mode 100644
index 000000000000..5cf2f965ffa6
--- /dev/null
+++ b/core/java/android/net/NetworkBadging.java
@@ -0,0 +1,152 @@
+/*
+ * 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.net;
+
+import android.annotation.DrawableRes;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.ScoredNetwork.Badging;
+import android.net.wifi.WifiManager;
+import android.view.View;
+
+/**
+ * Utility methods for working with network badging.
+ *
+ * TODO: move ScoredNetwork.Badging and related constants to this class.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkBadging {
+ private NetworkBadging() {}
+
+ /**
+ * Returns a Wi-Fi icon for a network with a given signal level and badging value.
+ *
+ * @param signalLevel The level returned by {@link WifiManager#calculateSignalLevel(int, int)}
+ * for a network. Must be between 0 and {@link WifiManager#RSSI_LEVELS}-1.
+ * @param badging {@see ScoredNetwork#Badging}, retrieved from
+ * {@link ScoredNetwork#calculateBadge(int)}.
+ * @param theme The theme for the current application, may be null.
+ * @return Drawable for the given icon
+ * @throws IllegalArgumentException if {@code signalLevel} is out of range or {@code badging}
+ * is an invalid value
+ */
+ @NonNull public static Drawable getWifiIcon(
+ @IntRange(from=0, to=4) int signalLevel, @Badging int badging, @Nullable Theme theme) {
+ Resources resources = Resources.getSystem();
+ if (badging == ScoredNetwork.BADGING_NONE) {
+ return resources.getDrawable(getWifiSignalResource(signalLevel), theme);
+ }
+ Drawable[] layers = new Drawable[] {
+ resources.getDrawable(getBadgedWifiSignalResource(signalLevel), theme),
+ resources.getDrawable(getWifiBadgeResource(badging), theme)
+ };
+ return new LayerDrawable(layers);
+ }
+
+ /**
+ * Returns the wifi signal resource id for the given signal level.
+ *
+ * <p>This wifi signal resource is a wifi icon to be displayed by itself when there is no badge.
+ *
+ * @param signalLevel The level returned by {@link WifiManager#calculateSignalLevel(int, int)}
+ * for a network. Must be between 0 and {@link WifiManager#RSSI_LEVELS}-1.
+ * @return the @DrawableRes for the icon
+ * @throws IllegalArgumentException for an invalid signal level
+ * @hide
+ */
+ @DrawableRes private static int getWifiSignalResource(int signalLevel) {
+ switch (signalLevel) {
+ case 0:
+ return com.android.internal.R.drawable.ic_wifi_signal_0;
+ case 1:
+ return com.android.internal.R.drawable.ic_wifi_signal_1;
+ case 2:
+ return com.android.internal.R.drawable.ic_wifi_signal_2;
+ case 3:
+ return com.android.internal.R.drawable.ic_wifi_signal_3;
+ case 4:
+ return com.android.internal.R.drawable.ic_wifi_signal_4;
+ default:
+ throw new IllegalArgumentException("Invalid signal level: " + signalLevel);
+ }
+ }
+
+ /**
+ * Returns the badged wifi signal resource id for the given signal level.
+ *
+ * <p>This badged wifi signal resource should be displayed with the quality badge retrieved
+ * from {@link #getWifiBadgeResource(int)}. If there is no badge,
+ * {@link #getWifiBadgeResource(int)} should be used instead of this method.
+ *
+ * @param signalLevel The level returned by {@link WifiManager#calculateSignalLevel(int, int)}
+ * for a network. Must be between 0 and {@link WifiManager#RSSI_LEVELS}-1.
+ * @return the @DrawableRes for the icon
+ * @throws IllegalArgumentException for an invalid signal level
+ * @hide
+ */
+ @DrawableRes private static int getBadgedWifiSignalResource(int signalLevel) {
+ switch (signalLevel) {
+ case 0:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_0_bars;
+ case 1:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_1_bar;
+ case 2:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_2_bars;
+ case 3:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_3_bars;
+ case 4:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_4_bars;
+ default:
+ throw new IllegalArgumentException("Invalid signal level: " + signalLevel);
+ }
+ }
+
+ /**
+ * Returns the wifi quality badge resource id for the the given badging balue.
+ *
+ * <p>This badge should be displayed with the badge signal resource retrieved from
+ * {@link #getBadgedWifiSignalResource(int)}.
+ *
+ * @param badging {@see ScoredNetwork#Badging} from {@link ScoredNetwork#calculateBadge(int)}.
+ * @return the @DrawableRes for the icon or {@link View#NO_ID} for
+ * {@link ScoredNetwork#BADGING_NONE}
+ * @throws IllegalArgumentException for an invalid badging value.
+ * @hide
+ */
+ @DrawableRes private static int getWifiBadgeResource(@Badging int badging) {
+ switch (badging) {
+ case ScoredNetwork.BADGING_NONE:
+ return View.NO_ID;
+ case ScoredNetwork.BADGING_SD:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_sd;
+ case ScoredNetwork.BADGING_HD:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_hd;
+ case ScoredNetwork.BADGING_4K:
+ return com.android.internal.R.drawable.ic_signal_wifi_badged_4k;
+ default:
+ throw new IllegalArgumentException("No resource found for badge: " + badging);
+ }
+ }
+}
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 1a128e05ce6e..e5f0bf000f64 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -16,10 +16,14 @@
package android.net;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiSsid;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.Objects;
@@ -65,6 +69,27 @@ public class NetworkKey implements Parcelable {
}
/**
+ * Constructs a new NetworkKey for the given {@link WifiInfo}.
+ *
+ * @param wifiInfo the {@link WifiInfo} to create a {@link NetworkKey} for.
+ * @return A new {@link NetworkKey} instance or <code>null</code> if the given {@link WifiInfo}
+ * instance doesn't represent a connected WiFi network.
+ * @hide
+ */
+ @Nullable
+ public static NetworkKey createFromWifiInfo(@Nullable WifiInfo wifiInfo) {
+ if (wifiInfo != null) {
+ final String ssid = wifiInfo.getSSID();
+ final String bssid = wifiInfo.getBSSID();
+ if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
+ && !TextUtils.isEmpty(bssid)) {
+ return new NetworkKey(new WifiKey(ssid, bssid));
+ }
+ }
+ return null;
+ }
+
+ /**
* Construct a new {@link NetworkKey} for a Wi-Fi network.
* @param wifiKey the {@link WifiKey} identifying this Wi-Fi network.
*/
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 16ae867d81e7..5739c79b8f96 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -5,8 +5,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -27,8 +25,6 @@ public abstract class NetworkRecommendationProvider {
"android.net.extra.RECOMMENDATION_RESULT";
/** The key into the callback Bundle where the sequence will be found. */
public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
- private static final String EXTRA_RECOMMENDATION_REQUEST =
- "android.net.extra.RECOMMENDATION_REQUEST";
private final IBinder mService;
/**
@@ -39,7 +35,7 @@ public abstract class NetworkRecommendationProvider {
if (handler == null) {
throw new IllegalArgumentException("The provided handler cannot be null.");
}
- mService = new ServiceWrapper(new ServiceHandler(handler.getLooper()));
+ mService = new ServiceWrapper(handler);
}
/**
@@ -125,42 +121,10 @@ public abstract class NetworkRecommendationProvider {
}
}
- private final class ServiceHandler extends Handler {
- static final int MSG_GET_RECOMMENDATION = 1;
- static final int MSG_REQUEST_SCORES = 2;
-
- ServiceHandler(Looper looper) {
- super(looper, null /*callback*/, true /*async*/);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final int what = msg.what;
- switch (what) {
- case MSG_GET_RECOMMENDATION:
- final IRemoteCallback callback = (IRemoteCallback) msg.obj;
- final int seq = msg.arg1;
- final RecommendationRequest request =
- msg.getData().getParcelable(EXTRA_RECOMMENDATION_REQUEST);
- final ResultCallback resultCallback = new ResultCallback(callback, seq);
- onRequestRecommendation(request, resultCallback);
- break;
-
- case MSG_REQUEST_SCORES:
- final NetworkKey[] networks = (NetworkKey[]) msg.obj;
- onRequestScores(networks);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown message: " + what);
- }
- }
- }
-
/**
- * A wrapper around INetworkRecommendationProvider that sends calls to the internal Handler.
+ * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
*/
- private static final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+ private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
private final Handler mHandler;
ServiceWrapper(Handler handler) {
@@ -168,20 +132,26 @@ public abstract class NetworkRecommendationProvider {
}
@Override
- public void requestRecommendation(RecommendationRequest request, IRemoteCallback callback,
- int sequence) throws RemoteException {
- final Message msg = mHandler.obtainMessage(
- ServiceHandler.MSG_GET_RECOMMENDATION, sequence, 0 /*arg2*/, callback);
- final Bundle data = new Bundle();
- data.putParcelable(EXTRA_RECOMMENDATION_REQUEST, request);
- msg.setData(data);
- msg.sendToTarget();
+ public void requestRecommendation(final RecommendationRequest request,
+ final IRemoteCallback callback, final int sequence) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ResultCallback resultCallback = new ResultCallback(callback, sequence);
+ onRequestRecommendation(request, resultCallback);
+ }
+ });
}
@Override
- public void requestScores(NetworkKey[] networks) throws RemoteException {
+ public void requestScores(final NetworkKey[] networks) throws RemoteException {
if (networks != null && networks.length > 0) {
- mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_SCORES, networks).sendToTarget();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onRequestScores(networks);
+ }
+ });
}
}
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index ae724709c6c6..cb780090c46a 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -178,6 +178,20 @@ public class NetworkRequest implements Parcelable {
}
/**
+ * Set the {@code NetworkCapabilities} for this builder instance,
+ * overriding any capabilities that had been previously set.
+ *
+ * @param nc The superseding {@code NetworkCapabilities} instance.
+ * @return The builder to facilitate chaining.
+ * @hide
+ */
+ public Builder setCapabilities(NetworkCapabilities nc) {
+ mNetworkCapabilities.clearAll();
+ mNetworkCapabilities.combineCapabilities(nc);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 9e4dd8748f39..9dcf4f44a559 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -18,6 +18,7 @@ package android.net;
import android.Manifest.permission;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +34,7 @@ import com.android.internal.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Internal class for discovering and managing the network scorer/recommendation application.
@@ -53,33 +55,43 @@ public class NetworkScorerAppManager {
* Holds metadata about a discovered network scorer/recommendation application.
*/
public static class NetworkScorerAppData {
- /** Package name of this scorer app. */
- public final String packageName;
-
/** UID of the scorer app. */
public final int packageUid;
+ private final ComponentName mRecommendationService;
- /**
- * Name of the recommendation service we can bind to.
- */
- public final String recommendationServiceClassName;
-
- public NetworkScorerAppData(String packageName, int packageUid,
- String recommendationServiceClassName) {
- this.packageName = packageName;
+ public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp) {
this.packageUid = packageUid;
- this.recommendationServiceClassName = recommendationServiceClassName;
+ this.mRecommendationService = recommendationServiceComp;
+ }
+
+ public String getRecommendationServicePackageName() {
+ return mRecommendationService.getPackageName();
+ }
+
+ public ComponentName getRecommendationServiceComponent() {
+ return mRecommendationService;
}
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder("NetworkScorerAppData{");
- sb.append("mPackageName='").append(packageName).append('\'');
- sb.append(", packageUid=").append(packageUid);
- sb.append(", recommendationServiceClassName='")
- .append(recommendationServiceClassName).append('\'');
- sb.append('}');
- return sb.toString();
+ return "NetworkScorerAppData{" +
+ "packageUid=" + packageUid +
+ ", mRecommendationService=" + mRecommendationService +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NetworkScorerAppData that = (NetworkScorerAppData) o;
+ return packageUid == that.packageUid &&
+ Objects.equals(mRecommendationService, that.mRecommendationService);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageUid, mRecommendationService);
}
}
@@ -110,16 +122,16 @@ public class NetworkScorerAppManager {
return null;
}
- final PackageManager pm = mContext.getPackageManager();
for (int i = 0; i < potentialPkgs.size(); i++) {
final String potentialPkg = potentialPkgs.get(i);
// Look for the recommendation service class and required receiver.
final ResolveInfo resolveServiceInfo = findRecommendationService(potentialPkg);
if (resolveServiceInfo != null) {
- return new NetworkScorerAppData(potentialPkg,
- resolveServiceInfo.serviceInfo.applicationInfo.uid,
- resolveServiceInfo.serviceInfo.name);
+ final ComponentName componentName =
+ new ComponentName(potentialPkg, resolveServiceInfo.serviceInfo.name);
+ return new NetworkScorerAppData(resolveServiceInfo.serviceInfo.applicationInfo.uid,
+ componentName);
} else {
if (DEBUG) {
Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
index b89a245623ee..9f97c5a79506 100644
--- a/core/java/android/net/RecommendationRequest.java
+++ b/core/java/android/net/RecommendationRequest.java
@@ -50,7 +50,7 @@ public final class RecommendationRequest implements Parcelable {
private WifiConfiguration mDefaultConfig;
private WifiConfiguration mConnectedConfig;
private WifiConfiguration[] mConnectableConfigs;
- private int mLastSelectedNetworkId;
+ private int mLastSelectedNetworkId = -1;
private long mLastSelectedTimestamp;
public Builder setScanResults(ScanResult[] scanResults) {
@@ -161,7 +161,7 @@ public final class RecommendationRequest implements Parcelable {
/**
* @return The {@link WifiConfiguration#networkId} of the last user selected network.
- * {@code 0} if not set.
+ * {@code -1} if not set.
*/
public int getLastSelectedNetworkId() {
return mLastSelectedNetworkId;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 7396189e77cd..d5377c717366 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1747,8 +1747,8 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* begin with and a scheme component cannot be found.
*
* @return normalized Uri (never null)
- * @see {@link android.content.Intent#setData}
- * @see {@link android.content.Intent#setDataAndNormalize}
+ * @see android.content.Intent#setData
+ * @see android.content.Intent#setDataAndNormalize
*/
public Uri normalizeScheme() {
String scheme = getScheme();
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 83d17ba7fdd2..bd3231464ccf 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -805,7 +805,7 @@ public final class NdefRecord implements Parcelable {
if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
throw new FormatException("expected MB flag");
- } else if (mb && records.size() != 0 && !ignoreMbMe) {
+ } else if (mb && (records.size() != 0 || inChunk) && !ignoreMbMe) {
throw new FormatException("unexpected MB flag");
} else if (inChunk && il) {
throw new FormatException("unexpected IL flag in non-leading chunk");
@@ -839,6 +839,9 @@ public final class NdefRecord implements Parcelable {
if (cf && !inChunk) {
// first chunk
+ if (typeLength == 0) {
+ throw new FormatException("expected non-zero type length in first chunk");
+ }
chunks.clear();
chunkTnf = tnf;
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 263750aa9946..3a441c7cb1ca 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -201,6 +201,11 @@ public class BatteryManager {
*/
public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
+ /**
+ * Battery charge status, from a BATTERY_STATUS_* value.
+ */
+ public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6;
+
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 80ecf9789c7b..817cb5bb9add 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -883,8 +883,11 @@ public class Build {
SystemProperties.getInt("ro.debuggable", 0) == 1;
/** {@hide} */
- public static final boolean IS_ENG =
- "eng".equals(getString("ro.build.type"));
+ public static final boolean IS_ENG = "eng".equals(TYPE);
+ /** {@hide} */
+ public static final boolean IS_USERDEBUG = "userdebug".equals(TYPE);
+ /** {@hide} */
+ public static final boolean IS_USER = "user".equals(TYPE);
/**
* Whether this build is running inside a container.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 175d883da29d..210ddb6cd397 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1119,8 +1119,8 @@ public final class Debug
* @hide
*/
public static void startMethodTracing(String traceName, FileDescriptor fd,
- int bufferSize, int flags) {
- VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0);
+ int bufferSize, int flags, boolean streamOutput) {
+ VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0, streamOutput);
}
/**
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 4616af8f7768..7cdb3cec5dbb 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -272,6 +272,11 @@ public class Environment {
}
/** {@hide} */
+ public static File getDataMiscCeDirectory() {
+ return buildPath(getDataDirectory(), "misc_ce");
+ }
+
+ /** {@hide} */
public static File getDataMiscCeDirectory(int userId) {
return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
}
@@ -380,6 +385,24 @@ public class Environment {
}
/**
+ * Returns location of preloaded cache directory for package name
+ * @see #getDataPreloadsDirectory()
+ * {@hide}
+ */
+ public static File getDataPreloadsFileCacheDirectory(String packageName) {
+ return new File(getDataPreloadsFileCacheDirectory(), packageName);
+ }
+
+ /**
+ * Returns location of preloaded cache directory.
+ * @see #getDataPreloadsDirectory()
+ * {@hide}
+ */
+ public static File getDataPreloadsFileCacheDirectory() {
+ return new File(getDataPreloadsDirectory(), "file_cache");
+ }
+
+ /**
* Return the primary shared/external storage directory. This directory may
* not currently be accessible if it has been mounted by the user on their
* computer, has been removed from the device, or some other problem has
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 1c2588ada181..12f539687247 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -43,6 +43,7 @@ interface IUserManager {
void setUserEnabled(int userHandle);
void evictCredentialEncryptionKey(int userHandle);
boolean removeUser(int userHandle);
+ boolean removeUserEvenWhenDisallowed(int userHandle);
void setUserName(int userHandle, String name);
void setUserIcon(int userHandle, in Bitmap icon);
ParcelFileDescriptor getUserIcon(int userHandle);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index d6d5cb6493e0..f94e89a2785d 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.IntegerRes;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -26,6 +27,7 @@ import android.util.Size;
import android.util.SizeF;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import libcore.util.SneakyThrow;
@@ -210,7 +212,7 @@ public final class Parcel {
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
- // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
+ // Keep in sync with frameworks/native/include/private/binder/ParcelValTypes.h.
private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
@@ -891,6 +893,21 @@ public final class Parcel {
}
}
+ public final void writeSparseIntArray(SparseIntArray val) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ int N = val.size();
+ writeInt(N);
+ int i=0;
+ while (i < N) {
+ writeInt(val.keyAt(i));
+ writeInt(val.valueAt(i));
+ i++;
+ }
+ }
+
public final void writeBooleanArray(boolean[] val) {
if (val != null) {
int N = val.length;
@@ -1323,7 +1340,7 @@ public final class Parcel {
}
/**
- * Flatten a heterogeneous array containing a particular object type into
+ * Flatten a homogeneous array containing a particular object type into
* the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. The
* type of the objects in the array must be one that implements Parcelable.
@@ -1345,7 +1362,7 @@ public final class Parcel {
if (val != null) {
int N = val.length;
writeInt(N);
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
T item = val[i];
if (item != null) {
writeInt(1);
@@ -1360,6 +1377,146 @@ public final class Parcel {
}
/**
+ * Write a uniform (all items are null or the same class) array list of
+ * parcelables.
+ *
+ * @param list The list to write.
+ *
+ * @hide
+ */
+ public final <T extends Parcelable> void writeTypedArrayList(@Nullable ArrayList<T> list,
+ int parcelableFlags) {
+ if (list != null) {
+ int N = list.size();
+ writeInt(N);
+ boolean wroteCreator = false;
+ for (int i = 0; i < N; i++) {
+ T item = list.get(i);
+ if (item != null) {
+ writeInt(1);
+ if (!wroteCreator) {
+ writeParcelableCreator(item);
+ wroteCreator = true;
+ }
+ item.writeToParcel(this, parcelableFlags);
+ } else {
+ writeInt(0);
+ }
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
+ /**
+ * Reads a uniform (all items are null or the same class) array list of
+ * parcelables.
+ *
+ * @return The list or null.
+ *
+ * @hide
+ */
+ public final @Nullable <T> ArrayList<T> readTypedArrayList(@Nullable ClassLoader loader) {
+ int N = readInt();
+ if (N <= 0) {
+ return null;
+ }
+ Parcelable.Creator<?> creator = null;
+ ArrayList<T> result = new ArrayList<T>(N);
+ for (int i = 0; i < N; i++) {
+ if (readInt() != 0) {
+ if (creator == null) {
+ creator = readParcelableCreator(loader);
+ if (creator == null) {
+ return null;
+ }
+ }
+ final T parcelable;
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ parcelable = (T) classLoaderCreator.createFromParcel(this, loader);
+ } else {
+ parcelable = (T) creator.createFromParcel(this);
+ }
+ result.add(parcelable);
+ } else {
+ result.add(null);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Write a uniform (all items are null or the same class) array set of
+ * parcelables.
+ *
+ * @param set The set to write.
+ *
+ * @hide
+ */
+ public final <T extends Parcelable> void writeTypedArraySet(@Nullable ArraySet<T> set,
+ int parcelableFlags) {
+ if (set != null) {
+ int N = set.size();
+ writeInt(N);
+ boolean wroteCreator = false;
+ for (int i = 0; i < N; i++) {
+ T item = set.valueAt(i);
+ if (item != null) {
+ writeInt(1);
+ if (!wroteCreator) {
+ writeParcelableCreator(item);
+ wroteCreator = true;
+ }
+ item.writeToParcel(this, parcelableFlags);
+ } else {
+ writeInt(0);
+ }
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
+ /**
+ * Reads a uniform (all items are null or the same class) array set of
+ * parcelables.
+ *
+ * @return The set or null.
+ *
+ * @hide
+ */
+ public final @Nullable <T> ArraySet<T> readTypedArraySet(@Nullable ClassLoader loader) {
+ int N = readInt();
+ if (N <= 0) {
+ return null;
+ }
+ Parcelable.Creator<?> creator = null;
+ ArraySet<T> result = new ArraySet<T>(N);
+ for (int i = 0; i < N; i++) {
+ T parcelable = null;
+ if (readInt() != 0) {
+ if (creator == null) {
+ creator = readParcelableCreator(loader);
+ if (creator == null) {
+ return null;
+ }
+ }
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ parcelable = (T) classLoaderCreator.createFromParcel(this, loader);
+ } else {
+ parcelable = (T) creator.createFromParcel(this);
+ }
+ }
+ result.append(parcelable);
+ }
+ return result;
+ }
+
+ /**
* Flatten the Parcelable object into the parcel.
*
* @param val The Parcelable object to be written.
@@ -2154,6 +2311,20 @@ public final class Parcel {
}
/**
+ * Read and return a new SparseIntArray object from the parcel at the current
+ * dataPosition(). Returns null if the previously written array object was null.
+ */
+ public final SparseIntArray readSparseIntArray() {
+ int N = readInt();
+ if (N < 0) {
+ return null;
+ }
+ SparseIntArray sa = new SparseIntArray(N);
+ readSparseIntArrayInternal(sa, N);
+ return sa;
+ }
+
+ /**
* Read and return a new ArrayList containing a particular object type from
* the parcel that was written with {@link #writeTypedList} at the
* current dataPosition(). Returns null if the
@@ -2922,6 +3093,15 @@ public final class Parcel {
}
}
+ private void readSparseIntArrayInternal(SparseIntArray outVal, int N) {
+ while (N > 0) {
+ int key = readInt();
+ int value = readInt();
+ outVal.append(key, value);
+ N--;
+ }
+ }
+
/**
* @hide For testing
*/
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index dff0a287e25c..31b3bc988f40 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -508,15 +508,6 @@ public final class PowerManager {
}
/**
- * Returns true if the twilight service should be used to adjust screen brightness
- * policy. This setting is experimental and disabled by default.
- * @hide
- */
- public static boolean useTwilightAdjustmentFeature() {
- return SystemProperties.getBoolean("persist.power.usetwilightadj", false);
- }
-
- /**
* Creates a new wake lock with the specified level and flags.
* <p>
* The {@code levelAndFlags} parameter specifies a wake lock level and optional flags
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a8822c5be2f0..ef5bc5cf9075 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -623,7 +623,8 @@ public class RecoverySystem {
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
diff --git a/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java b/core/java/android/os/Seccomp.java
index 7b3c0a70d3c2..f14e93fe9403 100644
--- a/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java
+++ b/core/java/android/os/Seccomp.java
@@ -13,20 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.logging.legacy;
+
+package android.os;
/**
- * Parse the Android framework sysui search query logs.
- * For now just treat them like actions.
* @hide
*/
-public class SysuiQueryParser extends SysuiActionParser {
- private static final String TAG = "SysuiQueryParser";
-
- private static final int EVENTLOG_TAG = 524289;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
+public final class Seccomp {
+ public static final native void setPolicy();
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ae981b77ca84..b9e4bad5cf26 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -40,6 +40,7 @@ import com.android.internal.util.HexDump;
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
+import dalvik.system.VMRuntime;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -423,7 +424,21 @@ public final class StrictMode {
* disk operations but will likely expand in future releases.
*/
public Builder detectAll() {
- return enable(ALL_THREAD_DETECT_BITS);
+ detectDiskReads();
+ detectDiskWrites();
+ detectNetwork();
+
+ final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) {
+ detectCustomSlowCalls();
+ }
+ if (targetSdk >= Build.VERSION_CODES.M) {
+ detectResourceMismatches();
+ }
+ if (targetSdk >= Build.VERSION_CODES.O) {
+ detectUnbufferedIo();
+ }
+ return this;
}
/**
@@ -722,18 +737,31 @@ public final class StrictMode {
* but will likely expand in future releases.
*/
public Builder detectAll() {
- int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
- | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
- | DETECT_VM_FILE_URI_EXPOSURE | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION
- | DETECT_VM_UNTAGGED_SOCKET;
-
- // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility
- // for apps to mark sockets that should be ignored
- if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) {
- flags |= DETECT_VM_CLEARTEXT_NETWORK;
- }
+ detectLeakedSqlLiteObjects();
- return enable(flags);
+ final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) {
+ detectActivityLeaks();
+ detectLeakedClosableObjects();
+ }
+ if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN) {
+ detectLeakedRegistrationObjects();
+ }
+ if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ detectFileUriExposure();
+ }
+ if (targetSdk >= Build.VERSION_CODES.M) {
+ // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have
+ // facility for apps to mark sockets that should be ignored
+ if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) {
+ detectCleartextNetwork();
+ }
+ }
+ if (targetSdk >= Build.VERSION_CODES.O) {
+ detectContentUriWithoutPermission();
+ detectUntaggedSockets();
+ }
+ return this;
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index efacb205c36d..dfcab3df628d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -66,6 +66,8 @@ public class UserManager {
private final IUserManager mService;
private final Context mContext;
+ private Boolean mIsManagedProfileCached;
+
/**
* @hide
* No user restriction.
@@ -514,6 +516,7 @@ public class UserManager {
* <li>{@link LayoutParams#TYPE_SYSTEM_ALERT}</li>
* <li>{@link LayoutParams#TYPE_SYSTEM_ERROR}</li>
* <li>{@link LayoutParams#TYPE_SYSTEM_OVERLAY}</li>
+ * <li>{@link LayoutParams#TYPE_APPLICATION_OVERLAY}</li>
*
* <p>This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
@@ -970,8 +973,14 @@ public class UserManager {
*/
@SystemApi
public boolean isManagedProfile() {
+ // No need for synchronization. Once it becomes non-null, it'll be non-null forever.
+ // Worst case we might end up calling the AIDL method multiple times but that's fine.
+ if (mIsManagedProfileCached != null) {
+ return mIsManagedProfileCached;
+ }
try {
- return mService.isManagedProfile(UserHandle.myUserId());
+ mIsManagedProfileCached = mService.isManagedProfile(UserHandle.myUserId());
+ return mIsManagedProfileCached;
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -987,6 +996,9 @@ public class UserManager {
*/
@SystemApi
public boolean isManagedProfile(@UserIdInt int userId) {
+ if (userId == UserHandle.myUserId()) {
+ return isManagedProfile();
+ }
try {
return mService.isManagedProfile(userId);
} catch (RemoteException re) {
@@ -2082,6 +2094,22 @@ public class UserManager {
}
/**
+ * Similar to {@link #removeUser(int)} except bypassing the checking of
+ * {@link UserManager#DISALLOW_REMOVE_USER}
+ * or {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
+ *
+ * @see {@link #removeUser(int)}
+ * @hide
+ */
+ public boolean removeUserEvenWhenDisallowed(@UserIdInt int userHandle) {
+ try {
+ return mService.removeUserEvenWhenDisallowed(userHandle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Updates the user's name.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 5ac33a1768c2..fa9f394add60 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -352,8 +352,8 @@ public class ZygoteProcess {
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
- if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
- argsForZygote.add("--enable-debugger");
+ if ((debugFlags & Zygote.DEBUG_ENABLE_JDWP) != 0) {
+ argsForZygote.add("--enable-jdwp");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
@@ -367,6 +367,9 @@ public class ZygoteProcess {
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
+ if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
+ argsForZygote.add("--java-debuggable");
+ }
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
@@ -379,9 +382,6 @@ public class ZygoteProcess {
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
- //TODO optionally enable debuger
- //argsForZygote.add("--enable-debugger");
-
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 405be1a2520c..344d947a3ad3 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -72,14 +72,6 @@ public abstract class RuntimePermissionPresenterService extends Service {
*/
public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
- /**
- * Gets the apps that use runtime permissions.
- *
- * @param system Whether to return only the system apps or only the non-system ones.
- * @return The app list.
- */
- public abstract List<ApplicationInfo> onGetAppsUsingPermissions(boolean system);
-
@Override
public final IBinder onBind(Intent intent) {
return new IRuntimePermissionPresenter.Stub() {
@@ -91,12 +83,6 @@ public abstract class RuntimePermissionPresenterService extends Service {
mHandler.obtainMessage(MyHandler.MSG_GET_APP_PERMISSIONS,
args).sendToTarget();
}
-
- @Override
- public void getAppsUsingPermissions(boolean system, RemoteCallback callback) {
- mHandler.obtainMessage(MyHandler.MSG_GET_APPS_USING_PERMISSIONS,
- system ? 1 : 0, 0, callback).sendToTarget();
- }
};
}
@@ -127,19 +113,6 @@ public abstract class RuntimePermissionPresenterService extends Service {
callback.sendResult(null);
}
} break;
-
- case MSG_GET_APPS_USING_PERMISSIONS: {
- RemoteCallback callback = (RemoteCallback) msg.obj;
- final boolean system = msg.arg1 == 1;
- List<ApplicationInfo> apps = onGetAppsUsingPermissions(system);
- if (apps != null && !apps.isEmpty()) {
- Bundle result = new Bundle();
- result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, apps);
- callback.sendResult(result);
- } else {
- callback.sendResult(null);
- }
- } break;
}
}
}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 8303bca34bee..089eaeceac55 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -145,6 +145,8 @@ public class Preference implements Comparable<Preference> {
private List<Preference> mDependents;
+ private PreferenceGroup mParentGroup;
+
private boolean mBaseMethodCalled;
/**
@@ -1238,6 +1240,16 @@ public class Preference implements Comparable<Preference> {
registerDependency();
}
+ /**
+ * Assigns a {@link PreferenceGroup} as the parent of this Preference. Set null to remove
+ * the current parent.
+ *
+ * @param parentGroup Parent preference group of this Preference or null if none.
+ */
+ void assignParent(@Nullable PreferenceGroup parentGroup) {
+ mParentGroup = parentGroup;
+ }
+
private void registerDependency() {
if (TextUtils.isEmpty(mDependencyKey)) return;
@@ -1401,6 +1413,17 @@ public class Preference implements Comparable<Preference> {
}
/**
+ * Returns the {@link PreferenceGroup} which is this Preference assigned to or null if this
+ * preference is not assigned to any group or is a root Preference.
+ *
+ * @return The parent PreferenceGroup or null if not attached to any.
+ */
+ @Nullable
+ public PreferenceGroup getParent() {
+ return mParentGroup;
+ }
+
+ /**
* Called when this Preference is being removed from the hierarchy. You
* should remove any references to this Preference that you know about. Make
* sure to call through to the superclass implementation.
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 06666f459e5d..5e7f68b794bf 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.animation.LayoutTransition;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.XmlRes;
@@ -87,7 +88,7 @@ import java.util.List;
* items. Doing this implicitly switches the class into its new "headers
* + fragments" mode rather than the old style of just showing a single
* preferences list.
- *
+ *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For information about using {@code PreferenceActivity},
@@ -199,6 +200,9 @@ public abstract class PreferenceActivity extends ListActivity implements
private ViewGroup mPrefsContainer;
+ // Null if in legacy mode.
+ private ViewGroup mHeadersContainer;
+
private FragmentBreadCrumbs mFragmentBreadCrumbs;
private boolean mSinglePane;
@@ -292,7 +296,7 @@ public abstract class PreferenceActivity extends ListActivity implements
holder = (HeaderViewHolder) view.getTag();
}
- // All view fields must be updated every time, because the view may be recycled
+ // All view fields must be updated every time, because the view may be recycled
Header header = getItem(position);
if (mRemoveIconIfEmpty) {
if (header.iconRes == 0) {
@@ -469,7 +473,7 @@ public abstract class PreferenceActivity extends ListActivity implements
}
return breadCrumbShortTitle;
}
-
+
@Override
public int describeContents() {
return 0;
@@ -558,6 +562,7 @@ public abstract class PreferenceActivity extends ListActivity implements
mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
+ mHeadersContainer = (ViewGroup) findViewById(com.android.internal.R.id.headers);
boolean hidingHeaders = onIsHidingHeaders();
mSinglePane = hidingHeaders || !onIsMultiPane();
String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
@@ -575,66 +580,39 @@ public abstract class PreferenceActivity extends ListActivity implements
(int) HEADER_ID_UNDEFINED);
if (curHeader >= 0 && curHeader < mHeaders.size()) {
setSelectedHeader(mHeaders.get(curHeader));
+ } else if (!mSinglePane && initialFragment == null) {
+ switchToHeader(onGetInitialHeader());
}
+ } else {
+ // This will for instance hide breadcrumbs for single pane.
+ showBreadCrumbs(getTitle(), null);
}
-
} else {
- if (initialFragment != null && mSinglePane) {
- // If we are just showing a fragment, we want to run in
- // new fragment mode, but don't need to compute and show
- // the headers.
- switchToHeader(initialFragment, initialArguments);
- if (initialTitle != 0) {
- CharSequence initialTitleStr = getText(initialTitle);
- CharSequence initialShortTitleStr = initialShortTitle != 0
- ? getText(initialShortTitle) : null;
- showBreadCrumbs(initialTitleStr, initialShortTitleStr);
- }
-
- } else {
- // We need to try to build the headers.
+ if (!onIsHidingHeaders()) {
onBuildHeaders(mHeaders);
+ }
- // If there are headers, then at this point we need to show
- // them and, depending on the screen, we may also show in-line
- // the currently selected preference fragment.
- if (mHeaders.size() > 0) {
- if (!mSinglePane) {
- if (initialFragment == null) {
- Header h = onGetInitialHeader();
- switchToHeader(h);
- } else {
- switchToHeader(initialFragment, initialArguments);
- }
- }
- }
+ if (initialFragment != null) {
+ switchToHeader(initialFragment, initialArguments);
+ } else if (!mSinglePane && mHeaders.size() > 0) {
+ switchToHeader(onGetInitialHeader());
}
}
- // The default configuration is to only show the list view. Adjust
- // visibility for other configurations.
- if (initialFragment != null && mSinglePane) {
- // Single pane, showing just a prefs fragment.
- findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
- mPrefsContainer.setVisibility(View.VISIBLE);
- if (initialTitle != 0) {
- CharSequence initialTitleStr = getText(initialTitle);
- CharSequence initialShortTitleStr = initialShortTitle != 0
- ? getText(initialShortTitle) : null;
- showBreadCrumbs(initialTitleStr, initialShortTitleStr);
- }
- } else if (mHeaders.size() > 0) {
+ if (mHeaders.size() > 0) {
setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
mPreferenceHeaderRemoveEmptyIcon));
- if (!mSinglePane) {
- // Multi-pane.
- getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
- if (mCurHeader != null) {
- setSelectedHeader(mCurHeader);
- }
- mPrefsContainer.setVisibility(View.VISIBLE);
- }
- } else {
+ getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
+ }
+
+ if (mSinglePane && initialFragment != null && initialTitle != 0) {
+ CharSequence initialTitleStr = getText(initialTitle);
+ CharSequence initialShortTitleStr = initialShortTitle != 0
+ ? getText(initialShortTitle) : null;
+ showBreadCrumbs(initialTitleStr, initialShortTitleStr);
+ }
+
+ if (mHeaders.size() == 0 && initialFragment == null) {
// If there are no headers, we are in the old "just show a screen
// of preferences" mode.
setContentView(com.android.internal.R.layout.preference_list_content_single);
@@ -642,6 +620,25 @@ public abstract class PreferenceActivity extends ListActivity implements
mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
mPreferenceManager.setOnPreferenceTreeClickListener(this);
+ mHeadersContainer = null;
+ } else if (mSinglePane) {
+ // Single-pane so one of the header or prefs containers must be hidden.
+ if (initialFragment != null || mCurHeader != null) {
+ mHeadersContainer.setVisibility(View.GONE);
+ } else {
+ mPrefsContainer.setVisibility(View.GONE);
+ }
+
+ // This animates our manual transitions between headers and prefs panel in single-pane.
+ // It also comes last so we don't animate any initial layout changes done above.
+ ViewGroup container = (ViewGroup) findViewById(
+ com.android.internal.R.id.prefs_container);
+ container.setLayoutTransition(new LayoutTransition());
+ } else {
+ // Multi-pane
+ if (mHeaders.size() > 0 && mCurHeader != null) {
+ setSelectedHeader(mCurHeader);
+ }
}
// see if we should show Back/Next buttons
@@ -697,12 +694,25 @@ public abstract class PreferenceActivity extends ListActivity implements
}
}
+ @Override
+ public void onBackPressed() {
+ if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0
+ && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) {
+ mCurHeader = null;
+
+ mPrefsContainer.setVisibility(View.GONE);
+ mHeadersContainer.setVisibility(View.VISIBLE);
+ getListView().clearChoices();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
/**
* Returns true if this activity is currently showing the header list.
*/
public boolean hasHeaders() {
- return getListView().getVisibility() == View.VISIBLE
- && mPreferenceManager == null;
+ return mHeadersContainer != null && mHeadersContainer.getVisibility() == View.VISIBLE;
}
/**
@@ -718,7 +728,7 @@ public abstract class PreferenceActivity extends ListActivity implements
* and a preference fragment.
*/
public boolean isMultiPane() {
- return hasHeaders() && mPrefsContainer.getVisibility() == View.VISIBLE;
+ return !mSinglePane;
}
/**
@@ -820,14 +830,14 @@ public abstract class PreferenceActivity extends ListActivity implements
if (!"preference-headers".equals(nodeName)) {
throw new RuntimeException(
"XML document must start with <preference-headers> tag; found"
- + nodeName + " at " + parser.getPositionDescription());
+ + nodeName + " at " + parser.getPositionDescription());
}
Bundle curBundle = null;
final int outerDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
@@ -889,7 +899,7 @@ public abstract class PreferenceActivity extends ListActivity implements
final int innerDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
@@ -939,8 +949,9 @@ public abstract class PreferenceActivity extends ListActivity implements
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.KITKAT) {
throw new RuntimeException(
"Subclasses of PreferenceActivity must override isValidFragment(String)"
- + " to verify that the Fragment class is valid! " + this.getClass().getName()
- + " has not checked if fragment " + fragmentName + " is valid.");
+ + " to verify that the Fragment class is valid! "
+ + this.getClass().getName()
+ + " has not checked if fragment " + fragmentName + " is valid.");
} else {
return true;
}
@@ -1017,6 +1028,13 @@ public abstract class PreferenceActivity extends ListActivity implements
// Only call this if we didn't save the instance state for later.
// If we did save it, it will be restored when we bind the adapter.
super.onRestoreInstanceState(state);
+
+ if (!mSinglePane) {
+ // Multi-pane.
+ if (mCurHeader != null) {
+ setSelectedHeader(mCurHeader);
+ }
+ }
}
@Override
@@ -1061,18 +1079,7 @@ public abstract class PreferenceActivity extends ListActivity implements
*/
public void onHeaderClick(Header header, int position) {
if (header.fragment != null) {
- if (mSinglePane) {
- int titleRes = header.breadCrumbTitleRes;
- int shortTitleRes = header.breadCrumbShortTitleRes;
- if (titleRes == 0) {
- titleRes = header.titleRes;
- shortTitleRes = 0;
- }
- startWithFragment(header.fragment, header.fragmentArguments, null, 0,
- titleRes, shortTitleRes);
- } else {
- switchToHeader(header);
- }
+ switchToHeader(header);
} else if (header.intent != null) {
startActivity(header.intent);
}
@@ -1084,7 +1091,7 @@ public abstract class PreferenceActivity extends ListActivity implements
* the selected fragment. The default implementation constructs an Intent
* that re-launches the current activity with the appropriate arguments to
* display the fragment.
- *
+ *
* @param fragmentName The name of the fragment to display.
* @param args Optional arguments to supply to the fragment.
* @param titleRes Optional resource ID of title to show for this item.
@@ -1103,7 +1110,7 @@ public abstract class PreferenceActivity extends ListActivity implements
intent.putExtra(EXTRA_NO_HEADERS, true);
return intent;
}
-
+
/**
* Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
* but uses a 0 titleRes.
@@ -1223,11 +1230,21 @@ public abstract class PreferenceActivity extends ListActivity implements
throw new IllegalArgumentException("Invalid fragment for this activity: "
+ fragmentName);
}
+
Fragment f = Fragment.instantiate(this, fragmentName, args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+ transaction.setTransition(mSinglePane
+ ? FragmentTransaction.TRANSIT_NONE
+ : FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.replace(com.android.internal.R.id.prefs, f);
transaction.commitAllowingStateLoss();
+
+ if (mSinglePane && mPrefsContainer.getVisibility() == View.GONE) {
+ // We are transitioning from headers to preferences panel in single-pane so we need
+ // to hide headers and show the prefs container.
+ mPrefsContainer.setVisibility(View.VISIBLE);
+ mHeadersContainer.setVisibility(View.GONE);
+ }
}
/**
@@ -1340,7 +1357,7 @@ public abstract class PreferenceActivity extends ListActivity implements
* be instantiated and placed in the appropriate pane. If running in
* single-pane mode, a new activity will be launched in which to show the
* fragment.
- *
+ *
* @param fragmentClass Full name of the class implementing the fragment.
* @param args Any desired arguments to supply to the fragment.
* @param titleRes Optional resource identifier of the title of this
@@ -1355,29 +1372,25 @@ public abstract class PreferenceActivity extends ListActivity implements
*/
public void startPreferencePanel(String fragmentClass, Bundle args, @StringRes int titleRes,
CharSequence titleText, Fragment resultTo, int resultRequestCode) {
- if (mSinglePane) {
- startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
- } else {
- Fragment f = Fragment.instantiate(this, fragmentClass, args);
- if (resultTo != null) {
- f.setTargetFragment(resultTo, resultRequestCode);
- }
- FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.replace(com.android.internal.R.id.prefs, f);
- if (titleRes != 0) {
- transaction.setBreadCrumbTitle(titleRes);
- } else if (titleText != null) {
- transaction.setBreadCrumbTitle(titleText);
- }
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
- transaction.addToBackStack(BACK_STACK_PREFS);
- transaction.commitAllowingStateLoss();
+ Fragment f = Fragment.instantiate(this, fragmentClass, args);
+ if (resultTo != null) {
+ f.setTargetFragment(resultTo, resultRequestCode);
}
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ transaction.replace(com.android.internal.R.id.prefs, f);
+ if (titleRes != 0) {
+ transaction.setBreadCrumbTitle(titleRes);
+ } else if (titleText != null) {
+ transaction.setBreadCrumbTitle(titleText);
+ }
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+ transaction.addToBackStack(BACK_STACK_PREFS);
+ transaction.commitAllowingStateLoss();
}
/**
* Called by a preference panel fragment to finish itself.
- *
+ *
* @param caller The fragment that is asking to be finished.
* @param resultCode Optional result code to send back to the original
* launching fragment.
@@ -1385,21 +1398,16 @@ public abstract class PreferenceActivity extends ListActivity implements
* launching fragment.
*/
public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
- if (mSinglePane) {
- setResult(resultCode, resultData);
- finish();
- } else {
- // XXX be smarter about popping the stack.
- onBackPressed();
- if (caller != null) {
- if (caller.getTargetFragment() != null) {
- caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
- resultCode, resultData);
- }
+ // TODO: be smarter about popping the stack.
+ onBackPressed();
+ if (caller != null) {
+ if (caller.getTargetFragment() != null) {
+ caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
+ resultCode, resultData);
}
}
}
-
+
@Override
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(),
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index f17506b98a2b..f135b26fc5df 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -29,14 +29,14 @@ import android.util.AttributeSet;
* A container for multiple
* {@link Preference} objects. It is a base class for Preference objects that are
* parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}.
- *
+ *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For information about building a settings UI with Preferences,
* read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
* guide.</p>
* </div>
- *
+ *
* @attr ref android.R.styleable#PreferenceGroup_orderingFromXml
*/
public abstract class PreferenceGroup extends Preference implements GenericInflater.Parent<Preference> {
@@ -80,7 +80,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
* <p>
* If this is called after preferences are added, they will not be
* re-ordered in the order they were added, hence call this method early on.
- *
+ *
* @param orderingAsAdded Whether to order according to the order added.
* @see Preference#setOrder(int)
*/
@@ -90,7 +90,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
/**
* Whether this group is ordering preferences in the order they are added.
- *
+ *
* @return Whether this group orders based on the order the children are added.
* @see #setOrderingAsAdded(boolean)
*/
@@ -115,7 +115,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
/**
* Returns the {@link Preference} at a particular index.
- *
+ *
* @param index The index of the {@link Preference} to retrieve.
* @return The {@link Preference}.
*/
@@ -126,7 +126,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
/**
* Adds a {@link Preference} at the correct position based on the
* preference's order.
- *
+ *
* @param preference The preference to add.
* @return Whether the preference is now in this group.
*/
@@ -135,7 +135,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
// Exists
return true;
}
-
+
if (preference.getOrder() == Preference.DEFAULT_ORDER) {
if (mOrderingAsAdded) {
preference.setOrder(mCurrentPreferenceOrder++);
@@ -161,11 +161,12 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
}
preference.onAttachedToHierarchy(getPreferenceManager());
-
+ preference.assignParent(this);
+
if (mAttachedToActivity) {
preference.onAttachedToActivity();
}
-
+
notifyHierarchyChanged();
return true;
@@ -173,7 +174,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
/**
* Removes a {@link Preference} from this group.
- *
+ *
* @param preference The preference to remove.
* @return Whether the preference was found and removed.
*/
@@ -186,10 +187,13 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
private boolean removePreferenceInt(Preference preference) {
synchronized(this) {
preference.onPrepareForRemoval();
+ if (preference.getParent() == this) {
+ preference.assignParent(null);
+ }
return mPreferenceList.remove(preference);
}
}
-
+
/**
* Removes all {@link Preference Preferences} from this group.
*/
@@ -202,10 +206,10 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
}
notifyHierarchyChanged();
}
-
+
/**
* Prepares a {@link Preference} to be added to the group.
- *
+ *
* @param preference The preference to add.
* @return Whether to allow adding the preference (true), or not (false).
*/
@@ -223,7 +227,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
* <p>
* This will recursively search for the preference into children that are
* also {@link PreferenceGroup PreferenceGroups}.
- *
+ *
* @param key The key of the preference to retrieve.
* @return The {@link Preference} with the key, or null.
*/
@@ -239,7 +243,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
if (curKey != null && curKey.equals(key)) {
return preference;
}
-
+
if (preference instanceof PreferenceGroup) {
final Preference returnedPreference = ((PreferenceGroup)preference)
.findPreference(key);
@@ -255,14 +259,14 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
/**
* Whether this preference group should be shown on the same screen as its
* contained preferences.
- *
+ *
* @return True if the contained preferences should be shown on the same
* screen as this preference.
*/
protected boolean isOnSameScreenAsChildren() {
return true;
}
-
+
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
@@ -270,7 +274,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
// Mark as attached so if a preference is later added to this group, we
// can tell it we are already attached
mAttachedToActivity = true;
-
+
// Dispatch to all contained preferences
final int preferenceCount = getPreferenceCount();
for (int i = 0; i < preferenceCount; i++) {
@@ -281,7 +285,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
@Override
protected void onPrepareForRemoval() {
super.onPrepareForRemoval();
-
+
// We won't be attached to the activity anymore
mAttachedToActivity = false;
}
@@ -297,7 +301,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
getPreference(i).onParentChanged(this, disableDependents);
}
}
-
+
void sortPreferences() {
synchronized (this) {
Collections.sort(mPreferenceList);
@@ -314,7 +318,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
getPreference(i).dispatchSaveInstanceState(container);
}
}
-
+
@Override
protected void dispatchRestoreInstanceState(Bundle container) {
super.dispatchRestoreInstanceState(container);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1b512c69901f..a0d16bc2d9b0 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,6 +19,7 @@ package android.provider;
import android.accounts.Account;
import android.annotation.SystemApi;
import android.app.Activity;
+import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -30,6 +31,7 @@ import android.content.CursorEntityIterator;
import android.content.Entity;
import android.content.EntityIterator;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
@@ -8170,29 +8172,11 @@ public final class ContactsContract {
/**
* The content:// style URI for this table. Requests to this URI can be
* performed on the UI thread because they are always unblocking.
- *
- * <p>Note when you listen on this URI (or any other sub-URIs), you'll be notified for
- * regular contact change notifications too, which will be sent on the root URI.
- * If you only want to be notified for provider status change notifications, listen on
- * {@link #STATUS_CHANGE_NOTIFICATION_CONTENT_URI} instead.
*/
public static final Uri CONTENT_URI =
Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
/**
- * URI to listen to provider status changes without listening to regular
- * contact changes. If a client only wants to monitor {@link ProviderStatus} with
- * {@link android.app.job.JobScheduler}, then this URI should be used instead of
- * {@link #CONTENT_URI}, because a job on {@link #CONTENT_URI} will also be invoked
- * when contacts are changed.
- *
- * <p>Note this URI cannot be queried. A query should be always made on
- * {@link #CONTENT_URI}.
- */
- public static final Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI =
- Uri.parse("content://com.android.contacts.provider_status");
-
- /**
* The MIME-type of {@link #CONTENT_URI} providing a directory of
* settings.
*/
@@ -8794,13 +8778,13 @@ public final class ContactsContract {
* This is the intent that is fired when the contacts database is created. <p> The
* READ_CONTACT permission is required to receive these broadcasts.
*
- * <p>As of O, this broadcast will no longer be sent. Applications can use
- * use {@link android.app.job.JobScheduler} to monitor
- * {@link ProviderStatus#STATUS_CHANGE_NOTIFICATION_CONTENT_URI}, and read
- * {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to get when
- * the contacts database was initialized.
+ * <p>Because this is an implicit broadcast, apps targeting Android O will no longer
+ * receive this broadcast via a manifest broadcast receiver. (Broadcast receivers
+ * registered at runtime with
+ * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)} will still receive it.)
+ * Instead, an app can use {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to see if the
+ * contacts database has been initialized when it starts.
*/
- @Deprecated
public static final String CONTACTS_DATABASE_CREATED =
"android.provider.Contacts.DATABASE_CREATED";
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 6170eb48444d..f5e558a01c56 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -678,8 +678,18 @@ public abstract class DocumentsProvider extends ContentProvider {
throw new UnsupportedOperationException("Pre-Android-O query format not supported.");
}
+ /**
+ * WARNING: Sub-classes should not override this method. This method is non-final
+ * solely for the purposes of backwards compatibility.
+ *
+ * @see #queryChildDocuments(String, String[], Bundle),
+ * {@link #queryDocument(String, String[])},
+ * {@link #queryRecentDocuments(String, String[])},
+ * {@link #queryRoots(String[])}, and
+ * {@link #querySearchDocuments(String, String, String[])}.
+ */
@Override
- public final Cursor query(Uri uri, String[] projection, String selection,
+ public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
// As of Android-O, ContentProvider#query (w/ bundle arg) is the primary
// transport method. We override that, and don't ever delegate to this metohd.
diff --git a/core/java/android/provider/OneTimeUseBuilder.java b/core/java/android/provider/OneTimeUseBuilder.java
new file mode 100644
index 000000000000..682e9c747322
--- /dev/null
+++ b/core/java/android/provider/OneTimeUseBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.provider;
+
+/**
+ * A builder that facilitates prohibiting its use after an instance was created with it.
+ *
+ * Suggested usage:
+ * call {@link #checkNotUsed} in each setter, and {@link #markUsed} in {@link #build}
+ *
+ * @param <T> Type of object being built
+ * @hide
+ */
+public abstract class OneTimeUseBuilder<T> {
+ private boolean used = false;
+
+ protected void markUsed() {
+ checkNotUsed();
+ used = true;
+ }
+
+ protected void checkNotUsed() {
+ if (used) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+
+ /**
+ * Builds the instance
+ *
+ * Once this method is called, this builder should no longer be used. Any subsequent calls to a
+ * setter or {@code build()} will throw an exception
+ */
+ public abstract T build();
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e3da337d9e6a..2936dfb59184 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -30,6 +30,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
+import android.app.NotificationChannel;
import android.app.SearchManager;
import android.app.WallpaperManager;
import android.content.ComponentName;
@@ -58,6 +59,7 @@ import android.os.IBinder;
import android.os.LocaleList;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
@@ -162,13 +164,13 @@ public final class Settings {
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
* <p>
- * Input: {@link ConnectivityManager.EXTRA_TETHER_TYPE} should be included to specify which type
- * of tethering should be checked. {@link ConnectivityManager.EXTRA_PROVISION_CALLBACK} should
+ * Input: {@link ConnectivityManager#EXTRA_TETHER_TYPE} should be included to specify which type
+ * of tethering should be checked. {@link ConnectivityManager#EXTRA_PROVISION_CALLBACK} should
* contain a {@link ResultReceiver} which will be called back with a tether result code.
* <p>
* Output: The result of the provisioning check.
- * {@link ConnectivityManager.TETHER_ERROR_NO_ERROR} if successful,
- * {@link ConnectivityManager.TETHER_ERROR_PROVISION_FAILED} for failure.
+ * {@link ConnectivityManager#TETHER_ERROR_NO_ERROR} if successful,
+ * {@link ConnectivityManager#TETHER_ERROR_PROVISION_FAILED} for failure.
*
* @hide
*/
@@ -295,7 +297,6 @@ public final class Settings {
* Input: Nothing.
* <p>
* Output: Nothing.
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_EXTERNAL_SOURCES =
@@ -1273,14 +1274,48 @@ public final class Settings {
/**
* Activity Action: Show notification settings for a single app.
- *
+ * <p>
+ * Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel to display.
+ * Input: Optionally, {@link #EXTRA_CHANNEL_ID}, to highlight that channel.
+ * <p>
+ * Output: Nothing.
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APP_NOTIFICATION_SETTINGS
= "android.settings.APP_NOTIFICATION_SETTINGS";
/**
+ * Activity Action: Show notification settings for a single {@link NotificationChannel}.
+ * <p>
+ * Must be called from an activity.
+ * <p>
+ * Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel to display.
+ * Input: {@link #EXTRA_CHANNEL_ID}, the id of the channel to display.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CHANNEL_NOTIFICATION_SETTINGS
+ = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
+
+ /**
+ * Activity Extra: The package owner of the notification channel settings to display.
+ * <p>
+ * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
+ */
+ public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
+
+ /**
+ * Activity Extra: The {@link NotificationChannel#getId()} of the notification channel settings
+ * to display.
+ * <p>
+ * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
+ */
+ public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
+
+ /**
* Activity Action: Show notification redaction settings.
*
* @hide
@@ -1290,7 +1325,6 @@ public final class Settings {
= "android.settings.ACTION_APP_NOTIFICATION_REDACTION";
/** @hide */ public static final String EXTRA_APP_UID = "app_uid";
- /** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
/**
* Activity Action: Show a dialog with disabled by policy message.
@@ -4094,6 +4128,7 @@ public final class Settings {
EPHEMERAL_SETTINGS.add(FONT_SCALE);
EPHEMERAL_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
EPHEMERAL_SETTINGS.add(TIME_12_24);
+ EPHEMERAL_SETTINGS.add(SOUND_EFFECTS_ENABLED);
}
/**
@@ -5161,6 +5196,9 @@ public final class Settings {
*
* <p>1 = permit app installation via the system package installer intent
* <p>0 = do not allow use of the package installer
+ * @deprecated Starting from {@link android.os.Build.VERSION_CODES#O}, apps should use
+ * {@link PackageManager#canRequestPackageInstalls()}
+ * @see PackageManager#canRequestPackageInstalls()
*/
public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -6683,12 +6721,6 @@ public final class Settings {
public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
/**
- * Whether brightness should automatically adjust based on twilight state.
- * @hide
- */
- public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
-
- /**
* Names of the service components that the current user has explicitly allowed to
* be a VR mode listener, separated by ':'.
*
@@ -7621,6 +7653,13 @@ public final class Settings {
public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
"location_background_throttle_interval_ms";
+ /**
+ * Packages that are whitelisted for background throttling (throttling will not be applied).
+ * @hide
+ */
+ public static final String LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST =
+ "location_background_throttle_package_whitelist";
+
/**
* Whether TV will switch to MHL port when a mobile device is plugged in.
* (0 = false, 1 = true)
@@ -8037,6 +8076,27 @@ public final class Settings {
public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
/**
+ * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
+ * overridden by the system based on device or application state. If null, the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ *
+ * @hide
+ */
+ public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
+ "network_metered_multipath_preference";
+
+ /**
+ * The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of
+ * colon-delimited key-value pairs. The key is the badging enum value defined in
+ * android.net.ScoredNetwork and the value is the minimum sustained network throughput in
+ * kbps required for the badge. For example: "10:3000,20:5000,30:25000"
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
+
+ /**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
* @hide
@@ -8141,6 +8201,14 @@ public final class Settings {
public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
/**
+ * Value to specify whether network quality scores and badging should be shown in the UI.
+ *
+ * Type: int (0 for false, 1 for true)
+ * @hide
+ */
+ public static final String NETWORK_SCORING_UI_ENABLED = "network_scoring_ui_enabled";
+
+ /**
* Value to specify if network recommendations from
* {@link com.android.server.NetworkScoreService} are enabled.
*
@@ -8755,6 +8823,26 @@ public final class Settings {
BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
/**
+ * Activity manager specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "enforce_bg_check=true,max_cached_processes=24"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * enforce_bg_check (boolean)
+ * max_cached_processes (int)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.am.ActivityManagerConstants
+ */
+ public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
+
+ /**
* Device Idle (Doze) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
@@ -8820,6 +8908,25 @@ public final class Settings {
public static final String APP_IDLE_CONSTANTS = "app_idle_constants";
/**
+ * Power manager specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "no_cached_wake_locks=1"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * no_cached_wake_locks (boolean)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.power.PowerManagerConstants
+ */
+ public static final String POWER_MANAGER_CONSTANTS = "power_manager_constants";
+
+ /**
* Alarm manager specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
@@ -9368,7 +9475,7 @@ public final class Settings {
/**
* WFC mode on roaming network.
* <p>
- * Type: int - see {@link WFC_IMS_MODE} for values
+ * Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
*/
@@ -9412,13 +9519,13 @@ public final class Settings {
public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
/**
- * The duration for caching uninstalled ephemeral apps.
+ * The duration for caching uninstalled instant apps.
* <p>
* Type: long
* @hide
*/
- public static final String UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS =
- "uninstalled_ephemeral_app_cache_duration_millis";
+ public static final String UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS =
+ "uninstalled_instant_app_cache_duration_millis";
/**
* Allows switching users when system user is locked.
@@ -9490,6 +9597,14 @@ public final class Settings {
public static final String CONTACTS_DATABASE_WAL_ENABLED = "contacts_database_wal_enabled";
/**
+ * Flag to enable the link to location permissions in location setting. Set to 0 to disable.
+ *
+ * @hide
+ */
+ public static final String LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED =
+ "location_settings_link_to_permissions_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -9514,10 +9629,11 @@ public final class Settings {
DOCK_SOUNDS_ENABLED,
CHARGING_SOUNDS_ENABLED,
USB_MASS_STORAGE_ENABLED,
+ NETWORK_RECOMMENDATIONS_ENABLED,
+ CURATE_SAVED_OPEN_NETWORKS,
+ WIFI_WAKEUP_ENABLED,
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
- WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
- WIFI_NUM_OPEN_NETWORKS_KEPT,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
DOCK_AUDIO_MEDIA_ENABLED,
@@ -10039,6 +10155,12 @@ public final class Settings {
* @hide
*/
public static final String WARNING_TEMPERATURE = "warning_temperature";
+
+ /**
+ * Whether the diskstats logging task is enabled/disabled.
+ * @hide
+ */
+ public static final String ENABLE_DISKSTATS_LOGGING = "enable_diskstats_logging";
}
/**
diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java
new file mode 100644
index 000000000000..f242d7936776
--- /dev/null
+++ b/core/java/android/provider/SettingsStringUtil.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.provider;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.text.TextUtils;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.function.Function;
+
+/**
+ * Utilities for dealing with {@link String} values in {@link Settings}
+ *
+ * @hide
+ */
+public class SettingsStringUtil {
+ private SettingsStringUtil() {}
+
+ public static final String DELIMITER = ":";
+
+ /**
+ * A {@link HashSet} of items, that uses a common convention of setting string
+ * serialization/deserialization of separating multiple items with {@link #DELIMITER}
+ */
+ public static abstract class ColonDelimitedSet<T> extends HashSet<T> {
+
+ public ColonDelimitedSet(String colonSeparatedItems) {
+ for (String cn :
+ TextUtils.split(TextUtils.emptyIfNull(colonSeparatedItems), DELIMITER)) {
+ add(itemFromString(cn));
+ }
+ }
+
+ protected abstract T itemFromString(String s);
+ protected String itemToString(T item) {
+ return String.valueOf(item);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ Iterator<T> it = iterator();
+ if (it.hasNext()) {
+ sb.append(it.next());
+ while (it.hasNext()) {
+ sb.append(DELIMITER);
+ sb.append(itemToString(it.next()));
+ }
+ }
+ return sb.toString();
+ }
+
+
+ public static class OfStrings extends ColonDelimitedSet<String> {
+ public OfStrings(String colonSeparatedItems) {
+ super(colonSeparatedItems);
+ }
+
+ @Override
+ protected String itemFromString(String s) {
+ return s;
+ }
+
+ public static String add(String delimitedElements, String element) {
+ final ColonDelimitedSet<String> set
+ = new ColonDelimitedSet.OfStrings(delimitedElements);
+ if (set.contains(element)) {
+ return delimitedElements;
+ }
+ set.add(element);
+ return set.toString();
+ }
+
+ public static String remove(String delimitedElements, String element) {
+ final ColonDelimitedSet<String> set
+ = new ColonDelimitedSet.OfStrings(delimitedElements);
+ if (!set.contains(element)) {
+ return delimitedElements;
+ }
+ set.remove(element);
+ return set.toString();
+ }
+
+ public static boolean contains(String delimitedElements, String element) {
+ final String[] elements = TextUtils.split(delimitedElements, DELIMITER);
+ return ArrayUtils.indexOf(elements, element) != -1;
+ }
+ }
+ }
+
+ public static class ComponentNameSet extends ColonDelimitedSet<ComponentName> {
+ public ComponentNameSet(String colonSeparatedPackageNames) {
+ super(colonSeparatedPackageNames);
+ }
+
+ @Override
+ protected ComponentName itemFromString(String s) {
+ return ComponentName.unflattenFromString(s);
+ }
+
+ @Override
+ protected String itemToString(ComponentName item) {
+ return item.flattenToString();
+ }
+
+ public static String add(String delimitedElements, ComponentName element) {
+ final ComponentNameSet set = new ComponentNameSet(delimitedElements);
+ if (set.contains(element)) {
+ return delimitedElements;
+ }
+ set.add(element);
+ return set.toString();
+ }
+
+ public static String remove(String delimitedElements, ComponentName element) {
+ final ComponentNameSet set = new ComponentNameSet(delimitedElements);
+ if (!set.contains(element)) {
+ return delimitedElements;
+ }
+ set.remove(element);
+ return set.toString();
+ }
+
+ public static boolean contains(String delimitedElements, ComponentName element) {
+ return ColonDelimitedSet.OfStrings.contains(
+ delimitedElements, element.flattenToString());
+ }
+ }
+
+ public static class SettingStringHelper {
+ private final ContentResolver mContentResolver;
+ private final String mSettingName;
+ private final int mUserId;
+
+ public SettingStringHelper(ContentResolver contentResolver, String name, int userId) {
+ mContentResolver = contentResolver;
+ mUserId = userId;
+ mSettingName = name;
+ }
+
+ public String read() {
+ return Settings.Secure.getStringForUser(
+ mContentResolver, mSettingName, mUserId);
+ }
+
+ public boolean write(String value) {
+ return Settings.Secure.putStringForUser(
+ mContentResolver, mSettingName, value, mUserId);
+ }
+
+ public boolean modify(Function<String, String> change) {
+ return write(change.apply(read()));
+ }
+ }
+}
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index e48a0d08de7d..a8b094eab0a2 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -284,8 +284,6 @@ public class VoicemailContract {
* not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String BACKED_UP = "backed_up";
@@ -294,8 +292,6 @@ public class VoicemailContract {
* restored, 0 if not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String RESTORED = "restored";
@@ -305,19 +301,19 @@ public class VoicemailContract {
* if not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String ARCHIVED = "archived";
/**
* Flag to indicate the voicemail is a OMTP voicemail handled by the {@link
* android.telephony.VisualVoicemailService}. The UI should only show OMTP voicemails from
- * the current visual voicemail package.
+ * the current visual voicemail package. For example, the selection could be
+ * {@code WHERE (IS_OMTP_VOICEMAIL == 0) OR ( IS_OMTP_VOICEMAIL == 1 AND SOURCE_PACKAGE ==
+ * "current.vvm.package")}
*
* <P>Type: INTEGER (boolean)</P>
*
- * @hide
+ * @see android.telephony.TelephonyManager#getVisualVoicemailPackageName
*/
public static final String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 22f1bedc6072..5461e6b6d699 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -83,6 +83,12 @@ public final class KeymasterDefs {
public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
public static final int KM_TAG_UNIQUE_ID = KM_BYTES | 707;
public static final int KM_TAG_ATTESTATION_CHALLENGE = KM_BYTES | 708;
+ public static final int KM_TAG_ATTESTATION_ID_BRAND = KM_BYTES | 710;
+ public static final int KM_TAG_ATTESTATION_ID_DEVICE = KM_BYTES | 711;
+ public static final int KM_TAG_ATTESTATION_ID_PRODUCT = KM_BYTES | 712;
+ public static final int KM_TAG_ATTESTATION_ID_SERIAL = KM_BYTES | 713;
+ public static final int KM_TAG_ATTESTATION_ID_IMEI = KM_BYTES | 714;
+ public static final int KM_TAG_ATTESTATION_ID_MEID = KM_BYTES | 715;
public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
public static final int KM_TAG_NONCE = KM_BYTES | 1001;
@@ -204,6 +210,7 @@ public final class KeymasterDefs {
public static final int KM_ERROR_INVALID_MAC_LENGTH = -57;
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
+ public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -249,6 +256,7 @@ public final class KeymasterDefs {
"Caller-provided IV not permitted");
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
"Invalid MAC or authentication tag length");
+ sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java
index 0f2994d37681..8fcd5ab55e6a 100644
--- a/core/java/android/security/net/config/ManifestConfigSource.java
+++ b/core/java/android/security/net/config/ManifestConfigSource.java
@@ -32,7 +32,7 @@ public class ManifestConfigSource implements ConfigSource {
private final int mApplicationInfoFlags;
private final int mTargetSdkVersion;
private final int mConfigResourceId;
- private final boolean mEphemeralApp;
+ private final int mTargetSandboxVesrsion;
private ConfigSource mConfigSource;
@@ -43,7 +43,7 @@ public class ManifestConfigSource implements ConfigSource {
mApplicationInfoFlags = info.flags;
mTargetSdkVersion = info.targetSdkVersion;
mConfigResourceId = info.networkSecurityConfigRes;
- mEphemeralApp = info.isEphemeralApp();
+ mTargetSandboxVesrsion = info.targetSandboxVersion;
}
@Override
@@ -71,7 +71,7 @@ public class ManifestConfigSource implements ConfigSource {
+ " debugBuild: " + debugBuild);
}
source = new XmlConfigSource(mContext, mConfigResourceId, debugBuild,
- mTargetSdkVersion, mEphemeralApp);
+ mTargetSdkVersion, mTargetSandboxVesrsion);
} else {
if (DBG) {
Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
@@ -80,9 +80,9 @@ public class ManifestConfigSource implements ConfigSource {
// should use the network security config.
boolean usesCleartextTraffic =
(mApplicationInfoFlags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0
- && !mEphemeralApp;
+ && mTargetSandboxVesrsion < 2;
source = new DefaultConfigSource(usesCleartextTraffic, mTargetSdkVersion,
- mEphemeralApp);
+ mTargetSandboxVesrsion);
}
mConfigSource = source;
return mConfigSource;
@@ -94,9 +94,9 @@ public class ManifestConfigSource implements ConfigSource {
private final NetworkSecurityConfig mDefaultConfig;
public DefaultConfigSource(boolean usesCleartextTraffic, int targetSdkVersion,
- boolean ephemeralApp) {
+ int targetSandboxVesrsion) {
mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(targetSdkVersion,
- ephemeralApp)
+ targetSandboxVesrsion)
.setCleartextTrafficPermitted(usesCleartextTraffic)
.build();
}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 7923702e3656..789fc273b965 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -175,13 +175,14 @@ public final class NetworkSecurityConfig {
*
* @hide
*/
- public static final Builder getDefaultBuilder(int targetSdkVersion, boolean ephemeralApp) {
+ public static final Builder getDefaultBuilder(int targetSdkVersion, int targetSandboxVesrsion) {
Builder builder = new Builder()
- .setCleartextTrafficPermitted(!ephemeralApp)
.setHstsEnforced(DEFAULT_HSTS_ENFORCED)
// System certificate store, does not bypass static pins.
.addCertificatesEntryRef(
new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
+ final boolean cleartextTrafficPermitted = targetSandboxVesrsion < 2;
+ builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
// Applications targeting N and above must opt in into trusting the user added certificate
// store.
if (targetSdkVersion <= Build.VERSION_CODES.M) {
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 38fe6b8466f5..a111fbce183c 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -37,7 +37,7 @@ public class XmlConfigSource implements ConfigSource {
private final int mResourceId;
private final boolean mDebugBuild;
private final int mTargetSdkVersion;
- private final boolean mEphemeralApp;
+ private final int mTargetSandboxVesrsion;
private boolean mInitialized;
private NetworkSecurityConfig mDefaultConfig;
@@ -57,16 +57,16 @@ public class XmlConfigSource implements ConfigSource {
@VisibleForTesting
public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
int targetSdkVersion) {
- this(context, resourceId, debugBuild, targetSdkVersion, false);
+ this(context, resourceId, debugBuild, targetSdkVersion, 1 /*targetSandboxVersion*/);
}
public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
- int targetSdkVersion, boolean ephemeralApp) {
+ int targetSdkVersion, int targetSandboxVesrsion) {
mResourceId = resourceId;
mContext = context;
mDebugBuild = debugBuild;
mTargetSdkVersion = targetSdkVersion;
- mEphemeralApp = ephemeralApp;
+ mTargetSandboxVesrsion = targetSandboxVesrsion;
}
public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
@@ -365,7 +365,7 @@ public class XmlConfigSource implements ConfigSource {
// Use the platform default as the parent of the base config for any values not provided
// there. If there is no base config use the platform default.
NetworkSecurityConfig.Builder platformDefaultBuilder =
- NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion, mEphemeralApp);
+ NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion, mTargetSandboxVesrsion);
addDebugAnchorsIfNeeded(debugConfigBuilder, platformDefaultBuilder);
if (baseConfigBuilder != null) {
baseConfigBuilder.setParent(platformDefaultBuilder);
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index 805d8e5f1a69..ab80aa3e23b8 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,11 +15,10 @@
*/
package android.service.autofill;
-import static android.service.voice.VoiceInteractionSession.KEY_FLAGS;
-import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import com.android.internal.os.HandlerCaller;
import android.annotation.SdkConstant;
import android.app.Activity;
import android.app.Service;
@@ -28,19 +27,15 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
-import android.view.autofill.AutoFillId;
import android.view.autofill.FillResponse;
-import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
-// TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
-// life-cycle (and how state could be maintained on server-side) is well documented.
+//TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
+//life-cycle (and how state could be maintained on server-side) is well documented.
/**
* Top-level service of the current auto-fill service for a given user.
@@ -48,9 +43,7 @@ import com.android.internal.os.SomeArgs;
* <p>Apps providing auto-fill capabilities must extend this service.
*/
public abstract class AutoFillService extends Service {
-
- static final String TAG = "AutoFillService";
- static final boolean DEBUG = true; // TODO: set to false once stable
+ private static final String TAG = "AutoFillService";
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -74,45 +67,40 @@ public abstract class AutoFillService extends Service {
*/
public static final String SERVICE_META_DATA = "android.autofill";
- // Internal bundle keys.
- /** @hide */ public static final String KEY_CALLBACK = "callback";
- /** @hide */ public static final String KEY_SAVABLE_IDS = "savable_ids";
-
- // Prefix for public bundle keys.
- private static final String KEY_PREFIX = "android.service.autofill.extra.";
-
- /**
- * Key of the {@link Bundle} passed to methods such as
- * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
- * containing the extras set by
- * {@link android.view.autofill.FillResponse.Builder#setExtras(Bundle)}.
- */
- public static final String EXTRA_RESPONSE_EXTRAS = KEY_PREFIX + "RESPONSE_EXTRAS";
-
- /**
- * Key of the {@link Bundle} passed to methods such as
- * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
- * containing the extras set by
- * {@link android.view.autofill.Dataset.Builder#setExtras(Bundle)}.
- */
- public static final String EXTRA_DATASET_EXTRAS = KEY_PREFIX + "DATASET_EXTRAS";
+ // Internal extras
+ /** @hide */
+ public static final String EXTRA_ACTIVITY_TOKEN =
+ "android.service.autofill.EXTRA_ACTIVITY_TOKEN";
// Handler messages.
private static final int MSG_CONNECT = 1;
- private static final int MSG_AUTO_FILL_ACTIVITY = 2;
- private static final int MSG_DISCONNECT = 3;
+ private static final int MSG_DISCONNECT = 2;
+ private static final int MSG_ON_FILL_REQUEST = 3;
+ private static final int MSG_ON_SAVE_REQUEST = 4;
private final IAutoFillService mInterface = new IAutoFillService.Stub() {
-
@Override
- public void autoFill(AssistStructure structure, IAutoFillServerCallback callback,
- Bundle extras, int flags) {
- mHandlerCaller
- .obtainMessageIOOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, extras, callback)
+ public void onFillRequest(AssistStructure structure, Bundle extras,
+ IFillCallback callback) {
+ ICancellationSignal transport = CancellationSignal.createTransport();
+ try {
+ callback.onCancellable(transport);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mHandlerCaller.obtainMessageOOOO(MSG_ON_FILL_REQUEST, structure,
+ CancellationSignal.fromTransport(transport), extras, callback)
.sendToTarget();
}
@Override
+ public void onSaveRequest(AssistStructure structure, Bundle extras,
+ ISaveCallback callback) {
+ mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
+ extras, callback).sendToTarget();
+ }
+
+ @Override
public void onConnected() {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT));
}
@@ -123,28 +111,35 @@ public abstract class AutoFillService extends Service {
}
};
- private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
-
- @Override
- public void executeMessage(Message msg) {
- switch (msg.what) {
- case MSG_CONNECT: {
- onConnected();
- break;
- } case MSG_AUTO_FILL_ACTIVITY: {
- final SomeArgs args = (SomeArgs) msg.obj;
- final int flags = msg.arg1;
- final AssistStructure structure = (AssistStructure) args.arg1;
- final Bundle extras = (Bundle) args.arg2;
- final IAutoFillServerCallback callback = (IAutoFillServerCallback) args.arg3;
- requestAutoFill(callback, structure, extras, flags);
- break;
- } case MSG_DISCONNECT: {
- onDisconnected();
- break;
- } default: {
- Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
- }
+ private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+ switch (msg.what) {
+ case MSG_CONNECT: {
+ onConnected();
+ break;
+ } case MSG_ON_FILL_REQUEST: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final AssistStructure structure = (AssistStructure) args.arg1;
+ final CancellationSignal cancellation = (CancellationSignal) args.arg2;
+ final Bundle extras = (Bundle) args.arg3;
+ final IFillCallback callback = (IFillCallback) args.arg4;
+ final FillCallback fillCallback = new FillCallback(callback);
+ args.recycle();
+ onFillRequest(structure, extras, cancellation, fillCallback);
+ break;
+ } case MSG_ON_SAVE_REQUEST: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final AssistStructure structure = (AssistStructure) args.arg1;
+ final Bundle extras = (Bundle) args.arg2;
+ final ISaveCallback callback = (ISaveCallback) args.arg3;
+ final SaveCallback saveCallback = new SaveCallback(callback);
+ args.recycle();
+ onSaveRequest(structure, extras, saveCallback);
+ break;
+ } case MSG_DISCONNECT: {
+ onDisconnected();
+ break;
+ } default: {
+ Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
}
}
};
@@ -159,7 +154,6 @@ public abstract class AutoFillService extends Service {
@Override
public void onCreate() {
super.onCreate();
-
mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
}
@@ -178,7 +172,7 @@ public abstract class AutoFillService extends Service {
* <p>You should generally do initialization here rather than in {@link #onCreate}.
*/
public void onConnected() {
- if (DEBUG) Log.d(TAG, "onConnected()");
+
}
/**
@@ -190,48 +184,36 @@ public abstract class AutoFillService extends Service {
* to notify the result of the request.
*
* @param structure {@link Activity}'s view structure.
- * @param data bundle containing additional arguments set by the Android system (currently none)
- * or data passed by the service on previous calls to fullfill other sections of this activity
- * (see {@link FillResponse} Javadoc for examples of multiple-sections requests).
- * @param cancellationSignal signal for observing cancel requests.
+ * @param data bundle containing data passed by the service on previous calls to fill.
+ * This bundle allows your service to keep state between fill and save requests
+ * as well as when filling different sections of the UI as the system will try to
+ * aggressively unbind from the service to conserve resources. See {@link FillResponse}
+ * Javadoc for examples of multiple-sections requests.
+ * @param cancellationSignal signal for observing cancellation requests. The system will use
+ * this to notify you that the fill result is no longer needed and you should stop
+ * handling this fill request in order to save resources.
* @param callback object used to notify the result of the request.
*/
- public abstract void onFillRequest(AssistStructure structure,
- Bundle data, CancellationSignal cancellationSignal, FillCallback callback);
+ public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
/**
* Called when user requests service to save the fields of an {@link Activity}.
*
* <p>Service must call one of the {@link SaveCallback} methods (like
- * {@link SaveCallback#onSuccess(AutoFillId[])} or {@link SaveCallback#onFailure(CharSequence)})
+ * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
* to notify the result of the request.
*
* @param structure {@link Activity}'s view structure.
- * @param data bundle containing additional arguments set by the Android system (currently none)
- * or data passed by the service in the {@link FillResponse} that originated this call.
- * @param cancellationSignal signal for observing cancel requests.
+ * @param data bundle containing data passed by the service on previous calls to fill.
+ * This bundle allows your service to keep state between fill and save requests
+ * as well as when filling different sections of the UI as the system will try to
+ * aggressively unbind from the service to conserve resources. See {@link FillResponse}
+ * Javadoc for examples of multiple-sections requests.
* @param callback object used to notify the result of the request.
*/
- public abstract void onSaveRequest(AssistStructure structure,
- Bundle data, CancellationSignal cancellationSignal, SaveCallback callback);
-
- private void requestAutoFill(IAutoFillServerCallback callback, AssistStructure structure,
- Bundle data, int flags) {
- switch (flags) {
- case AUTO_FILL_FLAG_TYPE_FILL:
- final FillCallback fillCallback = new FillCallback(callback);
- // TODO(b/33197203): hook up the cancelationSignal
- onFillRequest(structure, data, new CancellationSignal(), fillCallback);
- break;
- case AUTO_FILL_FLAG_TYPE_SAVE:
- final SaveCallback saveCallback = new SaveCallback(callback);
- // TODO(b/33197203): hook up the cancelationSignal
- onSaveRequest(structure, data, new CancellationSignal(), saveCallback);
- break;
- default:
- Log.w(TAG, "invalid flag on requestAutoFill(): " + flags);
- }
- }
+ public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+ @NonNull SaveCallback callback);
/**
* Called when the Android system disconnects from the service.
@@ -239,6 +221,6 @@ public abstract class AutoFillService extends Service {
* <p> At this point this service may no longer be an active {@link AutoFillService}.
*/
public void onDisconnected() {
- if (DEBUG) Log.d(TAG, "onDisconnected()");
+
}
}
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
index ab86580f1f3b..985e32fcd966 100644
--- a/core/java/android/service/autofill/AutoFillServiceInfo.java
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -16,6 +16,7 @@
package android.service.autofill;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.ComponentName;
@@ -31,11 +32,18 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import com.android.internal.R;
+
import java.io.IOException;
-/** @hide */
+// TODO(b/33197203 , b/33802548): add CTS tests
+/**
+ * {@link ServiceInfo} and meta-data about an {@link AutoFillService}.
+ *
+ * @hide
+ */
public final class AutoFillServiceInfo {
- static final String TAG = "AutoFillServiceInfo";
+ private static final String TAG = "AutoFillServiceInfo";
private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -52,76 +60,81 @@ public final class AutoFillServiceInfo {
throw new PackageManager.NameNotFoundException(comp.toString());
}
- @Nullable
- private String mParseError;
+ @NonNull
+ private final ServiceInfo mServiceInfo;
@Nullable
- private ServiceInfo mServiceInfo;
- @Nullable
- private String mSettingsActivity;
+ private final String mSettingsActivity;
public AutoFillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
this(pm, getServiceInfoOrThrow(comp, userHandle));
}
- public AutoFillServiceInfo(PackageManager pm, ServiceInfo si)
- throws PackageManager.NameNotFoundException{
- if (si == null) {
- mParseError = "Service not available";
- return;
+ public AutoFillServiceInfo(PackageManager pm, ServiceInfo si) {
+ mServiceInfo = si;
+ final TypedArray metaDataArray = getMetaDataArray(pm, si);
+ if (metaDataArray != null) {
+ mSettingsActivity =
+ metaDataArray.getString(R.styleable.AutoFillService_settingsActivity);
+ metaDataArray.recycle();
+ } else {
+ mSettingsActivity = null;
}
+ }
+
+ /**
+ * Gets the meta-data as a TypedArray, or null if not provided, or throws if invalid.
+ */
+ @Nullable
+ private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) {
+ // Check for permissions.
if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
- mParseError = "Service does not require permission "
- + Manifest.permission.BIND_AUTO_FILL;
- return;
+ Log.e(TAG, "Service does not require permission " + Manifest.permission.BIND_AUTO_FILL);
+ return null;
}
- XmlResourceParser parser = null;
+ // Get the AutoFill metadata, if declared.
+ XmlResourceParser parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
+ if (parser == null) {
+ return null;
+ }
+
+ // Parse service info and get the <autofill-service> tag as an AttributeSet.
+ AttributeSet attrs;
try {
- parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
- if (parser == null) {
- mParseError = "No " + AutoFillService.SERVICE_META_DATA
- + " meta-data for " + si.packageName;
- return;
+ // Move the XML parser to the first tag.
+ try {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(TAG, "Error parsing auto fill service meta-data", e);
+ return null;
}
- Resources res = pm.getResourcesForApplication(si.applicationInfo);
-
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
+ if (!"autofill-service".equals(parser.getName())) {
+ Log.e(TAG, "Meta-data does not start with autofill-service tag");
+ return null;
}
-
- String nodeName = parser.getName();
- if (!"autofill-service".equals(nodeName)) {
- mParseError = "Meta-data does not start with autofill-service tag";
- return;
+ attrs = Xml.asAttributeSet(parser);
+
+ // Get resources required to read the AttributeSet.
+ Resources res;
+ try {
+ res = pm.getResourcesForApplication(si.applicationInfo);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Error getting application resources", e);
+ return null;
}
- TypedArray array = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.AutoFillService);
- mSettingsActivity = array.getString(
- com.android.internal.R.styleable.AutoFillService_settingsActivity);
- array.recycle();
- } catch (XmlPullParserException | IOException | PackageManager.NameNotFoundException e) {
- mParseError = "Error parsing auto fill service meta-data: " + e;
- Log.w(TAG, "error parsing auto fill service meta-data", e);
- return;
+ return res.obtainAttributes(attrs, R.styleable.AutoFillService);
} finally {
- if (parser != null) parser.close();
+ parser.close();
}
- mServiceInfo = si;
}
- @Nullable
- public String getParseError() {
- return mParseError;
- }
-
- @Nullable
public ServiceInfo getServiceInfo() {
return mServiceInfo;
}
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 5a9a9f68486c..a306809886a7 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -16,52 +16,46 @@
package android.service.autofill;
-import static android.service.autofill.AutoFillService.DEBUG;
-
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
-import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
-import android.util.Log;
import android.view.autofill.FillResponse;
-import com.android.internal.util.Preconditions;
-
/**
* Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being
* auto-filled.
*/
-public final class FillCallback {
-
- private static final String TAG = "FillCallback";
-
- private final IAutoFillServerCallback mCallback;
-
- private boolean mReplied = false;
+public final class FillCallback implements Parcelable {
+ private final IFillCallback mCallback;
+ private boolean mCalled;
/** @hide */
- FillCallback(IAutoFillServerCallback callback) {
+ public FillCallback(IFillCallback callback) {
mCallback = callback;
}
+ /** @hide */
+ private FillCallback(Parcel parcel) {
+ mCallback = IFillCallback.Stub.asInterface(parcel.readStrongBinder());
+ }
+
/**
* Notifies the Android System that an
- * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
- * was successfully fulfilled by the service.
+ * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
+ * android.os.CancellationSignal, FillCallback)} was successfully fulfilled by the service.
*
* @param response auto-fill information for that activity, or {@code null} when the activity
- * cannot be auto-filled (for example, if it only contains read-only fields).
- *
- * @throws RuntimeException if an error occurred while calling the Android System.
+ * cannot be auto-filled (for example, if it only contains read-only fields). See
+ * {@link FillResponse} for examples.
*/
public void onSuccess(@Nullable FillResponse response) {
- if (DEBUG) Log.d(TAG, "onSuccess(): respose=" + response);
-
- checkNotRepliedYet();
-
+ assertNotCalled();
+ mCalled = true;
try {
- mCallback.showResponse(response);
+ mCallback.onSuccess(response);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -69,29 +63,49 @@ public final class FillCallback {
/**
* Notifies the Android System that an
- * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
+ * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure,
+ * Bundle, android.os.CancellationSignal, FillCallback)}
* could not be fulfilled by the service.
*
* @param message error message to be displayed to the user.
- *
- * @throws RuntimeException if an error occurred while calling the Android System.
*/
- public void onFailure(CharSequence message) {
- if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
-
- checkNotRepliedYet();
- Preconditions.checkArgument(message != null, "message cannot be null");
-
+ public void onFailure(@Nullable CharSequence message) {
+ assertNotCalled();
+ mCalled = true;
try {
- mCallback.showError(message.toString());
+ mCallback.onFailure(message);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
- // There can be only one!!
- private void checkNotRepliedYet() {
- Preconditions.checkState(!mReplied, "already replied");
- mReplied = true;
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeStrongBinder(mCallback.asBinder());
+ }
+
+ private void assertNotCalled() {
+ if (mCalled) {
+ throw new IllegalStateException("Already called");
+ }
}
+
+ public static final Creator<FillCallback> CREATOR = new Creator<FillCallback>() {
+ @Override
+ public FillCallback createFromParcel(Parcel parcel) {
+ return new FillCallback(parcel);
+ }
+
+ @Override
+ public FillCallback[] newArray(int size) {
+ return new FillCallback[size];
+ }
+ };
}
diff --git a/core/java/android/service/autofill/IAutoFillAppCallback.aidl b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
index 629b1f008d8f..c2e72e8235a4 100644
--- a/core/java/android/service/autofill/IAutoFillAppCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
@@ -18,11 +18,30 @@ package android.service.autofill;
import java.util.List;
+import android.content.Intent;
+import android.content.IntentSender;
import android.view.autofill.Dataset;
/**
+ * Object running in the application process and responsible for auto-filling it.
+ *
* @hide
*/
+// TODO(b/33197203): rename IAutoFillAppSession
oneway interface IAutoFillAppCallback {
+ /**
+ * Auto-fills the activity with the contents of a dataset.
+ */
void autoFill(in Dataset dataset);
+
+ /**
+ * Start an intent sender from the context of the filled app
+ */
+ void startIntentSender(in IntentSender intent, in Intent fillInIntent);
+
+ /**
+ * Called by system_service to enable auto-fill in a session, after it was asynchronously
+ * started by the manager.
+ */
+ void enableSession();
}
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index f8ae57bb8809..b39c0c8e07d4 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -16,7 +16,11 @@
package android.service.autofill;
+import android.graphics.Rect;
import android.os.Bundle;
+import android.os.IBinder;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
/**
* Mediator between apps being auto-filled and auto-fill service implementations.
@@ -24,5 +28,13 @@ import android.os.Bundle;
* {@hide}
*/
oneway interface IAutoFillManagerService {
- void requestAutoFill(IBinder activityToken, int userId, in Bundle extras, int flags);
+ // Methods called by AutoFillManager
+ void startSession(in IBinder activityToken, in IBinder appCallback, in AutoFillId autoFillId,
+ in Rect bounds, in AutoFillValue value);
+ void updateSession(in IBinder activityToken, in AutoFillId id, in Rect bounds,
+ in AutoFillValue value, int flags);
+ void finishSession(in IBinder activityToken);
+
+ // Methods called by ShellCommand
+ void requestSaveForUser(int userId);
}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index a1f22bf114e3..fa1ea65e30b0 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -18,15 +18,20 @@ package android.service.autofill;
import android.app.assist.AssistStructure;
import android.os.Bundle;
-import android.service.autofill.IAutoFillServerCallback;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.ISaveCallback;
import com.android.internal.os.IResultReceiver;
/**
+ * Interface from the system to an auto fill service.
+ *
* @hide
*/
oneway interface IAutoFillService {
- void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback,
- in Bundle extras, int flags);
+ void onFillRequest(in AssistStructure structure, in Bundle extras,
+ in IFillCallback callback);
+ void onSaveRequest(in AssistStructure structure, in Bundle extras,
+ in ISaveCallback callback);
void onConnected();
void onDisconnected();
}
diff --git a/core/java/android/service/autofill/IAutoFillServerCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 9d58c9956a25..537403e72fc5 100644
--- a/core/java/android/service/autofill/IAutoFillServerCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -16,16 +16,17 @@
package android.service.autofill;
-import java.util.List;
+import android.os.ICancellationSignal;
-import android.view.autofill.AutoFillId;
import android.view.autofill.FillResponse;
/**
+ * Interface to receive the result of a save request.
+ *
* @hide
*/
-oneway interface IAutoFillServerCallback {
- void showResponse(in FillResponse response);
- void showError(String message);
- void highlightSavedFields(in AutoFillId[] ids);
+interface IFillCallback {
+ void onCancellable(in ICancellationSignal cancellation);
+ void onSuccess(in FillResponse response);
+ void onFailure(CharSequence message);
}
diff --git a/core/java/android/service/autofill/ISaveCallback.aidl b/core/java/android/service/autofill/ISaveCallback.aidl
new file mode 100644
index 000000000000..e260c7375cc5
--- /dev/null
+++ b/core/java/android/service/autofill/ISaveCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.service.autofill;
+
+/**
+ * Interface to receive the result of a save request.
+ *
+ * @hide
+ */
+interface ISaveCallback {
+ void onSuccess();
+ void onFailure(CharSequence message);
+}
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 627d74c8e349..46b307233e88 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -16,54 +16,37 @@
package android.service.autofill;
-import static android.service.autofill.AutoFillService.DEBUG;
-
import android.app.Activity;
-import android.app.assist.AssistStructure.ViewNode;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
-import android.view.autofill.AutoFillId;
-
-import com.android.internal.util.Preconditions;
/**
* Handles save requests from the {@link AutoFillService} into the {@link Activity} being
* auto-filled.
+ *
+ * <p>This class is thread safe.
*/
public final class SaveCallback {
-
- private static final String TAG = "SaveCallback";
-
- private final IAutoFillServerCallback mCallback;
-
- private boolean mReplied = false;
+ private final ISaveCallback mCallback;
+ private boolean mCalled;
/** @hide */
- SaveCallback(IAutoFillServerCallback callback) {
+ SaveCallback(ISaveCallback callback) {
mCallback = callback;
}
/**
* Notifies the Android System that an
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
- * was successfully fulfilled by the service.
- *
- * @param ids ids ({@link ViewNode#getAutoFillId()}) of the fields that were saved.
+ * {@link AutoFillService#onSaveRequest (android.app.assist.AssistStructure, Bundle,
+ * SaveCallback)} was successfully fulfilled by the service.
*
* @throws RuntimeException if an error occurred while calling the Android System.
*/
- public void onSuccess(AutoFillId[] ids) {
- if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ((ids == null) ? "null" : ids.length));
-
- Preconditions.checkArgument(ids != null, "ids cannot be null");
- checkNotRepliedYet();
-
- Preconditions.checkArgument(ids.length > 0, "ids cannot be empty");
-
+ public void onSuccess() {
+ assertNotCalled();
+ mCalled = true;
try {
- mCallback.highlightSavedFields(ids);
+ mCallback.onSuccess();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -71,29 +54,26 @@ public final class SaveCallback {
/**
* Notifies the Android System that an
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
- * could not be fulfilled by the service.
+ * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * SaveCallback)} could not be fulfilled by the service.
*
* @param message error message to be displayed to the user.
*
* @throws RuntimeException if an error occurred while calling the Android System.
*/
public void onFailure(CharSequence message) {
- if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
-
- Preconditions.checkArgument(message != null, "message cannot be null");
- checkNotRepliedYet();
-
+ assertNotCalled();
+ mCalled = true;
try {
- mCallback.showError(message.toString());
+ mCallback.onFailure(message);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
- // There can be only one!!
- private void checkNotRepliedYet() {
- Preconditions.checkState(!mReplied, "already replied");
- mReplied = true;
+ private void assertNotCalled() {
+ if (mCalled) {
+ throw new IllegalStateException("Already called");
+ }
}
}
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index a512957d6040..287dc76a9b01 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -19,6 +19,8 @@ package android.service.gatekeeper;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Response object for a GateKeeper verification request.
* @hide
@@ -35,12 +37,28 @@ public final class GateKeeperResponse implements Parcelable {
private byte[] mPayload;
private boolean mShouldReEnroll;
+ /** Default constructor for response with generic response code **/
private GateKeeperResponse(int responseCode) {
mResponseCode = responseCode;
}
- private GateKeeperResponse(int responseCode, int timeout) {
- mResponseCode = responseCode;
+ @VisibleForTesting
+ public static GateKeeperResponse createGenericResponse(int responseCode) {
+ return new GateKeeperResponse(responseCode);
+ }
+
+ private static GateKeeperResponse createRetryResponse(int timeout) {
+ GateKeeperResponse response = new GateKeeperResponse(RESPONSE_RETRY);
+ response.mTimeout = timeout;
+ return response;
+ }
+
+ @VisibleForTesting
+ public static GateKeeperResponse createOkResponse(byte[] payload, boolean shouldReEnroll) {
+ GateKeeperResponse response = new GateKeeperResponse(RESPONSE_OK);
+ response.mPayload = payload;
+ response.mShouldReEnroll = shouldReEnroll;
+ return response;
}
@Override
@@ -53,17 +71,20 @@ public final class GateKeeperResponse implements Parcelable {
@Override
public GateKeeperResponse createFromParcel(Parcel source) {
int responseCode = source.readInt();
- GateKeeperResponse response = new GateKeeperResponse(responseCode);
+ final GateKeeperResponse response;
if (responseCode == RESPONSE_RETRY) {
- response.setTimeout(source.readInt());
+ response = createRetryResponse(source.readInt());
} else if (responseCode == RESPONSE_OK) {
- response.setShouldReEnroll(source.readInt() == 1);
+ final boolean shouldReEnroll = source.readInt() == 1;
+ byte[] payload = null;
int size = source.readInt();
if (size > 0) {
- byte[] payload = new byte[size];
+ payload = new byte[size];
source.readByteArray(payload);
- response.setPayload(payload);
}
+ response = createOkResponse(payload, shouldReEnroll);
+ } else {
+ response = createGenericResponse(responseCode);
}
return response;
}
@@ -104,17 +125,4 @@ public final class GateKeeperResponse implements Parcelable {
public int getResponseCode() {
return mResponseCode;
}
-
- private void setTimeout(int timeout) {
- mTimeout = timeout;
- }
-
- private void setShouldReEnroll(boolean shouldReEnroll) {
- mShouldReEnroll = shouldReEnroll;
- }
-
- private void setPayload(byte[] payload) {
- mPayload = payload;
- }
-
}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 01d3391d32af..b26e32835aa1 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -34,6 +34,6 @@ oneway interface INotificationListener
void onInterruptionFilterChanged(int interruptionFilter);
// rankers only
- void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+ void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder);
void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index d7a02a8042a1..de86b2d2b6ed 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -77,12 +77,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS
* A notification was posted by an app. Called before alert.
*
* @param sbn the new notification
- * @param importance the initial importance of the notification.
- * @param user true if the initial importance reflects an explicit user preference.
* @return an adjustment or null to take no action, within 100ms.
*/
- abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
- int importance, boolean user);
+ abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn);
/**
* Updates a notification. N.B. this won’t cause
@@ -119,6 +116,24 @@ public abstract class NotificationAssistantService extends NotificationListenerS
}
/**
+ * Inform the notification manager about un-snoozing a specific notification.
+ * <p>
+ * This should only be used for notifications snoozed by this listener using
+ * {@link #snoozeNotification(String, String)}. Once un-snoozed, you will get a
+ * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
+ * notification.
+ * @param key The key of the notification to snooze
+ */
+ public final void unsnoozeNotification(String key) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().unsnoozeNotificationFromAssistant(mWrapper, key);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Creates a notification channel that notifications can be posted to for a given package.
*
* @param pkg The package to create a channel for.
@@ -184,8 +199,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
@Override
- public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
- int importance, boolean user) {
+ public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
@@ -196,8 +210,6 @@ public abstract class NotificationAssistantService extends NotificationListenerS
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
- args.argi1 = importance;
- args.argi2 = user ? 1 : 0;
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
args).sendToTarget();
}
@@ -236,10 +248,8 @@ public abstract class NotificationAssistantService extends NotificationListenerS
case MSG_ON_NOTIFICATION_ENQUEUED: {
SomeArgs args = (SomeArgs) msg.obj;
StatusBarNotification sbn = (StatusBarNotification) args.arg1;
- final int importance = args.argi1;
- final boolean user = args.argi2 == 1;
args.recycle();
- Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+ Adjustment adjustment = onNotificationEnqueued(sbn);
if (adjustment != null) {
if (!isBound()) return;
try {
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d9306897d876..e5abdac9e860 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -183,8 +183,8 @@ public abstract class NotificationListenerService extends Service {
public static final int REASON_CHANNEL_BANNED = 17;
/** Notification was snoozed. */
public static final int REASON_SNOOZED = 18;
- /** Notification no longer visible because of user switch */
- public static final int REASON_USER_SWITCH = 19;
+ /** Notification was canceled due to timeout */
+ public static final int REASON_TIMEOUT = 19;
/**
* The full trim of the StatusBarNotification including all its features.
@@ -562,43 +562,6 @@ public abstract class NotificationListenerService extends Service {
}
}
- /**
- * Inform the notification manager about snoozing a specific notification.
- * <p>
- * Use this to snooze a notification for an indeterminate time. Upon being informed, the
- * notification manager will actually remove the notification and you will get an
- * {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
- * snoozing period expires, you will get a
- * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
- * notification. Use {@link #unsnoozeNotification(String)} to restore the notification.
- * @param key The key of the notification to snooze
- */
- public final void snoozeNotification(String key) {
- if (!isBound()) return;
- try {
- getNotificationInterface().snoozeNotificationFromListener(mWrapper, key);
- } catch (android.os.RemoteException ex) {
- Log.v(TAG, "Unable to contact notification manager", ex);
- }
- }
-
- /**
- * Inform the notification manager about un-snoozing a specific notification.
- * <p>
- * This should only be used for notifications snoozed by this listener using
- * {@link #snoozeNotification(String)}. Once un-snoozed, you will get a
- * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
- * notification.
- * @param key The key of the notification to snooze
- */
- public final void unsnoozeNotification(String key) {
- if (!isBound()) return;
- try {
- getNotificationInterface().unsnoozeNotificationFromListener(mWrapper, key);
- } catch (android.os.RemoteException ex) {
- Log.v(TAG, "Unable to contact notification manager", ex);
- }
- }
/**
* Inform the notification manager that these notifications have been viewed by the
@@ -663,6 +626,26 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Like {@link #getActiveNotifications()}, but returns the list of currently snoozed
+ * notifications, for all users this listener has access to.
+ *
+ * <p>The service should wait for the {@link #onListenerConnected()} event
+ * before performing this operation.
+ *
+ * @return An array of active notifications, sorted in natural order.
+ */
+ public final StatusBarNotification[] getSnoozedNotifications() {
+ try {
+ ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+ .getSnoozedNotificationsFromListener(mWrapper, TRIM_FULL);
+ return cleanUpNotificationList(parceledList);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ return null;
+ }
+
+ /**
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
@@ -711,36 +694,41 @@ public abstract class NotificationListenerService extends Service {
try {
ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
.getActiveNotificationsFromListener(mWrapper, keys, trim);
- List<StatusBarNotification> list = parceledList.getList();
- ArrayList<StatusBarNotification> corruptNotifications = null;
- int N = list.size();
- for (int i = 0; i < N; i++) {
- StatusBarNotification sbn = list.get(i);
- Notification notification = sbn.getNotification();
- try {
- // convert icon metadata to legacy format for older clients
- createLegacyIconExtras(notification);
- // populate remote views for older clients.
- maybePopulateRemoteViews(notification);
- } catch (IllegalArgumentException e) {
- if (corruptNotifications == null) {
- corruptNotifications = new ArrayList<>(N);
- }
- corruptNotifications.add(sbn);
- Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
- sbn.getPackageName());
- }
- }
- if (corruptNotifications != null) {
- list.removeAll(corruptNotifications);
- }
- return list.toArray(new StatusBarNotification[list.size()]);
+ return cleanUpNotificationList(parceledList);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
return null;
}
+ private StatusBarNotification[] cleanUpNotificationList(
+ ParceledListSlice<StatusBarNotification> parceledList) {
+ List<StatusBarNotification> list = parceledList.getList();
+ ArrayList<StatusBarNotification> corruptNotifications = null;
+ int N = list.size();
+ for (int i = 0; i < N; i++) {
+ StatusBarNotification sbn = list.get(i);
+ Notification notification = sbn.getNotification();
+ try {
+ // convert icon metadata to legacy format for older clients
+ createLegacyIconExtras(notification);
+ // populate remote views for older clients.
+ maybePopulateRemoteViews(notification);
+ } catch (IllegalArgumentException e) {
+ if (corruptNotifications == null) {
+ corruptNotifications = new ArrayList<>(N);
+ }
+ corruptNotifications.add(sbn);
+ Log.w(TAG, "get(Active/Snoozed)Notifications: can't rebuild notification from " +
+ sbn.getPackageName());
+ }
+ }
+ if (corruptNotifications != null) {
+ list.removeAll(corruptNotifications);
+ }
+ return list.toArray(new StatusBarNotification[list.size()]);
+ }
+
/**
* Gets the set of hints representing current state.
*
@@ -937,7 +925,7 @@ public abstract class NotificationListenerService extends Service {
}
/**
- * Request that the listener be rebound, after a previous call to (@link requestUnbind).
+ * Request that the listener be rebound, after a previous call to {@link #requestUnbind}.
*
* <p>This method will fail for listeners that have
* not been granted the permission by the user.
@@ -1112,8 +1100,8 @@ public abstract class NotificationListenerService extends Service {
}
@Override
- public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
- int importance, boolean user) throws RemoteException {
+ public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder)
+ throws RemoteException {
// no-op in the listener
}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 85baf4edaeca..85bccf746305 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -130,7 +130,7 @@ public class StatusBarNotification implements Parcelable {
}
return user.getIdentifier() + "|" + pkg + "|" +
(group == null
- ? "p:" + notification.priority
+ ? "c:" + notification.getChannel()
: "g:" + group);
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 887f4b6577b9..1781c2ac0d78 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -130,6 +130,11 @@ public class TileService extends Service {
*/
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_STATE = "state";
+
private final H mHandler = new H(Looper.getMainLooper());
private boolean mListening = false;
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 48f3ac3f06f7..e9bbc2de26cc 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -119,8 +119,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
public static final String KEY_CONTENT = "content";
/** @hide */
public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
- /** @hide */
- public static final String KEY_FLAGS = "flags";
final Context mContext;
final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 62ecab3583cd..10e417784700 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -42,5 +42,13 @@ interface IVrManager {
*/
boolean getVrModeState();
+ /**
+ * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+ * remain in VR mode even if the foreground does not specify VR mode being enabled. Mainly used
+ * by VR viewers to indicate that a device is placed in a VR viewer.
+ *
+ * @param enabled true if the device should be placed in persistent VR mode.
+ */
+ void setPersistentVrModeEnabled(in boolean enabled);
}
diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java
index c0948a6c138c..3396bceb75d0 100644
--- a/core/java/android/text/Editable.java
+++ b/core/java/android/text/Editable.java
@@ -94,10 +94,10 @@ extends CharSequence, GetChars, Spannable, Appendable
public Editable append(char text);
/**
- * Convenience for replace(0, length(), "", 0, 0)
- * @see #replace(int, int, CharSequence, int, int)
+ * Convenience for replace(0, length(), "", 0, 0).
* Note that this clears the text, not the spans;
* use {@link #clearSpans} if you need that.
+ * @see #replace(int, int, CharSequence, int, int)
*/
public void clear();
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index df694ff6af31..3048a3882010 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -164,7 +164,7 @@ public final class FontConfig implements Parcelable {
* Class that holds information about a Font.
*/
public static final class Font implements Parcelable {
- private final String mFontName;
+ private String mFontName;
private final int mTtcIndex;
private final List<Axis> mAxes;
private final int mWeight;
@@ -203,6 +203,13 @@ public final class FontConfig implements Parcelable {
}
/**
+ * @hide
+ */
+ public void setFontName(String fontName) {
+ mFontName = fontName;
+ }
+
+ /**
* Returns the index to be used to access this font when accessing a TTC file.
*/
public int getTtcIndex() {
diff --git a/core/java/android/text/ITextClassificationService.aidl b/core/java/android/text/ITextClassificationService.aidl
new file mode 100644
index 000000000000..a73dbf01a8e8
--- /dev/null
+++ b/core/java/android/text/ITextClassificationService.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface to the text classification service, which grants access to the text classification
+ * LSTM model file.
+ * {@hide}
+ */
+interface ITextClassificationService {
+
+ /**
+ * Request a file descriptor with read-only access to the LSTM model file.
+ * This file descriptor should be closed after the client is done with it.
+ */
+ ParcelFileDescriptor getModelFileFd();
+}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 186d96bce8e1..5f01f7b61bf1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -21,6 +21,7 @@ import android.graphics.BaseCanvas;
import android.graphics.Paint;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
@@ -73,8 +74,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanFlags = EmptyArray.INT;
mSpanMax = EmptyArray.INT;
mSpanOrder = EmptyArray.INT;
- mPrioSortBuffer = EmptyArray.INT;
- mOrderSortBuffer = EmptyArray.INT;
if (text instanceof Spanned) {
Spanned sp = (Spanned) text;
@@ -856,14 +855,14 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* @param queryStart Start index.
* @param queryEnd End index.
* @param kind Class type to search for.
- * @param sort If true the results are sorted by the insertion order.
+ * @param sortByInsertionOrder If true the results are sorted by the insertion order.
* @param <T>
* @return Array of the spans. Empty array if no results are found.
*
* @hide
*/
public <T> T[] getSpans(int queryStart, int queryEnd, @Nullable Class<T> kind,
- boolean sort) {
+ boolean sortByInsertionOrder) {
if (kind == null) return (T[]) ArrayUtils.emptyArray(Object.class);
if (mSpanCount == 0) return ArrayUtils.emptyArray(kind);
int count = countSpans(queryStart, queryEnd, kind, treeRoot());
@@ -873,13 +872,15 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
// Safe conversion, but requires a suppressWarning
T[] ret = (T[]) Array.newInstance(kind, count);
- if (sort) {
- mPrioSortBuffer = checkSortBuffer(mPrioSortBuffer, count);
- mOrderSortBuffer = checkSortBuffer(mOrderSortBuffer, count);
+ final int[] prioSortBuffer = sortByInsertionOrder ? obtain(count) : EmptyArray.INT;
+ final int[] orderSortBuffer = sortByInsertionOrder ? obtain(count) : EmptyArray.INT;
+ getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, prioSortBuffer,
+ orderSortBuffer, 0, sortByInsertionOrder);
+ if (sortByInsertionOrder) {
+ sort(ret, prioSortBuffer, orderSortBuffer);
+ recycle(prioSortBuffer);
+ recycle(orderSortBuffer);
}
- getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, mPrioSortBuffer,
- mOrderSortBuffer, 0, sort);
- if (sort) sort(ret, mPrioSortBuffer, mOrderSortBuffer);
return ret;
}
@@ -992,15 +993,63 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
/**
+ * Obtain a temporary sort buffer.
+ *
+ * @param elementCount the size of the int[] to be returned
+ * @return an int[] with elementCount length
+ */
+ private static int[] obtain(final int elementCount) {
+ int[] result = null;
+ synchronized (sCachedIntBuffer) {
+ // try finding a tmp buffer with length of at least elementCount
+ // if not get the first available one
+ int candidateIndex = -1;
+ for (int i = sCachedIntBuffer.length - 1; i >= 0; i--) {
+ if (sCachedIntBuffer[i] != null) {
+ if (sCachedIntBuffer[i].length >= elementCount) {
+ candidateIndex = i;
+ break;
+ } else if (candidateIndex == -1) {
+ candidateIndex = i;
+ }
+ }
+ }
+
+ if (candidateIndex != -1) {
+ result = sCachedIntBuffer[candidateIndex];
+ sCachedIntBuffer[candidateIndex] = null;
+ }
+ }
+ result = checkSortBuffer(result, elementCount);
+ return result;
+ }
+
+ /**
+ * Recycle sort buffer.
+ *
+ * @param buffer buffer to be recycled
+ */
+ private static void recycle(int[] buffer) {
+ synchronized (sCachedIntBuffer) {
+ for (int i = 0; i < sCachedIntBuffer.length; i++) {
+ if (sCachedIntBuffer[i] == null || buffer.length > sCachedIntBuffer[i].length) {
+ sCachedIntBuffer[i] = buffer;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
* Check the size of the buffer and grow if required.
*
- * @param buffer Buffer to be checked.
- * @param size Required size.
+ * @param buffer buffer to be checked.
+ * @param size required size.
* @return Same buffer instance if the current size is greater than required size. Otherwise a
* new instance is created and returned.
*/
- private final int[] checkSortBuffer(int[] buffer, int size) {
- if(size > buffer.length) {
+ private static int[] checkSortBuffer(int[] buffer, int size) {
+ if (buffer == null || size > buffer.length) {
return ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(size));
}
return buffer;
@@ -1025,16 +1074,19 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
for (int i = size - 1; i > 0; i--) {
- T v = array[0];
- int prio = priority[0];
- int insertOrder = insertionOrder[0];
+ final T tmpSpan = array[0];
array[0] = array[i];
+ array[i] = tmpSpan;
+
+ final int tmpPriority = priority[0];
priority[0] = priority[i];
+ priority[i] = tmpPriority;
+
+ final int tmpOrder = insertionOrder[0];
insertionOrder[0] = insertionOrder[i];
+ insertionOrder[i] = tmpOrder;
+
siftDown(0, array, i, priority, insertionOrder);
- array[i] = v;
- priority[i] = prio;
- insertionOrder[i] = insertOrder;
}
}
@@ -1050,10 +1102,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
*/
private final <T> void siftDown(int index, T[] array, int size, int[] priority,
int[] insertionOrder) {
- T v = array[index];
- int prio = priority[index];
- int insertOrder = insertionOrder[index];
-
int left = 2 * index + 1;
while (left < size) {
if (left < size - 1 && compareSpans(left, left + 1, priority, insertionOrder) < 0) {
@@ -1062,15 +1110,22 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
if (compareSpans(index, left, priority, insertionOrder) >= 0) {
break;
}
+
+ final T tmpSpan = array[index];
array[index] = array[left];
+ array[left] = tmpSpan;
+
+ final int tmpPriority = priority[index];
priority[index] = priority[left];
+ priority[left] = tmpPriority;
+
+ final int tmpOrder = insertionOrder[index];
insertionOrder[index] = insertionOrder[left];
+ insertionOrder[left] = tmpOrder;
+
index = left;
left = 2 * index + 1;
}
- array[index] = v;
- priority[index] = prio;
- insertionOrder[index] = insertOrder;
}
/**
@@ -1704,6 +1759,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
+
+ @GuardedBy("sCachedIntBuffer")
+ private static final int[][] sCachedIntBuffer = new int[6][0];
+
private InputFilter[] mFilters = NO_FILTERS;
private char[] mText;
@@ -1717,8 +1776,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
private int[] mSpanFlags;
private int[] mSpanOrder; // store the order of span insertion
private int mSpanInsertCount; // counter for the span insertion
- private int[] mPrioSortBuffer; // buffer used to sort getSpans result
- private int[] mOrderSortBuffer; // buffer used to sort getSpans result
private int mSpanCount;
private IdentityHashMap<Object, Integer> mIndexOfSpan;
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 4b02df86c82e..60d8a0fc8894 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -53,12 +53,16 @@ import java.lang.reflect.Array;
* @param end End index in the source object.
*/
private final void copySpans(Spanned src, int start, int end) {
- Object[] spans = src.getSpans(start, end, Object.class);
+ final Object[] spans = src.getSpans(start, end, Object.class);
for (int i = 0; i < spans.length; i++) {
+ if (spans[i] instanceof NoCopySpan) {
+ continue;
+ }
+
int st = src.getSpanStart(spans[i]);
int en = src.getSpanEnd(spans[i]);
- int fl = src.getSpanFlags(spans[i]);
+ final int fl = src.getSpanFlags(spans[i]);
if (st < start)
st = start;
@@ -78,33 +82,42 @@ import java.lang.reflect.Array;
* @param end End index in the source object.
*/
private final void copySpans(SpannableStringInternal src, int start, int end) {
- if (start == 0 && end == src.length()) {
+ int count = 0;
+ boolean includesNoCopySpan = false;
+ final int[] srcData = src.mSpanData;
+ final Object[] srcSpans = src.mSpans;
+ final int limit = src.mSpanCount;
+
+ for (int i = 0; i < limit; i++) {
+ int spanStart = srcData[i * COLUMNS + START];
+ int spanEnd = srcData[i * COLUMNS + END];
+ if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+ if (srcSpans[i] instanceof NoCopySpan) {
+ includesNoCopySpan = true;
+ continue;
+ }
+ count++;
+ }
+
+ if (count == 0) return;
+
+ if (!includesNoCopySpan && start == 0 && end == src.length()) {
mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length);
mSpanData = new int[src.mSpanData.length];
mSpanCount = src.mSpanCount;
System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length);
System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length);
} else {
- int count = 0;
- int[] srcData = src.mSpanData;
- int limit = src.mSpanCount;
- for (int i = 0; i < limit; i++) {
- int spanStart = srcData[i * COLUMNS + START];
- int spanEnd = srcData[i * COLUMNS + END];
- if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
- count++;
- }
-
- if (count == 0) return;
-
- Object[] srcSpans = src.mSpans;
mSpanCount = count;
mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount);
mSpanData = new int[mSpans.length * COLUMNS];
for (int i = 0, j = 0; i < limit; i++) {
int spanStart = srcData[i * COLUMNS + START];
int spanEnd = srcData[i * COLUMNS + END];
- if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+ if (isOutOfCopyRange(start, end, spanStart, spanEnd)
+ || srcSpans[i] instanceof NoCopySpan) {
+ continue;
+ }
if (spanStart < start) spanStart = start;
if (spanEnd > end) spanEnd = end;
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index bb952ab93077..ac9c0d782c53 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -62,6 +62,7 @@ import android.view.View;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
import java.lang.reflect.Array;
import java.util.Iterator;
@@ -455,10 +456,7 @@ public class TextUtils {
* @return true if str is null or zero length
*/
public static boolean isEmpty(@Nullable CharSequence str) {
- if (str == null || str.length() == 0)
- return true;
- else
- return false;
+ return str == null || str.length() == 0;
}
/** {@hide} */
@@ -466,6 +464,16 @@ public class TextUtils {
return isEmpty(str) ? null : str;
}
+ /** {@hide} */
+ public static String emptyIfNull(@Nullable String str) {
+ return str == null ? "" : str;
+ }
+
+ /** {@hide} */
+ public static String firstNotEmpty(@Nullable String a, @NonNull String b) {
+ return !isEmpty(a) ? a : Preconditions.checkStringNotEmpty(b);
+ }
+
/**
* Returns the length that the specified CharSequence would have if
* spaces and ASCII control characters were trimmed from the start and end,
diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java
index a183427a44d0..b098f16da1ed 100644
--- a/core/java/android/text/style/ClickableSpan.java
+++ b/core/java/android/text/style/ClickableSpan.java
@@ -22,7 +22,7 @@ import android.view.View;
/**
* If an object of this type is attached to the text of a TextView
* with a movement method of LinkMovementMethod, the affected spans of
- * text can be selected. If clicked, the {@link #onClick} method will
+ * text can be selected. If selected and clicked, the {@link #onClick} method will
* be called.
*/
public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 856dd0bff36e..b0bff680f390 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -43,7 +43,7 @@ public class ImageSpan extends DynamicDrawableSpan {
}
/**
- * @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead.
+ * @deprecated Use {@link #ImageSpan(Context, Bitmap, int)} instead.
*/
@Deprecated
public ImageSpan(Bitmap b, int verticalAlignment) {
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index c5e5df091592..d72a48d005a8 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -798,7 +798,7 @@ public class TtsSpan implements ParcelableSpan {
/**
* Creates a TtsSpan of type {@link #TYPE_DECIMAL} and sets the
* {@link #ARG_INTEGER_PART} and {@link #ARG_FRACTIONAL_PART} arguments.
- * @see {@link #setArgumentsFromDouble(double, int, int)
+ * @see #setArgumentsFromDouble(double, int, int)
*/
public DecimalBuilder(double number,
int minimumFractionDigits,
@@ -1082,7 +1082,7 @@ public class TtsSpan implements ParcelableSpan {
* Sets the {@link #ARG_UNIT} argument.
* @param unit The unit of the measure.
* @return This instance.
- * @see {@link TtsSpan.ARG_UNIT}
+ * @see TtsSpan.ARG_UNIT
*/
public MeasureBuilder setUnit(String unit) {
return setStringArgument(TtsSpan.ARG_UNIT, unit);
@@ -1116,7 +1116,7 @@ public class TtsSpan implements ParcelableSpan {
* Sets the {@link #ARG_HOURS} argument.
* @param hours The value to be set for hours. See {@link #ARG_HOURS}.
* @return This instance.
- * @see {@link #ARG_HOURS}
+ * @see #ARG_HOURS
*/
public TimeBuilder setHours(int hours) {
return setIntArgument(TtsSpan.ARG_HOURS, hours);
@@ -1127,7 +1127,7 @@ public class TtsSpan implements ParcelableSpan {
* @param minutes The value to be set for minutes. See
* {@link #ARG_MINUTES}.
* @return This instance.
- * @see {@link #ARG_MINUTES}
+ * @see #ARG_MINUTES
*/
public TimeBuilder setMinutes(int minutes) {
return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
@@ -1177,7 +1177,7 @@ public class TtsSpan implements ParcelableSpan {
* @param weekday The value to be set for weekday. See
* {@link #ARG_WEEKDAY}.
* @return This instance.
- * @see {@link #ARG_WEEKDAY}
+ * @see #ARG_WEEKDAY
*/
public DateBuilder setWeekday(int weekday) {
return setIntArgument(TtsSpan.ARG_WEEKDAY, weekday);
@@ -1187,7 +1187,7 @@ public class TtsSpan implements ParcelableSpan {
* Sets the {@link #ARG_DAY} argument.
* @param day The value to be set for day. See {@link #ARG_DAY}.
* @return This instance.
- * @see {@link #ARG_DAY}
+ * @see #ARG_DAY
*/
public DateBuilder setDay(int day) {
return setIntArgument(TtsSpan.ARG_DAY, day);
@@ -1197,7 +1197,7 @@ public class TtsSpan implements ParcelableSpan {
* Sets the {@link #ARG_MONTH} argument.
* @param month The value to be set for month. See {@link #ARG_MONTH}.
* @return This instance.
- * @see {@link #ARG_MONTH}
+ * @see #ARG_MONTH
*/
public DateBuilder setMonth(int month) {
return setIntArgument(TtsSpan.ARG_MONTH, month);
@@ -1207,7 +1207,7 @@ public class TtsSpan implements ParcelableSpan {
* Sets the {@link #ARG_YEAR} argument.
* @param year The value to be set for year. See {@link #ARG_YEAR}.
* @return This instance.
- * @see {@link #ARG_YEAR}
+ * @see #ARG_YEAR
*/
public DateBuilder setYear(int year) {
return setIntArgument(TtsSpan.ARG_YEAR, year);
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 4b0b065ad6b1..5303855c7003 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -141,9 +141,10 @@ public class ChangeTransform extends Transition {
* child view will be relative to its parent's final position, so it may appear to "jump"
* at the beginning.</p>
*
- * @return <code>true</code> when a changed parent should execute the transition
- * inside the scene root's overlay or <code>false</code> if a parent change only
- * affects the transform of the transitioning view.
+ * @param reparentWithOverlay <code>true</code> when a changed parent should execute the
+ * transition inside the scene root's overlay or <code>false</code>
+ * if a parent change only affects the transform of the transitioning
+ * view.
* @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay
*/
public void setReparentWithOverlay(boolean reparentWithOverlay) {
@@ -465,7 +466,7 @@ public class ChangeTransform extends Transition {
}
}
- private static class GhostListener extends Transition.TransitionListenerAdapter {
+ private static class GhostListener extends TransitionListenerAdapter {
private View mView;
private View mStartView;
private GhostView mGhostView;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 8823605c52b6..af2547e44b9f 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -2342,34 +2342,6 @@ public abstract class Transition implements Cloneable {
}
/**
- * Utility adapter class to avoid having to override all three methods
- * whenever someone just wants to listen for a single event.
- *
- * @hide
- * */
- public static class TransitionListenerAdapter implements TransitionListener {
- @Override
- public void onTransitionStart(Transition transition) {
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- }
-
- @Override
- public void onTransitionCancel(Transition transition) {
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
- }
- }
-
- /**
* Holds information about each animator used when a new transition starts
* while other transitions are still running to determine whether a running
* animation should be canceled or a new animation noop'd. The structure holds
diff --git a/core/java/android/transition/TransitionListenerAdapter.java b/core/java/android/transition/TransitionListenerAdapter.java
new file mode 100644
index 000000000000..c2179499ff03
--- /dev/null
+++ b/core/java/android/transition/TransitionListenerAdapter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.transition;
+
+/**
+ * This adapter class provides empty implementations of the methods from {@link
+ * android.transition.Transition.TransitionListener}.
+ * Any custom listener that cares only about a subset of the methods of this listener can
+ * simply subclass this adapter class instead of implementing the interface directly.
+ */
+public abstract class TransitionListenerAdapter implements Transition.TransitionListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransitionStart(Transition transition) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+}
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 6e4d78ded4f2..325ff38e7d40 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -298,7 +298,7 @@ public class TransitionManager {
previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
}
currentTransitions.add(mTransition);
- mTransition.addListener(new Transition.TransitionListenerAdapter() {
+ mTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
ArrayList<Transition> currentTransitions =
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
index 7103e6da0625..333208db5f79 100644
--- a/core/java/android/util/ByteStringUtils.java
+++ b/core/java/android/util/ByteStringUtils.java
@@ -33,7 +33,7 @@ public final class ByteStringUtils {
* @param bytes Byte array to encode.
* @return Hex encoded string representation of bytes.
*/
- public static String toString(byte[] bytes) {
+ public static String toHexString(byte[] bytes) {
if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
return null;
}
@@ -55,7 +55,7 @@ public final class ByteStringUtils {
* @param str Hex encoded string to decode.
* @return Decoded byte array representation of str.
*/
- public static byte[] toByteArray(String str) {
+ public static byte[] fromHexToByteArray(String str) {
if (str == null || str.length() == 0 || str.length() % 2 != 0) {
return null;
}
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index e4c025dece49..be531ff35991 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -129,4 +129,22 @@ public class KeyValueListParser {
}
return def;
}
+
+ /**
+ * Get the value for key as a boolean.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found.
+ * @return the string value associated with the key.
+ */
+ public boolean getBoolean(String key, boolean def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ return Boolean.parseBoolean(value);
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
}
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index 31819797ea17..0fe56f6efa21 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -80,6 +80,6 @@ public final class PackageUtils {
messageDigest.update(data);
- return ByteStringUtils.toString(messageDigest.digest());
+ return ByteStringUtils.toHexString(messageDigest.digest());
}
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 37d675707a84..0a294ababf84 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -19,7 +19,6 @@ package android.util;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.SystemClock;
-import android.text.format.DateUtils;
import com.android.internal.util.XmlUtils;
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 13ee48ef23ce..4ff4840df453 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -17,9 +17,11 @@
package android.view;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.os.Binder;
import android.os.Bundle;
@@ -29,7 +31,6 @@ import android.os.Message;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
-import android.text.TextUtils;
import android.text.style.AccessibilityClickableSpan;
import android.text.style.ClickableSpan;
import android.util.LongSparseArray;
@@ -93,6 +94,19 @@ final class AccessibilityInteractionController {
mPrefetcher = new AccessibilityNodePrefetcher();
}
+ private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid) {
+ // If the interrogation is performed by the same thread as the main UI
+ // thread in this process, set the message as a static reference so
+ // after this call completes the same thread but in the interrogating
+ // client can handle the message to generate the result.
+ if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+ AccessibilityInteractionClient.getInstanceForThread(
+ interrogatingTid).setSameThreadMessage(message);
+ } else {
+ mHandler.sendMessage(message);
+ }
+ }
+
private boolean isShown(View view) {
// The first two checks are made also made by isShown() which
// however traverses the tree up to the parent to catch that.
@@ -106,7 +120,7 @@ final class AccessibilityInteractionController {
public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
long accessibilityNodeId, Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
- long interrogatingTid, MagnificationSpec spec) {
+ long interrogatingTid, MagnificationSpec spec, Bundle arguments) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID;
message.arg1 = flags;
@@ -118,18 +132,10 @@ final class AccessibilityInteractionController {
args.arg1 = callback;
args.arg2 = spec;
args.arg3 = interactiveRegion;
+ args.arg4 = arguments;
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
@@ -143,6 +149,7 @@ final class AccessibilityInteractionController {
(IAccessibilityInteractionConnectionCallback) args.arg1;
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
final Region interactiveRegion = (Region) args.arg3;
+ final Bundle arguments = (Bundle) args.arg4;
args.recycle();
@@ -160,29 +167,12 @@ final class AccessibilityInteractionController {
root = findViewByAccessibilityId(accessibilityViewId);
}
if (root != null && isShown(root)) {
- mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
+ mPrefetcher.prefetchAccessibilityNodeInfos(
+ root, virtualDescendantId, flags, infos, arguments);
}
} finally {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
- // Recycle if called from another process. Specs are cached in the
- // system process and obtained from a pool when read from parcel.
- if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
- spec.recycle();
- }
- adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
- callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
- infos.clear();
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
-
- // Recycle if called from the same process. Regions are obtained in
- // the system process and instantiated when read from parcel.
- if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
- interactiveRegion.recycle();
- }
+ updateInfosForViewportAndReturnFindNodeResult(
+ infos, callback, interactionId, spec, interactiveRegion);
}
}
@@ -201,19 +191,9 @@ final class AccessibilityInteractionController {
args.arg2 = spec;
args.arg3 = viewId;
args.arg4 = interactiveRegion;
-
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void findAccessibilityNodeInfosByViewIdUiThread(Message message) {
@@ -227,7 +207,6 @@ final class AccessibilityInteractionController {
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
final String viewId = (String) args.arg3;
final Region interactiveRegion = (Region) args.arg4;
-
args.recycle();
final List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
@@ -257,25 +236,8 @@ final class AccessibilityInteractionController {
mAddNodeInfosForViewId.reset();
}
} finally {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
- // Recycle if called from another process. Specs are cached in the
- // system process and obtained from a pool when read from parcel.
- if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
- spec.recycle();
- }
- adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
- callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
-
- // Recycle if called from the same process. Regions are obtained in
- // the system process and instantiated when read from parcel.
- if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
- interactiveRegion.recycle();
- }
+ updateInfosForViewportAndReturnFindNodeResult(
+ infos, callback, interactionId, spec, interactiveRegion);
}
}
@@ -297,16 +259,7 @@ final class AccessibilityInteractionController {
args.arg4 = interactiveRegion;
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void findAccessibilityNodeInfosByTextUiThread(Message message) {
@@ -375,31 +328,14 @@ final class AccessibilityInteractionController {
}
}
} finally {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
- // Recycle if called from another process. Specs are cached in the
- // system process and obtained from a pool when read from parcel.
- if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
- spec.recycle();
- }
- adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
- callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
-
- // Recycle if called from the same process. Regions are obtained in
- // the system process and instantiated when read from parcel.
- if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
- interactiveRegion.recycle();
- }
+ updateInfosForViewportAndReturnFindNodeResult(
+ infos, callback, interactionId, spec, interactiveRegion);
}
}
public void findFocusClientThread(long accessibilityNodeId, int focusType,
Region interactiveRegion, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+ IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_FIND_FOCUS;
@@ -416,16 +352,7 @@ final class AccessibilityInteractionController {
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void findFocusUiThread(Message message) {
@@ -497,31 +424,14 @@ final class AccessibilityInteractionController {
}
}
} finally {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- applyAppScaleAndMagnificationSpecIfNeeded(focused, spec);
- // Recycle if called from another process. Specs are cached in the
- // system process and obtained from a pool when read from parcel.
- if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
- spec.recycle();
- }
- adjustIsVisibleToUserIfNeeded(focused, interactiveRegion);
- callback.setFindAccessibilityNodeInfoResult(focused, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
-
- // Recycle if called from the same process. Regions are obtained in
- // the system process and instantiated when read from parcel.
- if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
- interactiveRegion.recycle();
- }
+ updateInfoForViewportAndReturnFindNodeResult(
+ focused, callback, interactionId, spec, interactiveRegion);
}
}
public void focusSearchClientThread(long accessibilityNodeId, int direction,
Region interactiveRegion, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+ IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_FOCUS_SEARCH;
@@ -537,16 +447,7 @@ final class AccessibilityInteractionController {
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void focusSearchUiThread(Message message) {
@@ -582,31 +483,14 @@ final class AccessibilityInteractionController {
}
}
} finally {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- applyAppScaleAndMagnificationSpecIfNeeded(next, spec);
- // Recycle if called from another process. Specs are cached in the
- // system process and obtained from a pool when read from parcel.
- if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
- spec.recycle();
- }
- adjustIsVisibleToUserIfNeeded(next, interactiveRegion);
- callback.setFindAccessibilityNodeInfoResult(next, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
-
- // Recycle if called from the same process. Regions are obtained in
- // the system process and instantiated when read from parcel.
- if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
- interactiveRegion.recycle();
- }
+ updateInfoForViewportAndReturnFindNodeResult(
+ next, callback, interactionId, spec, interactiveRegion);
}
}
public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
Bundle arguments, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+ IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_PERFORM_ACCESSIBILITY_ACTION;
@@ -622,16 +506,7 @@ final class AccessibilityInteractionController {
message.obj = args;
- // If the interrogation is performed by the same thread as the main UI
- // thread in this process, set the message as a static reference so
- // after this call completes the same thread but in the interrogating
- // client can handle the message to generate the result.
- if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
- AccessibilityInteractionClient.getInstanceForThread(
- interrogatingTid).setSameThreadMessage(message);
- } else {
- mHandler.sendMessage(message);
- }
+ scheduleMessage(message, interrogatingPid, interrogatingTid);
}
private void performAccessibilityActionUiThread(Message message) {
@@ -742,26 +617,6 @@ final class AccessibilityInteractionController {
}
}
- private void applyAppScaleAndMagnificationSpecIfNeeded(Point point,
- MagnificationSpec spec) {
- final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
- if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
- return;
- }
-
- if (applicationScale != 1.0f) {
- point.x *= applicationScale;
- point.y *= applicationScale;
- }
-
- if (spec != null) {
- point.x *= spec.scale;
- point.y *= spec.scale;
- point.x += (int) spec.offsetX;
- point.y += (int) spec.offsetY;
- }
- }
-
private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
MagnificationSpec spec) {
if (info == null) {
@@ -791,6 +646,25 @@ final class AccessibilityInteractionController {
info.setBoundsInParent(boundsInParent);
info.setBoundsInScreen(boundsInScreen);
+ // Scale text locations if they are present
+ if (info.hasExtras()) {
+ Bundle extras = info.getExtras();
+ Parcelable[] textLocations =
+ extras.getParcelableArray(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY);
+ if (textLocations != null) {
+ for (int i = 0; i < textLocations.length; i++) {
+ // Unchecked cast - an app that puts other objects in this bundle with this
+ // key will crash.
+ RectF textLocation = ((RectF) textLocations[i]);
+ textLocation.scale(applicationScale);
+ if (spec != null) {
+ textLocation.scale(spec.scale);
+ textLocation.offset(spec.offsetX, spec.offsetY);
+ }
+ }
+ }
+ }
+
if (spec != null) {
AttachInfo attachInfo = mViewRootImpl.mAttachInfo;
if (attachInfo.mDisplay == null) {
@@ -829,6 +703,53 @@ final class AccessibilityInteractionController {
return (appScale != 1.0f || (spec != null && !spec.isNop()));
}
+ private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
+ IAccessibilityInteractionConnectionCallback callback, int interactionId,
+ MagnificationSpec spec, Region interactiveRegion) {
+ try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
+ adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+ callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+ infos.clear();
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ } finally {
+ recycleMagnificationSpecAndRegionIfNeeded(spec, interactiveRegion);
+ }
+ }
+
+ private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
+ IAccessibilityInteractionConnectionCallback callback, int interactionId,
+ MagnificationSpec spec, Region interactiveRegion) {
+ try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+ adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+ callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ } finally {
+ recycleMagnificationSpecAndRegionIfNeeded(spec, interactiveRegion);
+ }
+ }
+
+ private void recycleMagnificationSpecAndRegionIfNeeded(MagnificationSpec spec, Region region) {
+ if (android.os.Process.myPid() != Binder.getCallingPid()) {
+ // Specs are cached in the system process and obtained from a pool when read from
+ // a parcel, so only recycle the spec if called from another process.
+ if (spec != null) {
+ spec.recycle();
+ }
+ } else {
+ // Regions are obtained in the system process and instantiated when read from
+ // a parcel, so only recycle the region if caled from the same process.
+ if (region != null) {
+ region.recycle();
+ }
+ }
+ }
+
private boolean handleClickableSpanActionUiThread(
View view, int virtualDescendantId, Bundle arguments) {
Parcelable span = arguments.getParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN);
@@ -872,11 +793,18 @@ final class AccessibilityInteractionController {
private final ArrayList<View> mTempViewList = new ArrayList<View>();
public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
- List<AccessibilityNodeInfo> outInfos) {
+ List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+ // Determine if we'll be populating extra data
+ final String extraDataRequested = (arguments == null) ? null
+ : arguments.getString(AccessibilityNodeInfo.EXTRA_DATA_REQUESTED_KEY);
if (provider == null) {
AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
if (root != null) {
+ if (extraDataRequested != null) {
+ view.addExtraDataToAccessibilityNodeInfo(
+ root, extraDataRequested, arguments);
+ }
outInfos.add(root);
if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
prefetchPredecessorsOfRealNode(view, outInfos);
@@ -889,14 +817,14 @@ final class AccessibilityInteractionController {
}
}
} else {
- final AccessibilityNodeInfo root;
- if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- root = provider.createAccessibilityNodeInfo(virtualViewId);
- } else {
- root = provider.createAccessibilityNodeInfo(
- AccessibilityNodeProvider.HOST_VIEW_ID);
- }
+ final int idForRoot = (virtualViewId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)
+ ? AccessibilityNodeProvider.HOST_VIEW_ID : virtualViewId;
+ final AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(idForRoot);
if (root != null) {
+ if (extraDataRequested != null) {
+ provider.addExtraDataToAccessibilityNodeInfo(
+ idForRoot, root, extraDataRequested, arguments);
+ }
outInfos.add(root);
if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
@@ -1202,12 +1130,12 @@ final class AccessibilityInteractionController {
}
private class PrivateHandler extends Handler {
- private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
- private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
- private final static int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
- private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
- private final static int MSG_FIND_FOCUS = 5;
- private final static int MSG_FOCUS_SEARCH = 6;
+ private static final int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
+ private static final int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
+ private static final int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
+ private static final int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
+ private static final int MSG_FIND_FOCUS = 5;
+ private static final int MSG_FOCUS_SEARCH = 6;
public PrivateHandler(Looper looper) {
super(looper);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 105cc47c88aa..3ba55ed2c4dc 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -163,7 +163,7 @@ public final class Display {
/**
* Display flag: Indicates that the display is private. Only the application that
- * owns the display can create windows on it.
+ * owns the display and apps that are already on the display can create windows on it.
*
* @see #getFlags
*/
@@ -194,6 +194,19 @@ public final class Display {
public static final int FLAG_ROUND = 1 << 4;
/**
+ * Display flag: Indicates that the display can show its content when non-secure keyguard is
+ * shown.
+ * <p>
+ * This flag identifies secondary displays that won't show keyguard if it can be dismissed
+ * without entering credentials. Display content will be shown even if other displays are
+ * locked.
+ * </p>
+ *
+ * @see #getFlags
+ */
+ public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
+
+ /**
* Display flag: Indicates that the contents of the display should not be scaled
* to fit the physical screen dimensions. Used for development only to emulate
* devices with smaller physicals screens while preserving density.
@@ -777,8 +790,7 @@ public final class Display {
public boolean isHdr() {
synchronized (this) {
updateDisplayInfoLocked();
- int[] types = mDisplayInfo.hdrCapabilities.getSupportedHdrTypes();
- return types != null && types.length > 0;
+ return mDisplayInfo.isHdr();
}
}
@@ -788,12 +800,7 @@ public final class Display {
public boolean isWideColorGamut() {
synchronized (this) {
updateDisplayInfoLocked();
- for (int colorMode : mDisplayInfo.supportedColorModes) {
- if (colorMode == COLOR_MODE_DCI_P3 || colorMode > COLOR_MODE_SRGB) {
- return true;
- }
- }
- return false;
+ return mDisplayInfo.isWideColorGamut();
}
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 1aef6ec0f302..f6b94af4b954 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -519,6 +519,20 @@ public final class DisplayInfo implements Parcelable {
logicalHeight : logicalWidth;
}
+ public boolean isHdr() {
+ int[] types = hdrCapabilities != null ? hdrCapabilities.getSupportedHdrTypes() : null;
+ return types != null && types.length > 0;
+ }
+
+ public boolean isWideColorGamut() {
+ for (int colorMode : supportedColorModes) {
+ if (colorMode == Display.COLOR_MODE_DCI_P3 || colorMode > Display.COLOR_MODE_SRGB) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Returns true if the specified UID has access to this display.
*/
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 41a13cf59bd8..7fde8a652001 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -52,7 +52,9 @@ public class FocusFinder {
final Rect mFocusedRect = new Rect();
final Rect mOtherRect = new Rect();
final Rect mBestCandidateRect = new Rect();
- final SequentialFocusComparator mSequentialFocusComparator = new SequentialFocusComparator();
+ private final UserSpecifiedFocusComparator mUserSpecifiedFocusComparator =
+ new UserSpecifiedFocusComparator();
+ private final FocusComparator mFocusComparator = new FocusComparator();
private final ArrayList<View> mTempList = new ArrayList<View>();
@@ -225,12 +227,10 @@ public class FocusFinder {
View focused, Rect focusedRect, int direction) {
try {
// Note: This sort is stable.
- mSequentialFocusComparator.setRoot(root);
- mSequentialFocusComparator.setIsLayoutRtl(root.isLayoutRtl());
- mSequentialFocusComparator.setFocusables(focusables);
- Collections.sort(focusables, mSequentialFocusComparator);
+ mUserSpecifiedFocusComparator.setFocusables(focusables);
+ Collections.sort(focusables, mUserSpecifiedFocusComparator);
} finally {
- mSequentialFocusComparator.recycle();
+ mUserSpecifiedFocusComparator.recycle();
}
final int count = focusables.size();
@@ -703,36 +703,80 @@ public class FocusFinder {
return id != 0 && id != View.NO_ID;
}
- /**
- * Sorts views according to their visual layout and geometry for default tab order.
- * If views are part of a focus chain (nextFocusForwardId), then they are all grouped
- * together. The head of the chain is used to determine the order of the chain and is
- * first in the order and the tail of the chain is the last in the order. The views
- * in the middle of the chain can be arbitrary order.
- * This is used for sequential focus traversal.
- */
- private static final class SequentialFocusComparator implements Comparator<View> {
+ static FocusComparator getFocusComparator(ViewGroup root, boolean isRtl) {
+ FocusComparator comparator = getInstance().mFocusComparator;
+ comparator.setRoot(root);
+ comparator.setIsLayoutRtl(isRtl);
+ return comparator;
+ }
+
+ static final class FocusComparator implements Comparator<View> {
private final Rect mFirstRect = new Rect();
private final Rect mSecondRect = new Rect();
- private ViewGroup mRoot;
+ private ViewGroup mRoot = null;
private boolean mIsLayoutRtl;
+
+ public void setIsLayoutRtl(boolean b) {
+ mIsLayoutRtl = b;
+ }
+
+ public void setRoot(ViewGroup root) {
+ mRoot = root;
+ }
+
+ public int compare(View first, View second) {
+ if (first == second) {
+ return 0;
+ }
+
+ getRect(first, mFirstRect);
+ getRect(second, mSecondRect);
+
+ if (mFirstRect.top < mSecondRect.top) {
+ return -1;
+ } else if (mFirstRect.top > mSecondRect.top) {
+ return 1;
+ } else if (mFirstRect.left < mSecondRect.left) {
+ return mIsLayoutRtl ? 1 : -1;
+ } else if (mFirstRect.left > mSecondRect.left) {
+ return mIsLayoutRtl ? -1 : 1;
+ } else if (mFirstRect.bottom < mSecondRect.bottom) {
+ return -1;
+ } else if (mFirstRect.bottom > mSecondRect.bottom) {
+ return 1;
+ } else if (mFirstRect.right < mSecondRect.right) {
+ return mIsLayoutRtl ? 1 : -1;
+ } else if (mFirstRect.right > mSecondRect.right) {
+ return mIsLayoutRtl ? -1 : 1;
+ } else {
+ // The view are distinct but completely coincident so we consider
+ // them equal for our purposes. Since the sort is stable, this
+ // means that the views will retain their layout order relative to one another.
+ return 0;
+ }
+ }
+
+ private void getRect(View view, Rect rect) {
+ view.getDrawingRect(rect);
+ mRoot.offsetDescendantRectToMyCoords(view, rect);
+ }
+ }
+
+ /**
+ * Sorts views according to any explicitly-specified focus-chains. If there are no explicitly
+ * specified focus chains (eg. no nextFocusForward attributes defined), this should be a no-op.
+ */
+ private static final class UserSpecifiedFocusComparator implements Comparator<View> {
private final SparseArray<View> mFocusables = new SparseArray<View>();
private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
+ private final ArrayMap<View, Integer> mOriginalOrdinal = new ArrayMap<>();
public void recycle() {
- mRoot = null;
mFocusables.clear();
mHeadsOfChains.clear();
mIsConnectedTo.clear();
- }
-
- public void setRoot(ViewGroup root) {
- mRoot = root;
- }
-
- public void setIsLayoutRtl(boolean b) {
- mIsLayoutRtl = b;
+ mOriginalOrdinal.clear();
}
public void setFocusables(ArrayList<View> focusables) {
@@ -755,6 +799,10 @@ public class FocusFinder {
setHeadOfChain(view);
}
}
+
+ for (int i = 0; i < focusables.size(); ++i) {
+ mOriginalOrdinal.put(focusables.get(i), i);
+ }
}
private void setHeadOfChain(View head) {
@@ -793,44 +841,22 @@ public class FocusFinder {
return 1; // first is end of chain
}
}
+ boolean involvesChain = false;
if (firstHead != null) {
first = firstHead;
+ involvesChain = true;
}
if (secondHead != null) {
second = secondHead;
+ involvesChain = true;
}
- // First see if they belong to the same focus chain.
- getRect(first, mFirstRect);
- getRect(second, mSecondRect);
-
- if (mFirstRect.top < mSecondRect.top) {
- return -1;
- } else if (mFirstRect.top > mSecondRect.top) {
- return 1;
- } else if (mFirstRect.left < mSecondRect.left) {
- return mIsLayoutRtl ? 1 : -1;
- } else if (mFirstRect.left > mSecondRect.left) {
- return mIsLayoutRtl ? -1 : 1;
- } else if (mFirstRect.bottom < mSecondRect.bottom) {
- return -1;
- } else if (mFirstRect.bottom > mSecondRect.bottom) {
- return 1;
- } else if (mFirstRect.right < mSecondRect.right) {
- return mIsLayoutRtl ? 1 : -1;
- } else if (mFirstRect.right > mSecondRect.right) {
- return mIsLayoutRtl ? -1 : 1;
+ if (involvesChain) {
+ // keep original order between chains
+ return mOriginalOrdinal.get(first) < mOriginalOrdinal.get(second) ? -1 : 1;
} else {
- // The view are distinct but completely coincident so we consider
- // them equal for our purposes. Since the sort is stable, this
- // means that the views will retain their layout order relative to one another.
return 0;
}
}
-
- private void getRect(View view, Rect rect) {
- view.getDrawingRect(rect);
- mRoot.offsetDescendantRectToMyCoords(view, rect);
- }
}
}
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 800a63f7da07..92f0e8f81f11 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -137,7 +137,7 @@ public final class FrameMetrics {
/**
* Identifiers for metrics available for each frame.
*
- * {@see {@link #getMetric(int)}}
+ * {@see #getMetric(int)}
* @hide
*/
@IntDef({
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index 36a81db2880a..4cf7cf3ef1f0 100644
--- a/core/java/android/view/IDockedStackListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -40,8 +40,11 @@ oneway interface IDockedStackListener {
*
* @param minimized Whether the docked stack is currently minimized.
* @param animDuration The duration of the animation for changing the minimized state.
+ * @param isHomeStackResizable If the home stack is resizable, a portion of the docked stack
+ * will be shown with the divider
*/
- void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
+ void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
+ boolean isHomeStackResizable);
/**
* Called when window manager decides to adjust the divider for IME. Like the minimized state,
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index d59be02c7371..2fe98c0b6f05 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -16,8 +16,6 @@
package android.view;
-import android.graphics.Rect;
-
/**
* An interface to the PinnedStackController to update it of state changes, and to query
* information based on the current state.
@@ -27,17 +25,7 @@ import android.graphics.Rect;
interface IPinnedStackController {
/**
- * Notifies the controller that the user is currently interacting with the PIP.
- */
- oneway void setInInteractiveMode(boolean inInteractiveMode);
-
- /**
- * Notifies the controller that the PIP is currently minimized.
+ * Notifies the controller that the PiP is currently minimized.
*/
oneway void setIsMinimized(boolean isMinimized);
-
- /**
- * Notifies the controller that the desired snap mode is to the closest edge.
- */
- oneway void setSnapToEdge(boolean snapToEdge);
}
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index 3c348c50369f..c7340bfa329e 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -17,6 +17,7 @@
package android.view;
import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
import android.view.IPinnedStackController;
/**
@@ -33,24 +34,28 @@ oneway interface IPinnedStackListener {
void onListenerRegistered(IPinnedStackController controller);
/**
- * Called when window manager decides to adjust the pinned stack bounds, or when the listener
- * is first registered to allow the listener to synchronized its state with the controller.
+ * Called when the window manager has detected a change that would cause the movement bounds
+ * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides
+ * the components that allow the listener to calculate the movement bounds itself. The
+ * {@param normalBounds} are also the default bounds that the PiP would be entered in its
+ * current state with the aspect ratio applied.
*/
- void onBoundsChanged(boolean adjustedForIme);
+ void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds,
+ boolean fromImeAdjustement);
/**
- * Called when window manager decides to adjust the minimized state, or when the listener
- * is first registered to allow the listener to synchronized its state with the controller.
+ * Called when window manager decides to adjust the pinned stack bounds because of the IME, or
+ * when the listener is first registered to allow the listener to synchronized its state with
+ * the controller. This call will always be followed by a onMovementBoundsChanged() call
+ * with fromImeAdjustement set to true.
*/
- void onMinimizedStateChanged(boolean isMinimized);
+ void onImeVisibilityChanged(boolean imeVisible, int imeHeight);
/**
- * Called when window manager decides to adjust the snap-to-edge state, which determines whether
- * to snap only to the corners of the screen or to the closest edge. It is called when the
- * listener is first registered to allow the listener to synchronized its state with the
- * controller.
+ * Called when window manager decides to adjust the minimized state, or when the listener
+ * is first registered to allow the listener to synchronized its state with the controller.
*/
- void onSnapToEdgeStateChanged(boolean isSnapToEdge);
+ void onMinimizedStateChanged(boolean isMinimized);
/**
* Called when the set of actions for the current PiP activity changes, or when the listener
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 707300f7987a..10b1e1948a6a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -96,4 +96,9 @@ oneway interface IWindow {
* Called when Keyboard Shortcuts are requested for the window.
*/
void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
+
+ /**
+ * Tell the window that it is either gaining or losing pointer capture.
+ */
+ void dispatchPointerCaptureChanged(boolean hasCapture);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 19edb5c830d6..dd76fcff6ec8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -135,9 +135,6 @@ interface IWindowManager
// ids that were affected by the update, ActivityManager should resize these stacks.
int[] setNewDisplayOverrideConfiguration(in Configuration overrideConfig, int displayId);
- // Retrieves the new bounds after the configuration update evaluated by window manager.
- Rect getBoundsForNewConfiguration(int stackId);
-
void startFreezingScreen(int exitAnim, int enterAnim);
void stopFreezingScreen();
@@ -340,16 +337,6 @@ interface IWindowManager
void registerPinnedStackListener(int displayId, IPinnedStackListener listener);
/**
- * Returns the initial bounds that PIP will be shown when it is first started.
- */
- Rect getPictureInPictureDefaultBounds(int displayId);
-
- /**
- * Returns the bounds that the PIP can move on the screen in the current PIP state.
- */
- Rect getPictureInPictureMovementBounds(int displayId);
-
- /**
* Updates the dim layer used while resizing.
*
* @param visible Whether the dim layer should be visible.
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 55f64d9f6664..035d48ffc33f 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -237,6 +237,14 @@ public final class InputDevice implements Parcelable {
public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
/**
+ * The input source is a mouse device whose relative motions should be interpreted as
+ * navigation events.
+ *
+ * @see #SOURCE_CLASS_TRACKBALL
+ */
+ public static final int SOURCE_MOUSE_RELATIVE = 0x00020000 | SOURCE_CLASS_TRACKBALL;
+
+ /**
* The input source is a touch pad or digitizer tablet that is not
* associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
*
@@ -975,6 +983,7 @@ public final class InputDevice implements Parcelable {
appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse");
appendSourceDescriptionIfApplicable(description, SOURCE_STYLUS, "stylus");
appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball");
+ appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE_RELATIVE, "mouse_relative");
appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK, "joystick");
appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 88f2d3460346..02202db52fac 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -675,8 +675,8 @@ public class KeyCharacterMap implements Parcelable {
*
* @return The modifier behavior for this keyboard.
*
- * @see {@link #MODIFIER_BEHAVIOR_CHORDED}
- * @see {@link #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED}
+ * @see #MODIFIER_BEHAVIOR_CHORDED
+ * @see #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED
*/
public int getModifierBehavior() {
switch (getKeyboardType()) {
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 0da710a1fb33..c3d3f3918ccf 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.Nullable;
+import android.app.Notification;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
@@ -39,7 +40,7 @@ import java.util.ArrayList;
*/
@RemoteViews.RemoteView
public class NotificationHeaderView extends ViewGroup {
- public static final int NO_COLOR = -1;
+ public static final int NO_COLOR = Notification.COLOR_INVALID;
private final int mChildMinWidth;
private final int mContentEndMargin;
private View mAppName;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index fc666975ee25..ea6e63c3b9de 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -139,9 +139,6 @@ public class RenderNode {
RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
}
- // Note: written by native when display lists are detached
- private boolean mValid;
-
// Do not access directly unless you are ThreadedRenderer
final long mNativeRenderNode;
private final View mOwningView;
@@ -233,7 +230,6 @@ public class RenderNode {
long displayList = canvas.finishRecording();
nSetDisplayList(mNativeRenderNode, displayList);
canvas.recycle();
- mValid = true;
}
/**
@@ -242,10 +238,7 @@ public class RenderNode {
* obsolete resources after related resources are gone.
*/
public void discardDisplayList() {
- if (!mValid) return;
-
nSetDisplayList(mNativeRenderNode, 0);
- mValid = false;
}
/**
@@ -254,10 +247,12 @@ public class RenderNode {
*
* @return boolean true if the display list is able to be replayed, false otherwise.
*/
- public boolean isValid() { return mValid; }
+ public boolean isValid() {
+ return nIsValid(mNativeRenderNode);
+ }
long getNativeDisplayList() {
- if (!mValid) {
+ if (!isValid()) {
throw new IllegalStateException("The display list is not valid.");
}
return mNativeRenderNode;
@@ -827,8 +822,7 @@ public class RenderNode {
// Regular JNI methods
///////////////////////////////////////////////////////////////////////////
- // Intentionally not static because it acquires a reference to 'this'
- private native long nCreate(String name);
+ private static native long nCreate(String name);
private static native long nGetNativeFinalizer();
private static native void nOutput(long renderNode);
@@ -853,6 +847,9 @@ public class RenderNode {
// @CriticalNative methods
///////////////////////////////////////////////////////////////////////////
+ @CriticalNative
+ private static native boolean nIsValid(long renderNode);
+
// Matrix
@CriticalNative
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a12600a0d4e2..cf8da179bab5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -34,7 +34,7 @@ public class SurfaceControl {
private static final String TAG = "SurfaceControl";
private static native long nativeCreate(SurfaceSession session, String name,
- int w, int h, int format, int flags)
+ int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
throws OutOfResourcesException;
private static native void nativeRelease(long nativeObject);
private static native void nativeDestroy(long nativeObject);
@@ -281,12 +281,26 @@ public class SurfaceControl {
* @param h The surface initial height.
* @param flags The surface creation flags. Should always include {@link #HIDDEN}
* in the creation flags.
+ * @param windowType The type of the window as specified in WindowManager.java.
+ * @param ownerUid A unique per-app ID.
*
* @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
*/
public SurfaceControl(SurfaceSession session,
+ String name, int w, int h, int format, int flags, int windowType, int ownerUid)
+ throws OutOfResourcesException {
+ this(session, name, w, h, format, flags, null, windowType, ownerUid);
+ }
+
+ public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
+ this(session, name, w, h, format, flags, null, -1, -1);
+ }
+
+ public SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
+ SurfaceControl parent, int windowType, int ownerUid)
+ throws OutOfResourcesException {
if (session == null) {
throw new IllegalArgumentException("session must not be null");
}
@@ -304,7 +318,8 @@ public class SurfaceControl {
}
mName = name;
- mNativeObject = nativeCreate(session, name, w, h, format, flags);
+ mNativeObject = nativeCreate(session, name, w, h, format, flags,
+ parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
if (mNativeObject == 0) {
throw new OutOfResourcesException(
"Couldn't allocate SurfaceControl native object");
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f3ebcb4b326b..4ceb23628fb4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -496,15 +496,6 @@ public final class ThreadedRenderer {
private static void destroyResources(View view) {
view.destroyHardwareResources();
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyResources(group.getChildAt(i));
- }
- }
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e7f96de881c8..ee979844bd20 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -39,7 +39,6 @@ import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.TestApi;
import android.annotation.UiThread;
-import android.app.Application.OnProvideAssistDataListener;
import android.content.ClipData;
import android.content.Context;
import android.content.ContextWrapper;
@@ -104,6 +103,7 @@ import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import android.view.autofill.AutoFillManager;
import android.view.autofill.AutoFillType;
import android.view.autofill.AutoFillValue;
import android.view.autofill.VirtualViewDelegate;
@@ -857,22 +857,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static boolean sCascadedDragDrop;
+ /** @hide */
+ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Focusable {}
+
/**
- * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
- * calling setFlags.
+ * This view does not want keystrokes.
+ * <p>
+ * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
+ * android:focusable}.
*/
- private static final int NOT_FOCUSABLE = 0x00000000;
+ public static final int NOT_FOCUSABLE = 0x00000000;
/**
- * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling
- * setFlags.
+ * This view wants keystrokes.
+ * <p>
+ * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
+ * android:focusable}.
*/
- private static final int FOCUSABLE = 0x00000001;
+ public static final int FOCUSABLE = 0x00000001;
+
+ /**
+ * This view determines focusability automatically. This is the default.
+ * <p>
+ * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
+ * android:focusable}.
+ */
+ public static final int FOCUSABLE_AUTO = 0x00000010;
/**
* Mask for use with setFlags indicating bits used for focus.
*/
- private static final int FOCUSABLE_MASK = 0x00000001;
+ private static final int FOCUSABLE_MASK = 0x00000011;
/**
* This view will adjust its padding to fit sytem windows (e.g. status bar)
@@ -3681,6 +3698,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
+
+ OnCapturedPointerListener mOnCapturedPointerListener;
}
ListenerInfo mListenerInfo;
@@ -4003,37 +4022,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int mLayerType = LAYER_TYPE_NONE;
Paint mLayerPaint;
-
- /**
- * Set when a request was made to decide if views in an {@link android.app.Activity} can be
- * auto-filled by an {@link android.service.autofill.AutoFillService}.
- *
- * <p>Since this request is made without a explicit user consent, the resulting
- * {@link android.app.assist.AssistStructure} should not contain any PII
- * (Personally Identifiable Information).
- *
- * <p>Examples:
- * <ul>
- * <li>{@link android.widget.TextView} texts should only be included when they were set by
- * static resources.
- * <li>{@link android.webkit.WebView} virtual children should be restricted to a subset of
- * input fields and tags (like {@code id}).
- * </ul>
- */
- // TODO(b/33197203) (b/34078930): improve documentation: mention all cases, show examples, etc.
- // In particular, be more specific about webview restrictions
- public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x1;
-
- /**
- * Set when the user explicitly asked a {@link android.service.autofill.AutoFillService} to save
- * the value of the {@link View}s in an {@link android.app.Activity}.
- *
- * <p>The resulting {@link android.app.assist.AssistStructure} can contain any kind of PII
- * (Personally Identifiable Information). For example, the text of password fields should be
- * included since that's what's typically saved.
- */
- public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x2;
-
/**
* Set to true when drawing cache is enabled and cannot be created.
*
@@ -4136,7 +4124,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
- mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
+ mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO;
// Set some flags defaults
mPrivateFlags2 =
(LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
@@ -4322,6 +4310,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+ // Set default values.
+ viewFlagValues |= FOCUSABLE_AUTO;
+ viewFlagMasks |= FOCUSABLE_AUTO;
+
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
@@ -4434,8 +4426,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
break;
case com.android.internal.R.styleable.View_focusable:
- if (a.getBoolean(attr, false)) {
- viewFlagValues |= FOCUSABLE;
+ viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a);
+ if ((viewFlagValues & FOCUSABLE_AUTO) == 0) {
viewFlagMasks |= FOCUSABLE_MASK;
}
break;
@@ -5006,7 +4998,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case GONE: out.append('G'); break;
default: out.append('.'); break;
}
- out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.');
+ out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.');
out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.');
out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D');
out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.');
@@ -6364,6 +6356,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see ViewGroup#getTouchscreenBlocksFocus()
*/
public boolean hasFocusable() {
+ return hasFocusable(true);
+ }
+
+ /**
+ * @hide pending determination of whether this should be public or not.
+ * Currently used for compatibility with old focusability expectations in ListView.
+ */
+ public boolean hasFocusable(boolean allowAutoFocus) {
if (!isFocusableInTouchMode()) {
for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) {
final ViewGroup g = (ViewGroup) p;
@@ -6372,7 +6372,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
}
- return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable();
+ if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
+ return false;
+ }
+ return (allowAutoFocus
+ ? getFocusable() != NOT_FOCUSABLE
+ : getFocusable() == FOCUSABLE) && isFocusable();
}
/**
@@ -6408,16 +6413,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (isPressed()) {
setPressed(false);
}
- if (imm != null && mAttachInfo != null
- && mAttachInfo.mHasWindowFocus) {
+ if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
imm.focusOut(this);
}
onFocusLost();
- } else if (imm != null && mAttachInfo != null
- && mAttachInfo.mHasWindowFocus) {
+ } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
imm.focusIn(this);
}
+ if (isAutoFillable()) {
+ AutoFillManager afm = getAutoFillManager();
+ if (afm != null) {
+ afm.focusChanged(this, gainFocus);
+ }
+ }
+
invalidate(true);
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnFocusChangeListener != null) {
@@ -6868,7 +6878,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* fills in all data that can be inferred from the view itself.
*/
public void onProvideStructure(ViewStructure structure) {
- onProvideStructureForAssistOrAutoFill(structure, 0);
+ onProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -6879,19 +6889,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param structure Fill in with structured view data. The default implementation
* fills in all data that can be inferred from the view itself.
- * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
- onProvideStructureForAssistOrAutoFill(structure, flags);
+ onProvideStructureForAssistOrAutoFill(structure, true);
}
- private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
- boolean forAutoFill = (flags
- & (View.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
+ private void onProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
final int id = mID;
if (id != NO_ID && !isViewIdGenerated(id)) {
String pkg, type, entry;
@@ -6909,11 +6914,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
if (forAutoFill) {
- // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
- // reuse the accessibility id to save space.
- structure.setAutoFillId(getAccessibilityViewId());
-
- structure.setAutoFillType(getAutoFillType());
+ final AutoFillType autoFillType = getAutoFillType();
+ // Don't need to fill auto-fill info if view does not support it.
+ // For example, only TextViews that are editable support auto-fill
+ if (autoFillType != null) {
+ // The auto-fill id needs to be unique, but its value doesn't matter, so it's better
+ // to reuse the accessibility id to save space.
+ structure.setAutoFillId(getAccessibilityViewId());
+ structure.setAutoFillType(autoFillType);
+ structure.setAutoFillValue(getAutoFillValue());
+ }
}
structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
@@ -6966,7 +6976,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* optimal implementation providing this data.
*/
public void onProvideVirtualStructure(ViewStructure structure) {
- onProvideVirtualStructureForAssistOrAutoFill(structure, 0);
+ onProvideVirtualStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -6981,14 +6991,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@code flags} parameter - see the documentation on each flag for more details.
*
* @param structure Fill in with structured view data.
- * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
- onProvideVirtualStructureForAssistOrAutoFill(structure, flags);
+ onProvideVirtualStructureForAssistOrAutoFill(structure, true);
}
- private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+ private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
// NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
// this method should take a boolean with the type of request.
AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
@@ -6996,7 +7006,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityNodeInfo info = createAccessibilityNodeInfo();
structure.setChildCount(1);
ViewStructure root = structure.newChild(0);
- populateVirtualStructure(root, provider, info, flags);
+ populateVirtualStructure(root, provider, info, forAutoFill);
info.recycle();
}
}
@@ -7006,21 +7016,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* this view.
*
* <p>By default returns {@code null} but should be overridden when view provides a virtual
- * hierachy on {@link OnProvideAssistDataListener} that takes flags used by the AutoFill
- * Framework (such as {@link #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE}).
+ * hierachy on {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
*/
@Nullable
- public VirtualViewDelegate getAutoFillVirtualViewDelegate(
- @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) {
+ public VirtualViewDelegate getAutoFillVirtualViewDelegate() {
return null;
}
/**
* Automatically fills the content of this view with the {@code value}.
*
- * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to
- * support the AutoFill Framework.
+ * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()
+ * and #getAutoFillValue()} to support the AutoFill Framework.
*
* <p>Typically, it is implemented by:
*
@@ -7042,7 +7049,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Describes the auto-fill type that should be used on callas to
+ * Describes the auto-fill type that should be used on calls to
* {@link #autoFill(AutoFillValue)} and
* {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
*
@@ -7054,13 +7061,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return null;
}
- private void populateVirtualStructure(ViewStructure structure,
- AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) {
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
+ /**
+ * Gets the {@link View}'s current auto-fill value.
+ *
+ * <p>By default returns {@code null}, but views should override it,
+ * {@link #autoFill(AutoFillValue)}, and {@link #getAutoFillType()} to support the AutoFill
+ * Framework.
+ */
+ @Nullable
+ public AutoFillValue getAutoFillValue() {
+ return null;
+ }
+
+ @Nullable
+ private AutoFillManager getAutoFillManager() {
+ return mContext.getSystemService(AutoFillManager.class);
+ }
- final boolean sanitized = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
+ private boolean isAutoFillable() {
+ return getAutoFillType() != null && !isAutoFillBlocked();
+ }
+ private void populateVirtualStructure(ViewStructure structure,
+ AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutoFill) {
structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
null, null, null);
Rect rect = structure.getTempRect();
@@ -7098,7 +7121,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
CharSequence cname = info.getClassName();
structure.setClassName(cname != null ? cname.toString() : null);
structure.setContentDescription(info.getContentDescription());
- if (!sanitized && (info.getText() != null || info.getError() != null)) {
+ if (!forAutoFill && (info.getText() != null || info.getError() != null)) {
// TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to
// just set sanitized values (like text coming from resource files), rather than not
// setting it at all.
@@ -7112,7 +7135,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
ViewStructure child = structure.newChild(i);
- populateVirtualStructure(child, provider, cinfo, flags);
+ populateVirtualStructure(child, provider, cinfo, forAutoFill);
cinfo.recycle();
}
}
@@ -7124,7 +7147,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #onProvideVirtualStructure}.
*/
public void dispatchProvideStructure(ViewStructure structure) {
- dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+ dispatchProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -7137,25 +7160,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
*
* @param structure Fill in with structured view data.
- * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
- dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+ dispatchProvideStructureForAssistOrAutoFill(structure, true);
}
- private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
- boolean forAutoFill = (flags
- & (View.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
-
+ private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
if (!blocked) {
if (forAutoFill) {
- onProvideAutoFillStructure(structure, flags);
- onProvideAutoFillVirtualStructure(structure, flags);
+ // NOTE: flags are not currently supported, hence 0
+ onProvideAutoFillStructure(structure, 0);
+ onProvideAutoFillVirtualStructure(structure, 0);
} else {
onProvideStructure(structure);
onProvideVirtualStructure(structure);
@@ -7315,6 +7333,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+ * additional data.
+ * <p>
+ * This method only needs overloading if the node is marked as having extra data available.
+ * </p>
+ *
+ * @param info The info to which to add the extra data
+ * @param extraDataKey A key specifying the type of extra data to add to the info. The
+ * extra data should be added to the {@link Bundle} returned by
+ * the info's {@link AccessibilityNodeInfo#getExtras} method.
+ * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+ *
+ * @see AccessibilityNodeInfo#setExtraAvailableData
+ */
+ public void addExtraDataToAccessibilityNodeInfo(
+ AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+ }
+
+ /**
* Determine the order in which this view will be drawn relative to its siblings for a11y
*
* @param info The info whose drawing order should be populated
@@ -8453,20 +8490,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Set whether this view can receive the focus.
- *
+ * <p>
* Setting this to false will also ensure that this view is not focusable
* in touch mode.
*
* @param focusable If true, this view can receive the focus.
*
* @see #setFocusableInTouchMode(boolean)
+ * @see #setFocusable(int)
* @attr ref android.R.styleable#View_focusable
*/
public void setFocusable(boolean focusable) {
- if (!focusable) {
+ setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE);
+ }
+
+ /**
+ * Sets whether this view can receive focus.
+ * <p>
+ * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability
+ * automatically based on the view's interactivity. This is the default.
+ * <p>
+ * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable
+ * in touch mode.
+ *
+ * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE},
+ * or {@link #FOCUSABLE_AUTO}.
+ * @see #setFocusableInTouchMode(boolean)
+ * @attr ref android.R.styleable#View_focusable
+ */
+ public void setFocusable(@Focusable int focusable) {
+ if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) {
setFlags(0, FOCUSABLE_IN_TOUCH_MODE);
}
- setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK);
+ setFlags(focusable, FOCUSABLE_MASK);
}
/**
@@ -9056,14 +9112,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
- * Returns whether this View is able to take focus.
+ * Returns whether this View is currently able to take focus.
*
* @return True if this view can take focus, or false otherwise.
- * @attr ref android.R.styleable#View_focusable
*/
@ViewDebug.ExportedProperty(category = "focus")
public final boolean isFocusable() {
- return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK);
+ return FOCUSABLE == (mViewFlags & FOCUSABLE);
+ }
+
+ /**
+ * Returns the focusable setting for this view.
+ *
+ * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}.
+ * @attr ref android.R.styleable#View_focusable
+ */
+ @ViewDebug.ExportedProperty(mapping = {
+ @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"),
+ @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"),
+ @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
+ })
+ @Focusable
+ public int getFocusable() {
+ return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE;
}
/**
@@ -9615,8 +9686,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusable
- if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
- (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
+ if ((mViewFlags & FOCUSABLE) != FOCUSABLE
+ || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
@@ -10586,6 +10657,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Pass a captured pointer event down to the focused view.
+ *
+ * @param event The motion event to be dispatched.
+ * @return True if the event was handled by the view, false otherwise.
+ */
+ public boolean dispatchCapturedPointerEvent(MotionEvent event) {
+ if (!hasPointerCapture()) {
+ return false;
+ }
+ //noinspection SimplifiableIfStatement
+ ListenerInfo li = mListenerInfo;
+ if (li != null && li.mOnCapturedPointerListener != null
+ && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) {
+ return true;
+ }
+ return onCapturedPointerEvent(event);
+ }
+
+ /**
* Dispatch a generic motion event.
* <p>
* Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
@@ -11970,14 +12060,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
int privateFlags = mPrivateFlags;
+ // If focusable is auto, update the FOCUSABLE bit.
+ if (((mViewFlags & FOCUSABLE_AUTO) != 0)
+ && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
+ int newFocus = NOT_FOCUSABLE;
+ if ((mViewFlags & (CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
+ newFocus = FOCUSABLE;
+ } else {
+ mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE);
+ }
+ mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus;
+ int focusChanged = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE);
+ changed = (changed & ~FOCUSABLE) | focusChanged;
+ }
+
/* Check if the FOCUSABLE bit has changed */
- if (((changed & FOCUSABLE_MASK) != 0) &&
- ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) {
- if (((old & FOCUSABLE_MASK) == FOCUSABLE)
+ if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) {
+ if (((old & FOCUSABLE) == FOCUSABLE)
&& ((privateFlags & PFLAG_FOCUSED) != 0)) {
/* Give up focus if we are no longer focusable */
clearFocus();
- } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE)
+ } else if (((old & FOCUSABLE) == NOT_FOCUSABLE)
&& ((privateFlags & PFLAG_FOCUSED) == 0)) {
/*
* Tell the view system that we are now available to take focus
@@ -12120,7 +12223,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
if (accessibilityEnabled) {
- if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0
+ if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0
|| (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
|| (changed & CONTEXT_CLICKABLE) != 0) {
if (oldIncludeForAccessibility != includeForAccessibility()) {
@@ -13474,7 +13577,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Any previously attached StateListAnimator will be detached.
*
* @param stateListAnimator The StateListAnimator to update the view
- * @see {@link android.animation.StateListAnimator}
+ * @see android.animation.StateListAnimator
*/
public void setStateListAnimator(StateListAnimator stateListAnimator) {
if (mStateListAnimator == stateListAnimator) {
@@ -14266,16 +14369,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
protected void damageInParent() {
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).damageChild(this, r);
- } else {
- mParent.invalidateChild(this, r);
- }
+ if (mParent != null && mAttachInfo != null) {
+ mParent.onDescendantInvalidated(this, this);
}
}
@@ -16525,11 +16620,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@CallSuper
protected void destroyHardwareResources() {
- // Although the Layer will be destroyed by RenderNode, we want to release
- // the staging display list, which is also a signal to RenderNode that it's
- // safe to free its copy of the display list as it knows that we will
- // push an updated DisplayList if we try to draw again
- resetDisplayList();
+ if (mOverlay != null) {
+ mOverlay.getOverlayView().destroyHardwareResources();
+ }
+ if (mGhostView != null) {
+ mGhostView.destroyHardwareResources();
+ }
}
/**
@@ -16700,11 +16796,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
private void resetDisplayList() {
- if (mRenderNode.isValid()) {
- mRenderNode.discardDisplayList();
- }
-
- if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) {
+ mRenderNode.discardDisplayList();
+ if (mBackgroundRenderNode != null) {
mBackgroundRenderNode.discardDisplayList();
}
}
@@ -18045,7 +18138,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private static String printFlags(int flags) {
String output = "";
int numFlags = 0;
- if ((flags & FOCUSABLE_MASK) == FOCUSABLE) {
+ if ((flags & FOCUSABLE) == FOCUSABLE) {
output += "TAKES_FOCUS";
numFlags++;
}
@@ -19879,9 +19972,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * {@hide}
* @param id the id of the view to be found
* @return the view of the specified id, null if cannot be found
+ * @hide
*/
protected View findViewTraversal(@IdRes int id) {
if (id == mID) {
@@ -19891,9 +19984,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * {@hide}
* @param tag the tag of the view to be found
* @return the view of specified tag, null if cannot be found
+ * @hide
*/
protected View findViewWithTagTraversal(Object tag) {
if (tag != null && tag.equals(mTag)) {
@@ -19903,10 +19996,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * {@hide}
* @param predicate The predicate to evaluate.
* @param childToSkip If not null, ignores this child during the recursive traversal.
* @return The first view that matches the predicate or null.
+ * @hide
*/
protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
if (predicate.apply(this)) {
@@ -19984,19 +20077,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * {@hide}
* Look for a child view that matches the specified predicate.
* If this view matches the predicate, return this view.
*
* @param predicate The predicate to evaluate.
* @return The first view that matches the predicate or null.
+ * @hide
*/
public final View findViewByPredicate(Predicate<View> predicate) {
return findViewByPredicateTraversal(predicate, null);
}
/**
- * {@hide}
* Look for a child view that matches the specified predicate,
* starting with the specified view and its descendents and then
* recusively searching the ancestors and siblings of that view
@@ -20010,6 +20102,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param start The view to start from.
* @param predicate The predicate to evaluate.
* @return The first view that matches the predicate or null.
+ * @hide
*/
public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) {
View childToSkip = null;
@@ -22600,7 +22693,110 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return mPointerIcon;
}
- //
+ /**
+ * Checks pointer capture status.
+ *
+ * @return true if the view has pointer capture.
+ * @see #requestPointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public boolean hasPointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl == null) {
+ return false;
+ }
+ return viewRootImpl.hasPointerCapture();
+ }
+
+ /**
+ * Requests pointer capture mode.
+ * <p>
+ * When the window has pointer capture, the mouse pointer icon will disappear and will not
+ * change its position. Further mouse will be dispatched with the source
+ * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available
+ * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events
+ * (touchscreens, or stylus) will not be affected.
+ * <p>
+ * If the window already has pointer capture, this call does nothing.
+ * <p>
+ * The capture may be released through {@link #releasePointerCapture()}, or will be lost
+ * automatically when the window loses focus.
+ *
+ * @see #releasePointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public void requestPointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.requestPointerCapture(true);
+ }
+ }
+
+
+ /**
+ * Releases the pointer capture.
+ * <p>
+ * If the window does not have pointer capture, this call will do nothing.
+ * @see #requestPointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public void releasePointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.requestPointerCapture(false);
+ }
+ }
+
+ /**
+ * Called when the window has just acquired or lost pointer capture.
+ *
+ * @param hasCapture True if the view now has pointerCapture, false otherwise.
+ */
+ @CallSuper
+ public void onPointerCaptureChange(boolean hasCapture) {
+ }
+
+ /**
+ * @see #onPointerCaptureChange
+ */
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ onPointerCaptureChange(hasCapture);
+ }
+
+ /**
+ * Implement this method to handle captured pointer events
+ *
+ * @param event The captured pointer event.
+ * @return True if the event was handled, false otherwise.
+ * @see #requestPointerCapture()
+ */
+ public boolean onCapturedPointerEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a captured pointer event
+ * is being dispatched this view. The callback will be invoked before the event is
+ * given to the view.
+ */
+ public interface OnCapturedPointerListener {
+ /**
+ * Called when a captured pointer event is dispatched to a view.
+ * @param view The view this event has been dispatched to.
+ * @param event The captured event.
+ * @return True if the listener has consumed the event, false otherwise.
+ */
+ boolean onCapturedPointer(View view, MotionEvent event);
+ }
+
+ /**
+ * Set a listener to receive callbacks when the pointer capture state of a view changes.
+ * @param l The {@link OnCapturedPointerListener} to receive callbacks.
+ */
+ public void setOnCapturedPointerListener(OnCapturedPointerListener l) {
+ getListenerInfo().mOnCapturedPointerListener = l;
+ }
+
// Properties
//
/**
@@ -24157,6 +24353,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+ * additional data.
+ * <p>
+ * This method only needs to be implemented if the View offers to provide additional data.
+ * </p>
+ * <p>
+ * The default implementation behaves as
+ * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for
+ * the case where no accessibility delegate is set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param info The info to which to add the extra data
+ * @param extraDataKey A key specifying the type of extra data to add to the info. The
+ * extra data should be added to the {@link Bundle} returned by
+ * the info's {@link AccessibilityNodeInfo#getExtras} method.
+ * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+ *
+ * @see AccessibilityNodeInfo#setExtraAvailableData
+ */
+ public void addExtraDataToAccessibilityNodeInfo(
+ View host, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+ host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments);
+ }
+
+ /**
* Called when a child of the host View has requested sending an
* {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
* to augment the event.
@@ -24497,7 +24719,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Determine if this view is rendered on a round wearable device and is the main view
* on the screen.
*/
- private boolean shouldDrawRoundScrollbar() {
+ boolean shouldDrawRoundScrollbar() {
if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) {
return false;
}
@@ -24514,7 +24736,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false;
}
- getLocationOnScreen(mAttachInfo.mTmpLocation);
+ getLocationInWindow(mAttachInfo.mTmpLocation);
return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft()
&& mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop();
}
@@ -24549,6 +24771,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide Binary compatibility stub. To be removed when we finalize O APIs.
+ */
+ public void setTooltip(@Nullable CharSequence tooltipText) {
+ setTooltipText(tooltipText);
+ }
+
+ /**
* Returns the view's tooltip text.
*
* @return the tooltip text
@@ -24558,6 +24787,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null;
}
+ /**
+ * @hide Binary compatibility stub. To be removed when we finalize O APIs.
+ */
+ @Nullable
+ public CharSequence getTooltip() {
+ return getTooltipText();
+ }
+
private boolean showTooltip(int x, int y, boolean fromLongClick) {
if (mAttachInfo == null) {
return false;
@@ -24670,6 +24907,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
ViewConfiguration.getLongPressTooltipHideTimeout());
}
+ private int getFocusableAttribute(TypedArray attributes) {
+ TypedValue val = new TypedValue();
+ if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) {
+ if (val.type == TypedValue.TYPE_INT_BOOLEAN) {
+ return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE);
+ } else {
+ return val.data;
+ }
+ } else {
+ return FOCUSABLE_AUTO;
+ }
+ }
+
/**
* @return The content view of the tooltip popup currently being shown, or null if the tooltip
* is not showing.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index ba73c5f1be60..36beaaae864a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -19,6 +19,7 @@ package android.view;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import android.animation.LayoutTransition;
+import android.annotation.CallSuper;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.UiThread;
@@ -59,6 +60,7 @@ import com.android.internal.R;
import com.android.internal.util.Predicate;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -1105,13 +1107,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return null;
}
+ /** @hide Overriding hidden method */
@Override
- public boolean hasFocusable() {
+ public boolean hasFocusable(boolean allowAutoFocus) {
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
- if (isFocusable()) {
+ // TODO This should probably be super.hasFocusable, but that would change behavior
+ if ((allowAutoFocus ? getFocusable() != NOT_FOCUSABLE : getFocusable() == FOCUSABLE)
+ && isFocusable()) {
return true;
}
@@ -1122,7 +1127,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
for (int i = 0; i < count; i++) {
final View child = children[i];
- if (child.hasFocusable()) {
+ if (child.hasFocusable(allowAutoFocus)) {
return true;
}
}
@@ -1136,31 +1141,42 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int focusableCount = views.size();
final int descendantFocusability = getDescendantFocusability();
+ final boolean focusSelf = (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen());
- if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
- if (shouldBlockFocusForTouchscreen()) {
- focusableMode |= FOCUSABLES_TOUCH_MODE;
+ if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
+ if (focusSelf) {
+ super.addFocusables(views, direction, focusableMode);
}
+ return;
+ }
- final int count = mChildrenCount;
- final View[] children = mChildren;
+ if (shouldBlockFocusForTouchscreen()) {
+ focusableMode |= FOCUSABLES_TOUCH_MODE;
+ }
- for (int i = 0; i < count; i++) {
- final View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
- child.addFocusables(views, direction, focusableMode);
- }
+ if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
+ super.addFocusables(views, direction, focusableMode);
+ }
+
+ int count = 0;
+ final View[] children = new View[mChildrenCount];
+ for (int i = 0; i < mChildrenCount; ++i) {
+ View child = mChildren[i];
+ if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+ children[count++] = child;
}
}
+ Arrays.sort(children, 0, count, FocusFinder.getFocusComparator(this, false));
+ for (int i = 0; i < count; ++i) {
+ children[i].addFocusables(views, direction, focusableMode);
+ }
- // we add ourselves (if focusable) in all cases except for when we are
- // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
+ // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
+ // there aren't any focusable descendants. this is
// to avoid the focus search finding layouts when a more precise search
// among the focusable children would be more interesting.
- if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
- // No focusable descendants
- || (focusableCount == views.size())) &&
- (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
+ if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
+ && focusableCount == views.size()) {
super.addFocusables(views, direction, focusableMode);
}
}
@@ -1756,6 +1772,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
+ public boolean dispatchCapturedPointerEvent(MotionEvent event) {
+ if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+ == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
+ if (super.dispatchCapturedPointerEvent(event)) {
+ return true;
+ }
+ } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+ == PFLAG_HAS_BOUNDS) {
+ if (mFocused.dispatchCapturedPointerEvent(event)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ exitHoverTargets();
+
+ super.dispatchPointerCaptureChanged(hasCapture);
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchPointerCaptureChanged(hasCapture);
+ }
+ }
+
+ @Override
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
@@ -3175,7 +3219,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void dispatchProvideStructure(ViewStructure structure) {
super.dispatchProvideStructure(structure);
- dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+ dispatchProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -3187,16 +3231,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
super.dispatchProvideAutoFillStructure(structure, flags);
- dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+ dispatchProvideStructureForAssistOrAutoFill(structure, true);
}
- private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
- boolean forAutoFill = (flags
- & (View.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
-
+ private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
if (!blocked) {
@@ -3263,7 +3302,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Must explicitly check which recursive method to call.
if (forAutoFill) {
- child.dispatchProvideAutoFillStructure(cstructure, flags);
+ // NOTE: flags are not currently supported, hence 0
+ child.dispatchProvideAutoFillStructure(cstructure, 0);
} else {
child.dispatchProvideStructure(cstructure);
}
@@ -4597,6 +4637,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
clearCachedLayoutMode();
}
+ /** @hide */
+ @Override
+ protected void destroyHardwareResources() {
+ super.destroyHardwareResources();
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ getChildAt(i).destroyHardwareResources();
+ }
+ }
+
/**
* Adds a view during layout. This is useful if in your onLayout() method,
* you need to add more views (as does the list view for example).
@@ -5372,100 +5422,60 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
- /**
- * HW-only, Rect-ignoring invalidation path.
- *
- * Returns false if this path was unable to complete successfully. This means
- * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
- * damage area.
- *
- * Hardware acceleration ignores damage rectangles, since native computes damage for everything
- * drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area).
- *
- * Ignores opaque dirty optimizations, always using the full PFLAG_DIRTY flag.
- *
- * Ignores FLAG_OPTIMIZE_INVALIDATE, since we're not computing a rect,
- * so no point in optimizing that.
- * @hide
- */
- public boolean tryInvalidateChildHardware(View child) {
- final AttachInfo attachInfo = mAttachInfo;
- if (attachInfo == null || !attachInfo.mHardwareAccelerated) {
- return false;
- }
+ @Override
+ @CallSuper
+ public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
+ /*
+ * HW-only, Rect-ignoring damage codepath
+ *
+ * We don't deal with rectangles here, since RenderThread native code computes damage for
+ * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
+ */
- // verify it's ViewGroups up to a ViewRootImpl
- ViewRootImpl viewRoot = null;
- ViewParent parent = getParent();
- while (parent != null) {
- if (parent instanceof ViewGroup) {
- parent = parent.getParent();
- } else if (parent instanceof ViewRootImpl) {
- viewRoot = (ViewRootImpl) parent;
- break;
- } else {
- // unknown parent type, abort
- return false;
- }
- }
- if (viewRoot == null) {
- // unable to find ViewRoot
- return false;
- }
+ // if set, combine the animation flag into the parent
+ mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
- final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
+ if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
+ // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
+ // optimization in provides in a DisplayList world.
+ mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
- if (child.mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= PFLAG_INVALIDATED;
+ // simplified invalidateChildInParent behavior: clear cache validity to be safe...
+ mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
- parent = this;
- do {
- if (parent != viewRoot) {
- // Note: we cast here without checking isinstance, to avoid cost of isinstance again
- ViewGroup viewGroup = (ViewGroup) parent;
- if (drawAnimation) {
- viewGroup.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
- }
-
- // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
- // optimization in provides in a DisplayList world.
- viewGroup.mPrivateFlags =
- (viewGroup.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
-
- // simplified invalidateChildInParent behavior: clear cache validity to be safe,
- // and mark inval if in layer
- viewGroup.mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- if (viewGroup.mLayerType != LAYER_TYPE_NONE) {
- viewGroup.mPrivateFlags |= PFLAG_INVALIDATED;
- }
- } else {
- if (drawAnimation) {
- viewRoot.mIsAnimating = true;
- }
- ((ViewRootImpl) parent).invalidate();
- return true;
- }
+ // ... and mark inval if in software layer that needs to repaint (hw handled in native)
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ // Layered parents should be invalidated. Escalate to a full invalidate (and note that
+ // we do this after consuming any relevant flags from the originating descendant)
+ mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
+ target = this;
+ }
- parent = parent.getParent();
- } while (parent != null);
- return true;
+ if (mParent != null) {
+ mParent.onDescendantInvalidated(this, target);
+ }
}
/**
* Don't call or override this method. It is used for the implementation of
* the view hierarchy.
+ *
+ * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
+ * draw state in descendants.
*/
+ @Deprecated
@Override
public final void invalidateChild(View child, final Rect dirty) {
- if (tryInvalidateChildHardware(child)) {
+ final AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null && attachInfo.mHardwareAccelerated) {
+ // HW accelerated fast path
+ onDescendantInvalidated(child, child);
return;
}
ViewParent parent = this;
-
- final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
// If the child is drawing an animation, we want to copy this flag onto
// ourselves and the parent to make sure the invalidate request goes
@@ -5568,7 +5578,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* This implementation returns null if this ViewGroup does not have a parent,
* if this ViewGroup is already fully invalidated or if the dirty rectangle
* does not intersect with this ViewGroup's bounds.
+ *
+ * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
+ * draw state in descendants.
*/
+ @Deprecated
@Override
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
@@ -5617,74 +5631,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
- * Native-calculated damage path
- * Returns false if this path was unable to complete successfully. This means
- * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
- * damage area
- * @hide
- */
- public boolean damageChildDeferred() {
- ViewParent parent = getParent();
- while (parent != null) {
- if (parent instanceof ViewGroup) {
- parent = parent.getParent();
- } else if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).invalidate();
- return true;
- } else {
- parent = null;
- }
- }
- return false;
- }
-
- /**
- * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
- * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
- * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
- *
- * @hide
- */
- public void damageChild(View child, final Rect dirty) {
- if (damageChildDeferred()) {
- return;
- }
-
- ViewParent parent = this;
-
- final AttachInfo attachInfo = mAttachInfo;
- if (attachInfo != null) {
- int left = child.mLeft;
- int top = child.mTop;
- if (!child.getMatrix().isIdentity()) {
- child.transformRect(dirty);
- }
-
- do {
- if (parent instanceof ViewGroup) {
- ViewGroup parentVG = (ViewGroup) parent;
- if (parentVG.mLayerType != LAYER_TYPE_NONE) {
- // Layered parents should be recreated, not just re-issued
- parentVG.invalidate();
- parent = null;
- } else {
- parent = parentVG.damageChildInParent(left, top, dirty);
- left = parentVG.mLeft;
- top = parentVG.mTop;
- }
- } else {
- // Reached the top; this calls into the usual invalidate method in
- // ViewRootImpl, which schedules a traversal
- final int[] location = attachInfo.mInvalidateChildLocation;
- location[0] = left;
- location[1] = top;
- parent = parent.invalidateChildInParent(location, dirty);
- }
- } while (parent != null);
- }
- }
-
- /**
* Quick invalidation method that simply transforms the dirty rect into the parent's
* coordinate system, pruning the invalidation if the parent has already been invalidated.
*
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 1676a004585b..f061370cc581 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -328,22 +328,10 @@ public class ViewOverlay {
}
}
- /**
- * @hide
- */
@Override
- public void damageChild(View child, final Rect dirty) {
- if (mHostView != null) {
- // Note: This is not a "fast" invalidation. Would be nice to instead invalidate
- // using DisplayList properties and a dirty rect instead of causing a real
- // invalidation of the host view
- int left = child.mLeft;
- int top = child.mTop;
- if (!child.getMatrix().isIdentity()) {
- child.transformRect(dirty);
- }
- dirty.offset(left, top);
- mHostView.invalidate(dirty);
+ public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
+ if (mHostView != null && mHostView.getParent() != null) {
+ mHostView.getParent().onDescendantInvalidated(mHostView, target);
}
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 79b05cdb6e50..cc11cb8205d5 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.accessibility.AccessibilityEvent;
@@ -53,12 +54,36 @@ public interface ViewParent {
*/
public void requestTransparentRegion(View child);
+
+ /**
+ * The target View has been invalidated, or has had a drawing property changed that
+ * requires the hierarchy to re-render.
+ *
+ * This method is called by the View hierarchy to signal ancestors that a View either needs to
+ * re-record its drawing commands, or drawing properties have changed. This is how Views
+ * schedule a drawing traversal.
+ *
+ * This signal is generally only dispatched for attached Views, since only they need to draw.
+ *
+ * @param child Direct child of this ViewParent containing target
+ * @param target The view that needs to redraw
+ */
+ default void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
+ if (getParent() != null) {
+ // Note: should pass 'this' as default, but can't since we may not be a View
+ getParent().onDescendantInvalidated(child, target);
+ }
+ }
+
/**
* All or part of a child is dirty and needs to be redrawn.
*
* @param child The child which is dirty
* @param r The area within the child that is invalid
+ *
+ * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead.
*/
+ @Deprecated
public void invalidateChild(View child, Rect r);
/**
@@ -80,7 +105,10 @@ public interface ViewParent {
* @param r The area within the child that is invalid
*
* @return the parent of this ViewParent or null
+ *
+ * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead.
*/
+ @Deprecated
public ViewParent invalidateChildInParent(int[] location, Rect r);
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3cbe82e8b6b9..9e8dda8389bf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -192,8 +193,8 @@ public final class ViewRootImpl implements ViewParent,
View mAccessibilityFocusedHost;
AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
- // The view which captures mouse input, or null when no one is capturing.
- View mCapturingView;
+ // True if the window currently has pointer capture enabled.
+ boolean mPointerCapture;
int mViewVisibility;
boolean mAppVisible = true;
@@ -1065,6 +1066,14 @@ public final class ViewRootImpl implements ViewParent,
return mLayoutRequested;
}
+ @Override
+ public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
+ if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
+ mIsAnimating = true;
+ }
+ invalidate();
+ }
+
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
@@ -3200,6 +3209,27 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ boolean hasPointerCapture() {
+ return mPointerCapture;
+ }
+
+ void requestPointerCapture(boolean enabled) {
+ if (mPointerCapture == enabled) {
+ return;
+ }
+ InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled);
+ }
+
+ private void handlePointerCaptureChanged(boolean hasCapture) {
+ if (mPointerCapture == hasCapture) {
+ return;
+ }
+ mPointerCapture = hasCapture;
+ if (mView != null) {
+ mView.dispatchPointerCaptureChanged(hasCapture);
+ }
+ }
+
@Override
public void requestChildFocus(View child, View focused) {
if (DEBUG_INPUT_RESIZE) {
@@ -3393,6 +3423,7 @@ public final class ViewRootImpl implements ViewParent,
private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
private final static int MSG_UPDATE_POINTER_ICON = 27;
+ private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
final class ViewRootHandler extends Handler {
@Override
@@ -3442,6 +3473,8 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_DISPATCH_WINDOW_SHOWN";
case MSG_UPDATE_POINTER_ICON:
return "MSG_UPDATE_POINTER_ICON";
+ case MSG_POINTER_CAPTURE_CHANGED:
+ return "MSG_POINTER_CAPTURE_CHANGED";
}
return super.getMessageName(message);
}
@@ -3613,6 +3646,10 @@ public final class ViewRootImpl implements ViewParent,
.softInputMode &=
~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
mHasHadWindowFocus = true;
+ } else {
+ if (mPointerCapture) {
+ handlePointerCaptureChanged(false);
+ }
}
}
} break;
@@ -3691,6 +3728,10 @@ public final class ViewRootImpl implements ViewParent,
MotionEvent event = (MotionEvent) msg.obj;
resetPointerIcon(event);
} break;
+ case MSG_POINTER_CAPTURE_CHANGED: {
+ final boolean hasCapture = msg.arg1 != 0;
+ handlePointerCaptureChanged(hasCapture);
+ } break;
}
}
}
@@ -4421,14 +4462,12 @@ public final class ViewRootImpl implements ViewParent,
int groupNavigationDirection = 0;
- if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
- final int character =
- event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
- if (character == '+') {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
+ if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
groupNavigationDirection = View.FOCUS_FORWARD;
- }
-
- if (character == '_') {
+ } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
+ KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
groupNavigationDirection = View.FOCUS_BACKWARD;
}
}
@@ -4474,11 +4513,8 @@ public final class ViewRootImpl implements ViewParent,
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
- final View eventTarget =
- (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
- mCapturingView : mView;
mAttachInfo.mHandlingPointerEvent = true;
- boolean handled = eventTarget.dispatchPointerEvent(event);
+ boolean handled = mView.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
maybeUpdateTooltip(event);
mAttachInfo.mHandlingPointerEvent = false;
@@ -4512,6 +4548,12 @@ public final class ViewRootImpl implements ViewParent,
private int processTrackballEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
+ if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
+ return FINISH_HANDLED;
+ }
+ }
+
if (mView.dispatchTrackballEvent(event)) {
return FINISH_HANDLED;
}
@@ -6702,6 +6744,14 @@ public final class ViewRootImpl implements ViewParent,
MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
}
+ public void dispatchPointerCaptureChanged(boolean on) {
+ final int what = MSG_POINTER_CAPTURE_CHANGED;
+ mHandler.removeMessages(what);
+ Message msg = mHandler.obtainMessage(what);
+ msg.arg1 = on ? 1 : 0;
+ mHandler.sendMessage(msg);
+ }
+
/**
* Post a callback to send a
* {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
@@ -7282,6 +7332,15 @@ public final class ViewRootImpl implements ViewParent,
viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
}
}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchPointerCaptureChanged(hasCapture);
+ }
+ }
+
}
public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
@@ -7433,13 +7492,13 @@ public final class ViewRootImpl implements ViewParent,
public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
- int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+ int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
interactiveRegion, interactionId, callback, flags, interrogatingPid,
- interrogatingTid, spec);
+ interrogatingTid, spec, args);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 839e11c01303..5bae594b5659 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -29,6 +29,15 @@ import android.view.autofill.VirtualViewDelegate;
* View.onProvideStructure}.
*/
public abstract class ViewStructure {
+
+ /**
+ * Flag used when adding virtual views for auto-fill, it indicates the contents of the view
+ * (such as * {@link android.app.assist.AssistStructure.ViewNode#getText()} and
+ * {@link android.app.assist.AssistStructure.ViewNode#getAutoFillValue()})
+ * can be passed to the {@link android.service.autofill.AutoFillService}.
+ */
+ public static final int AUTO_FILL_FLAG_SANITIZED = 0x1;
+
/**
* Set the identifier for this view.
*
@@ -264,8 +273,14 @@ public abstract class ViewStructure {
/**
* Like {@link #newChild(int)}, but providing a {@code virtualId} to the child so it can be
* auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+ *
+ * @param index child index
+ * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
+ * AutoFillValue)}.
+ * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
*/
- public abstract ViewStructure newChild(int index, int virtualId);
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract ViewStructure newChild(int index, int virtualId, int flags);
/**
* Like {@link #newChild}, but allows the caller to asynchronously populate the returned
@@ -280,15 +295,36 @@ public abstract class ViewStructure {
/**
* Like {@link #asyncNewChild(int)}, but providing a {@code virtualId} to the child so it can be
* auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+ *
+ * @param index child index
+ * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
+ * AutoFillValue)}.
+ * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
*/
- public abstract ViewStructure asyncNewChild(int index, int virtualId);
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags);
/**
* Sets the {@link AutoFillType} that can be used to auto-fill this node.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public abstract void setAutoFillType(AutoFillType info);
/**
+ * Sets the {@link AutoFillValue} representing the current value of this node.
+ */
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract void setAutoFillValue(AutoFillValue value);
+
+ /**
+ * @hide
+ *
+ * TODO(b/33197203, b/33269702): temporary set it as not sanitized until
+ * AssistStructure automaticaly sets sanitization based on text coming from resources
+ */
+ public abstract void setSanitized(boolean sensitive);
+
+ /**
* Call when done populating a {@link ViewStructure} returned by
* {@link #asyncNewChild}.
*/
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 8bc988d8de1a..0053caa78278 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -27,6 +27,7 @@ import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.annotation.SystemApi;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -573,6 +574,13 @@ public abstract class Window {
*/
default public void onProvideKeyboardShortcuts(
List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { };
+
+ /**
+ * Called when pointer capture is enabled or disabled for the current window.
+ *
+ * @param hasCapture True if the window has pointer capture.
+ */
+ default public void onPointerCaptureChanged(boolean hasCapture) { };
}
/** @hide */
@@ -1128,6 +1136,28 @@ public abstract class Window {
}
/**
+ * <p>Set the color mode of the window. Setting the color mode might
+ * override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
+ *
+ * <p>The color mode must be one of {@link ActivityInfo#COLOR_MODE_DEFAULT},
+ * {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} or {@link ActivityInfo#COLOR_MODE_HDR}.</p>
+ */
+ public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.setColorMode(colorMode);
+ dispatchWindowAttributesChanged(attrs);
+ }
+
+ /**
+ * Returns the color mode of the window, one of {@link ActivityInfo#COLOR_MODE_DEFAULT},
+ * {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} or {@link ActivityInfo#COLOR_MODE_HDR}.
+ */
+ @ActivityInfo.ColorMode
+ public int getColorMode() {
+ return getAttributes().getColorMode();
+ }
+
+ /**
* Set the amount of dim behind the window when using
* {@link WindowManager.LayoutParams#FLAG_DIM_BEHIND}. This overrides
* the default dim amount of that is selected by the Window based on
@@ -1894,7 +1924,7 @@ public abstract class Window {
public Transition getEnterTransition() { return null; }
/**
- * Returns he Transition that will be used to move Views out of the scene when the Window is
+ * Returns the Transition that will be used to move Views out of the scene when the Window is
* preparing to close, for example after a call to
* {@link android.app.Activity#finishAfterTransition()}. The exiting
* Views will be those that are regular Views or ViewGroups that have
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 8f2d2e15a019..02c8945d9fce 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -158,5 +158,10 @@ public class WindowCallbackWrapper implements Window.Callback {
List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
mWrapped.onProvideKeyboardShortcuts(data, menu, deviceId);
}
+
+ @Override
+ public void onPointerCaptureChanged(boolean hasCapture) {
+ mWrapped.onPointerCaptureChanged(hasCapture);
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e5a6ebdfb9e0..5a640faf08d3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -22,7 +22,6 @@ import android.app.KeyguardManager;
import android.app.Presentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.IBinder;
@@ -336,7 +335,9 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_QS_DIALOG,
to = "TYPE_QS_DIALOG"),
@ViewDebug.IntToString(from = TYPE_SCREENSHOT,
- to = "TYPE_SCREENSHOT")
+ to = "TYPE_SCREENSHOT"),
+ @ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY,
+ to = "TYPE_APPLICATION_OVERLAY")
})
public int type;
@@ -463,14 +464,18 @@ public interface WindowManager extends ViewManager {
* These windows are normally placed above all applications, but behind
* the status bar.
* In multiuser systems shows on all users' windows.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
/**
* Window type: system window, such as low power alert. These windows
* are always on top of application windows.
* In multiuser systems shows only on the owning user's window.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
/**
@@ -483,7 +488,9 @@ public interface WindowManager extends ViewManager {
/**
* Window type: transient notifications.
* In multiuser systems shows only on the owning user's window.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
/**
@@ -491,7 +498,9 @@ public interface WindowManager extends ViewManager {
* on top of everything else. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows only on the owning user's window.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;
/**
@@ -499,7 +508,9 @@ public interface WindowManager extends ViewManager {
* the keyguard is active. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows on all users' windows.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
/**
@@ -518,7 +529,9 @@ public interface WindowManager extends ViewManager {
* Window type: internal system error windows, appear on top of
* everything they can.
* In multiuser systems shows only on the owning user's window.
+ * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
+ @Deprecated
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;
/**
@@ -704,10 +717,44 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;
/**
+ * Window type: Application overlay windows are displayed above all activity windows
+ * (types between {@link #FIRST_APPLICATION_WINDOW} and {@link #LAST_APPLICATION_WINDOW})
+ * but below critical system windows like the status bar or IME.
+ * <p>
+ * The system may change the position, size, or visibility of these windows at anytime
+ * to reduce visual clutter to the user and also manage resources.
+ * <p>
+ * Requires {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission.
+ * <p>
+ * In mult-iuser systems shows only on the owning user's screen.
+ */
+ public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
+ /**
+ * Return true if the window type is an alert window.
+ *
+ * @param type The window type.
+ * @return If the window type is an alert window.
+ * @hide
+ */
+ public static boolean isSystemAlertWindowType(int type) {
+ switch (type) {
+ case TYPE_PHONE:
+ case TYPE_PRIORITY_PHONE:
+ case TYPE_SYSTEM_ALERT:
+ case TYPE_SYSTEM_ERROR:
+ case TYPE_SYSTEM_OVERLAY:
+ case TYPE_APPLICATION_OVERLAY:
+ return true;
+ }
+ return false;
+ }
+
/** @deprecated this is ignored, this value is set automatically when needed. */
@Deprecated
public static final int MEMORY_TYPE_NORMAL = 0;
@@ -1577,7 +1624,8 @@ public interface WindowManager extends ViewManager {
/**
* The desired bitmap format. May be one of the constants in
- * {@link android.graphics.PixelFormat}. Default is OPAQUE.
+ * {@link android.graphics.PixelFormat}. The choice of format
+ * might be overridden by {@link #setColorMode(int)}. Default is OPAQUE.
*/
public int format;
@@ -1833,6 +1881,17 @@ public interface WindowManager extends ViewManager {
*/
public long hideTimeoutMilliseconds = -1;
+ /**
+ * The color mode requested by this window. The target display may
+ * not be able to honor the request. When the color mode is not set
+ * to {@link ActivityInfo#COLOR_MODE_DEFAULT}, it might override the
+ * pixel format specified in {@link #format}.
+ *
+ * @hide
+ */
+ @ActivityInfo.ColorMode
+ private int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1912,6 +1971,31 @@ public interface WindowManager extends ViewManager {
preservePreviousSurfaceInsets = preservePrevious;
}
+ /**
+ * <p>Set the color mode of the window. Setting the color mode might
+ * override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
+ *
+ * <p>The color mode must be one of {@link ActivityInfo#COLOR_MODE_DEFAULT},
+ * {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} or
+ * {@link ActivityInfo#COLOR_MODE_HDR}.</p>
+ *
+ * @see #getColorMode()
+ */
+ public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
+ mColorMode = colorMode;
+ }
+
+ /**
+ * Returns the color mode of the window, one of {@link ActivityInfo#COLOR_MODE_DEFAULT},
+ * {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} or {@link ActivityInfo#COLOR_MODE_HDR}.
+ *
+ * @see #setColorMode(int)
+ */
+ @ActivityInfo.ColorMode
+ public int getColorMode() {
+ return mColorMode;
+ }
+
/** @hide */
@SystemApi
public final void setUserActivityTimeout(long timeout) {
@@ -2268,9 +2352,11 @@ public interface WindowManager extends ViewManager {
sb.append(',');
sb.append(y);
sb.append(")(");
- sb.append((width== MATCH_PARENT ?"fill":(width==WRAP_CONTENT?"wrap":width)));
+ sb.append((width == MATCH_PARENT ? "fill" : (width == WRAP_CONTENT
+ ? "wrap" : String.valueOf(width))));
sb.append('x');
- sb.append((height== MATCH_PARENT ?"fill":(height==WRAP_CONTENT?"wrap":height)));
+ sb.append((height == MATCH_PARENT ? "fill" : (height == WRAP_CONTENT
+ ? "wrap" : String.valueOf(height))));
sb.append(")");
if (horizontalMargin != 0) {
sb.append(" hm=");
@@ -2367,6 +2453,7 @@ public interface WindowManager extends ViewManager {
sb.append(" needsMenuKey=");
sb.append(needsMenuKey);
}
+ sb.append(" colorMode=").append(mColorMode);
sb.append('}');
return sb.toString();
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index bc4ae6d0fcf1..8e597dc40894 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -16,6 +16,51 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_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_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -30,6 +75,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Slog;
import android.view.animation.Animation;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -423,6 +469,14 @@ public interface WindowManagerPolicy {
public boolean isInputMethodWindow();
public int getDisplayId();
+
+ /**
+ * Returns true if the window owner can add internal system windows.
+ * That is, they have {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}.
+ */
+ default boolean canAddInternalSystemWindow() {
+ return false;
+ }
}
/**
@@ -659,27 +713,181 @@ public interface WindowManagerPolicy {
int navigationPresence);
/**
- * Assign a window type to a layer. Allows you to control how different
+ * Returns the layer assignment for the window state. Allows you to control how different
+ * kinds of windows are ordered on-screen.
+ *
+ * @param win The window state
+ * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
+ */
+ default int getWindowLayerLw(WindowState win) {
+ return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
+ }
+
+ /**
+ * Returns the layer assignment for the window type. Allows you to control how different
* kinds of windows are ordered on-screen.
*
* @param type The type of window being assigned.
+ * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
+ */
+ default int getWindowLayerFromTypeLw(int type) {
+ if (isSystemAlertWindowType(type)) {
+ throw new IllegalArgumentException("Use getWindowLayerFromTypeLw() or"
+ + " getWindowLayerLw() for alert window types");
+ }
+ return getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */);
+ }
+
+ /**
+ * Returns the layer assignment for the window type. Allows you to control how different
+ * kinds of windows are ordered on-screen.
*
- * @return int An arbitrary integer used to order windows, with lower
- * numbers below higher ones.
- */
- public int windowTypeToLayerLw(int type);
+ * @param type The type of window being assigned.
+ * @param canAddInternalSystemWindow If the owner window associated with the type we are
+ * evaluating can add internal system windows. I.e they have
+ * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
+ * types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
+ * can be assigned layers greater than the layer for
+ * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
+ * layers would be lesser.
+ * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
+ */
+ default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
+ if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
+ return APPLICATION_LAYER;
+ }
+
+ switch (type) {
+ case TYPE_WALLPAPER:
+ // wallpaper is at the bottom, though the window manager may move it.
+ return 1;
+ case TYPE_PRESENTATION:
+ case TYPE_PRIVATE_PRESENTATION:
+ return APPLICATION_LAYER;
+ case TYPE_DOCK_DIVIDER:
+ return APPLICATION_LAYER;
+ case TYPE_QS_DIALOG:
+ return APPLICATION_LAYER;
+ case TYPE_PHONE:
+ return 3;
+ case TYPE_SEARCH_BAR:
+ case TYPE_VOICE_INTERACTION_STARTING:
+ return 4;
+ case TYPE_VOICE_INTERACTION:
+ // voice interaction layer is almost immediately above apps.
+ return 5;
+ case TYPE_INPUT_CONSUMER:
+ return 6;
+ case TYPE_SYSTEM_DIALOG:
+ return 7;
+ case TYPE_TOAST:
+ // toasts and the plugged-in battery thing
+ return 8;
+ case TYPE_PRIORITY_PHONE:
+ // SIM errors and unlock. Not sure if this really should be in a high layer.
+ return 9;
+ case TYPE_DREAM:
+ // used for Dreams (screensavers with TYPE_DREAM windows)
+ return 10;
+ case TYPE_SYSTEM_ALERT:
+ // like the ANR / app crashed dialogs
+ return canAddInternalSystemWindow ? 11 : 10;
+ case TYPE_APPLICATION_OVERLAY:
+ return 13;
+ case TYPE_INPUT_METHOD:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 14;
+ case TYPE_INPUT_METHOD_DIALOG:
+ // on-screen keyboards and other such input method user interfaces go here.
+ return 15;
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ return 17;
+ case TYPE_STATUS_BAR:
+ return 18;
+ case TYPE_STATUS_BAR_PANEL:
+ return 19;
+ case TYPE_KEYGUARD_DIALOG:
+ return 20;
+ case TYPE_VOLUME_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return 21;
+ case TYPE_SYSTEM_OVERLAY:
+ // the on-screen volume indicator and controller shown when the user
+ // changes the device volume
+ return canAddInternalSystemWindow ? 22 : 11;
+ case TYPE_NAVIGATION_BAR:
+ // the navigation bar, if available, shows atop most things
+ return 23;
+ case TYPE_NAVIGATION_BAR_PANEL:
+ // some panels (e.g. search) need to show on top of the navigation bar
+ return 24;
+ case TYPE_SCREENSHOT:
+ // screenshot selection layer shouldn't go above system error, but it should cover
+ // navigation bars at the very least.
+ return 25;
+ case TYPE_SYSTEM_ERROR:
+ // system-level error dialogs
+ return canAddInternalSystemWindow ? 26 : 10;
+ case TYPE_MAGNIFICATION_OVERLAY:
+ // used to highlight the magnified portion of a display
+ return 27;
+ case TYPE_DISPLAY_OVERLAY:
+ // used to simulate secondary display devices
+ return 28;
+ case TYPE_DRAG:
+ // the drag layer: input for drag-and-drop is associated with this window,
+ // which sits above all other focusable windows
+ return 29;
+ case TYPE_ACCESSIBILITY_OVERLAY:
+ // overlay put by accessibility services to intercept user interaction
+ return 30;
+ case TYPE_SECURE_SYSTEM_OVERLAY:
+ return 31;
+ case TYPE_BOOT_PROGRESS:
+ return 32;
+ case TYPE_POINTER:
+ // the (mouse) pointer layer
+ return 33;
+ default:
+ Slog.e("WindowManager", "Unknown window type: " + type);
+ return APPLICATION_LAYER;
+ }
+ }
+
+ int APPLICATION_LAYER = 2;
+ int APPLICATION_MEDIA_SUBLAYER = -2;
+ int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
+ int APPLICATION_PANEL_SUBLAYER = 1;
+ int APPLICATION_SUB_PANEL_SUBLAYER = 2;
+ int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
/**
- * Return how to Z-order sub-windows in relation to the window they are
- * attached to. Return positive to have them ordered in front, negative for
- * behind.
+ * Return how to Z-order sub-windows in relation to the window they are attached to.
+ * Return positive to have them ordered in front, negative for behind.
*
* @param type The sub-window type code.
*
* @return int Layer in relation to the attached window, where positive is
* above and negative is below.
*/
- public int subWindowTypeToLayerLw(int type);
+ default int getSubWindowLayerFromTypeLw(int type) {
+ switch (type) {
+ case TYPE_APPLICATION_PANEL:
+ case TYPE_APPLICATION_ATTACHED_DIALOG:
+ return APPLICATION_PANEL_SUBLAYER;
+ case TYPE_APPLICATION_MEDIA:
+ return APPLICATION_MEDIA_SUBLAYER;
+ case TYPE_APPLICATION_MEDIA_OVERLAY:
+ return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+ case TYPE_APPLICATION_SUB_PANEL:
+ return APPLICATION_SUB_PANEL_SUBLAYER;
+ case TYPE_APPLICATION_ABOVE_SUB_PANEL:
+ return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
+ }
+ Slog.e("WindowManager", "Unknown sub-window type: " + type);
+ return 0;
+ }
/**
* Get the highest layer (actually one more than) that the wallpaper is
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index db2ea483f3ab..143c49a7db7e 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -554,7 +554,7 @@ public final class AccessibilityCache {
// Layer of indirection included to break dependency chain for testing
public static class AccessibilityNodeRefresher {
public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
- return info.refresh(bypassCache);
+ return info.refresh(null, bypassCache);
}
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 1543597efe10..828583cdfe81 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -159,7 +159,7 @@ public final class AccessibilityInteractionClient
public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
return findAccessibilityNodeInfoByAccessibilityId(connectionId,
AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
- false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+ false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
}
/**
@@ -259,7 +259,7 @@ public final class AccessibilityInteractionClient
*/
public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
- int prefetchFlags) {
+ int prefetchFlags, Bundle arguments) {
if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0
&& (prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) == 0) {
throw new IllegalArgumentException("FLAG_PREFETCH_SIBLINGS"
@@ -285,9 +285,8 @@ public final class AccessibilityInteractionClient
final long identityToken = Binder.clearCallingIdentity();
final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
- prefetchFlags, Thread.currentThread().getId());
+ prefetchFlags, Thread.currentThread().getId(), arguments);
Binder.restoreCallingIdentity(identityToken);
- // If the scale is zero the call has failed.
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index bfb8d8396665..45302b6cbdce 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -633,6 +633,28 @@ public final class AccessibilityManager {
}
/**
+ * Report a fingerprint gesture to accessibility. Only available for the system process.
+ *
+ * @param keyCode The key code of the gesture
+ * @return {@code true} if accessibility consumes the event. {@code false} if not.
+ * @hide
+ */
+ public boolean sendFingerprintGesture(int keyCode) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return false;
+ }
+ }
+ try {
+ return service.sendFingerprintGesture(keyCode);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Sets the current state and notifies listeners, if necessary.
*
* @param stateFlags The state flags.
@@ -757,6 +779,49 @@ public final class AccessibilityManager {
}
}
+ /**
+ * Notifies that the accessibility button in the system's navigation area has been clicked
+ *
+ * @hide
+ */
+ public void notifyAccessibilityButtonClicked() {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.notifyAccessibilityButtonClicked();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while dispatching accessibility button click", re);
+ }
+ }
+
+ /**
+ * Notifies that the availability of the accessibility button in the system's navigation area
+ * has changed.
+ *
+ * @param available {@code true} if the accessibility button is available within the system
+ * navigation area, {@code false} otherwise
+ * @hide
+ */
+ public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.notifyAccessibilityButtonAvailabilityChanged(available);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while dispatching accessibility button availability change", re);
+ }
+ }
+
private IAccessibilityManager getServiceLocked() {
if (mService == null) {
tryConnectToServiceLocked(null);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 56d45b097272..b0a11cd5b8e9 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -16,6 +16,8 @@
package android.view.accessibility;
+import static java.util.Collections.EMPTY_LIST;
+
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.Nullable;
@@ -517,6 +519,46 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
+ /**
+ * Key used to request and locate extra data for text character location. This key requests that
+ * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with
+ * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two
+ * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and
+ * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid
+ * inside the CharSequence returned by {@link #getText()}, and the length must be positive.
+ * <p>
+ * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this
+ * string as a key for {@link Bundle#getParcelableArray(String)}. The
+ * {@link android.graphics.RectF} will be null for characters that either do not exist or are
+ * off the screen.
+ *
+ * {@see #refreshWithExtraData(String, Bundle)}
+ */
+ public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY =
+ "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+
+ /**
+ * Integer argument specifying the start index of the requested text location data. Must be
+ * valid inside the CharSequence returned by {@link #getText()}.
+ *
+ * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
+ */
+ public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX =
+ "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+
+ /**
+ * Integer argument specifying the end index of the requested text location data. Must be
+ * positive.
+ *
+ * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
+ */
+ public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
+ "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+
+ /** @hide */
+ public static final String EXTRA_DATA_REQUESTED_KEY =
+ "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
+
// Boolean attributes.
private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
@@ -651,6 +693,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private CharSequence mError;
private CharSequence mContentDescription;
private String mViewIdResourceName;
+ private ArrayList<String> mExtraDataKeys;
private LongArray mChildNodeIds;
private ArrayList<AccessibilityAction> mActions;
@@ -786,14 +829,14 @@ public class AccessibilityNodeInfo implements Parcelable {
*
* @hide
*/
- public boolean refresh(boolean bypassCache) {
+ public boolean refresh(Bundle arguments, boolean bypassCache) {
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
- mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
+ mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments);
if (refreshedInfo == null) {
return false;
}
@@ -804,15 +847,33 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Refreshes this info with the latest state of the view it represents.
- * <p>
- * <strong>Note:</strong> If this method returns false this info is obsolete
- * since it represents a view that is no longer in the view tree and should
- * be recycled.
- * </p>
- * @return Whether the refresh succeeded.
+ *
+ * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
+ * by this node is no longer in the view tree (and thus this node is obsolete and should be
+ * recycled).
*/
public boolean refresh() {
- return refresh(true);
+ return refresh(null, true);
+ }
+
+ /**
+ * Refreshes this info with the latest state of the view it represents, and request new
+ * data be added by the View.
+ *
+ * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
+ * with this mechanism is generally expensive to retrieve, so should only be
+ * requested when needed. See
+ * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
+ * {@link #getAvailableExtraData()}.
+ * @param args A bundle of arguments for the request. These depend on the particular request.
+ *
+ * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
+ * by this node is no longer in the view tree (and thus this node is obsolete and should be
+ * recycled).
+ */
+ public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
+ args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
+ return refresh(args, true);
}
/**
@@ -872,7 +933,7 @@ public class AccessibilityNodeInfo implements Parcelable {
final long childId = mChildNodeIds.get(index);
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
- childId, false, FLAG_PREFETCH_DESCENDANTS);
+ childId, false, FLAG_PREFETCH_DESCENDANTS, null);
}
/**
@@ -1263,6 +1324,45 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Get the extra data available for this node.
+ * <p>
+ * Some data that is useful for some accessibility services is expensive to compute, and would
+ * place undue overhead on apps to compute all the time. That data can be requested with
+ * {@link #refreshWithExtraData(String, Bundle)}.
+ *
+ * @return An unmodifiable list of keys corresponding to extra data that can be requested.
+ * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
+ */
+ public List<String> getAvailableExtraData() {
+ if (mExtraDataKeys != null) {
+ return Collections.unmodifiableList(mExtraDataKeys);
+ } else {
+ return EMPTY_LIST;
+ }
+ }
+
+ /**
+ * Set the extra data available for this node.
+ * <p>
+ * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that
+ * it will populate the node's extras with corresponding pieces of information in
+ * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ *
+ * @param extraDataKeys A list of types of extra data that are available.
+ * @see #getAvailableExtraData()
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setAvailableExtraData(List<String> extraDataKeys) {
+ enforceNotSealed();
+ mExtraDataKeys = new ArrayList<>(extraDataKeys);
+ }
+
+ /**
* Sets the maximum text length, or -1 for no limit.
* <p>
* Typically used to indicate that an editable text field has a limit on
@@ -2658,6 +2758,14 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Check if a node has an extras bundle
+ * @hide
+ */
+ public boolean hasExtras() {
+ return mExtras != null;
+ }
+
+ /**
* Gets the value of a boolean property.
*
* @param property The property.
@@ -2955,6 +3063,12 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeInt(mInputType);
parcel.writeInt(mLiveRegion);
parcel.writeInt(mDrawingOrderInParent);
+ if (mExtraDataKeys != null) {
+ parcel.writeInt(1);
+ parcel.writeStringList(mExtraDataKeys);
+ } else {
+ parcel.writeInt(0);
+ }
if (mExtras != null) {
parcel.writeInt(1);
@@ -3054,6 +3168,8 @@ public class AccessibilityNodeInfo implements Parcelable {
mInputType = other.mInputType;
mLiveRegion = other.mLiveRegion;
mDrawingOrderInParent = other.mDrawingOrderInParent;
+ mExtraDataKeys = other.mExtraDataKeys;
+
if (other.mExtras != null) {
mExtras = new Bundle(other.mExtras);
} else {
@@ -3137,6 +3253,12 @@ public class AccessibilityNodeInfo implements Parcelable {
mDrawingOrderInParent = parcel.readInt();
if (parcel.readInt() == 1) {
+ mExtraDataKeys = parcel.createStringArrayList();
+ } else {
+ mExtraDataKeys = null;
+ }
+
+ if (parcel.readInt() == 1) {
mExtras = parcel.readBundle();
} else {
mExtras = null;
@@ -3455,7 +3577,7 @@ public class AccessibilityNodeInfo implements Parcelable {
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index abcbb7044de8..722b659e8fdc 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -102,6 +102,27 @@ public abstract class AccessibilityNodeProvider {
}
/**
+ * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+ * additional data.
+ * <p>
+ * This method only needs to be implemented if a virtual view offers to provide additional
+ * data.
+ * </p>
+ *
+ * @param virtualViewId The virtual view id used to create the node
+ * @param info The info to which to add the extra data
+ * @param extraDataKey A key specifying the type of extra data to add to the info. The
+ * extra data should be added to the {@link Bundle} returned by
+ * the info's {@link AccessibilityNodeInfo#getExtras} method.
+ * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+ *
+ * @see AccessibilityNodeInfo#setExtraAvailableData
+ */
+ public void addExtraDataToAccessibilityNodeInfo(
+ int virtualViewId, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+ }
+
+ /**
* Performs an accessibility action on a virtual view, i.e. a descendant of the
* host View, with the given <code>virtualViewId</code> or the host View itself
* if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 3287298c5a6b..c3904060247a 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -183,7 +183,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mId, AccessibilityNodeInfo.ROOT_NODE_ID,
- true, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+ true, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
}
/**
@@ -209,7 +209,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mParentId, mAnchorId, true, 0);
+ mParentId, mAnchorId, true, 0, null);
}
/**
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index cecc4af49e2e..4c0fdfd5afdf 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -33,7 +33,8 @@ oneway interface IAccessibilityInteractionConnection {
void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds,
int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
- int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
+ int interrogatingPid, long interrogatingTid, in MagnificationSpec spec,
+ in Bundle arguments);
void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index ed77f68f2195..8fde47a30b2b 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -1,5 +1,4 @@
-/* //device/java/android/android/app/INotificationManager.aidl
-**
+/*
** Copyright 2009, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -60,6 +59,13 @@ interface IAccessibilityManager {
IBinder getWindowToken(int windowId, int userId);
+ void notifyAccessibilityButtonClicked();
+
+ void notifyAccessibilityButtonAvailabilityChanged(boolean available);
+
// Requires WRITE_SECURE_SETTINGS
void performAccessibilityShortcut();
+
+ // System process only
+ boolean sendFingerprintGesture(int gestureKeyCode);
}
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index df2f18c21735..7fa49c1a6c8f 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -150,7 +150,7 @@ public class LayoutAnimationController {
* Returns the order used to compute the delay of each child's animation.
*
* @return one of {@link #ORDER_NORMAL}, {@link #ORDER_REVERSE} or
- * {@link #ORDER_RANDOM)
+ * {@link #ORDER_RANDOM}
*
* @attr ref android.R.styleable#LayoutAnimation_animationOrder
*/
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
index b7b694d26030..3dbf5a8b0415 100644
--- a/core/java/android/view/autofill/AutoFillId.java
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -29,6 +29,7 @@ public final class AutoFillId implements Parcelable {
private boolean mVirtual;
private int mVirtualId;
+ // TODO(b/33197203): use factory and cache values, since they're immutable
/** @hide */
public AutoFillId(int id) {
mVirtual = false;
@@ -43,6 +44,13 @@ public final class AutoFillId implements Parcelable {
}
/** @hide */
+ public AutoFillId(int parentId, int virtualChildId) {
+ mVirtual = true;
+ mViewId = parentId;
+ mVirtualId = virtualChildId;
+ }
+
+ /** @hide */
public int getViewId() {
return mViewId;
}
diff --git a/core/java/android/view/autofill/AutoFillManager.java b/core/java/android/view/autofill/AutoFillManager.java
new file mode 100644
index 000000000000..58607ba51579
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillManager.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.VERBOSE;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.autofill.IAutoFillManagerService;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * App entry point to the AutoFill Framework.
+ */
+// TODO(b/33197203): improve this javadoc
+//TODO(b/33197203): restrict manager calls to activity
+public final class AutoFillManager {
+
+ private static final String TAG = "AutoFillManager";
+
+ /** @hide */ public static final int FLAG_START_SESSION = 0x1;
+ /** @hide */ public static final int FLAG_FOCUS_GAINED = 0x2;
+ /** @hide */ public static final int FLAG_FOCUS_LOST = 0x4;
+ /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x8;
+
+ private final IAutoFillManagerService mService;
+ private final Context mContext;
+
+ private AutoFillSession mSession;
+
+ /**
+ * @hide
+ */
+ public AutoFillManager(Context context, IAutoFillManagerService service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Called to indicate the focus on an auto-fillable {@link View} changed.
+ *
+ * @param view view whose focus changed.
+ * @param gainFocus whether focus was gained or lost.
+ */
+ public void focusChanged(View view, boolean gainFocus) {
+ if (mSession == null) {
+ // Starts new session.
+ final Rect bounds = new Rect();
+ view.getBoundsOnScreen(bounds);
+ final AutoFillId id = getAutoFillId(view);
+ final AutoFillValue value = view.getAutoFillValue();
+ startSession(id, bounds, value);
+ return;
+ }
+
+ if (!mSession.isEnabled()) {
+ // Auto-fill is disabled for this session.
+ return;
+ }
+
+ // Update focus on existing session.
+ final Rect bounds = new Rect();
+ view.getBoundsOnScreen(bounds);
+ final AutoFillId id = getAutoFillId(view);
+ final AutoFillValue value = view.getAutoFillValue();
+ updateSession(id, bounds, value, gainFocus ? FLAG_FOCUS_GAINED : FLAG_FOCUS_LOST);
+ }
+
+ /**
+ * Called to indicate the focus on an auto-fillable virtual {@link View} changed.
+ *
+ * @param parent parent view whose focus changed.
+ * @param childId id identifying the virtual child inside the parent view.
+ * @param bounds child boundaries, relative to the top window.
+ * @param gainFocus whether focus was gained or lost.
+ */
+ public void virtualFocusChanged(View parent, int childId, Rect bounds, boolean gainFocus) {
+ if (mSession == null) {
+ // Starts new session.
+ final AutoFillId id = getAutoFillId(parent, childId);
+ startSession(id, bounds, null);
+ return;
+ }
+
+ if (!mSession.isEnabled()) {
+ // Auto-fill is disabled for this session.
+ return;
+ }
+
+ // Update focus on existing session.
+ final AutoFillId id = getAutoFillId(parent, childId);
+ updateSession(id, bounds, null, gainFocus ? FLAG_FOCUS_GAINED : FLAG_FOCUS_LOST);
+ }
+
+ /**
+ * Called to indicate the value of an auto-fillable {@link View} changed.
+ *
+ * @param view view whose focus changed.
+ */
+ public void valueChanged(View view) {
+ if (mSession == null) return;
+
+ final AutoFillId id = getAutoFillId(view);
+ final AutoFillValue value = view.getAutoFillValue();
+ updateSession(id, null, value, FLAG_VALUE_CHANGED);
+ }
+
+
+ /**
+ * Called to indicate the value of an auto-fillable virtual {@link View} changed.
+ *
+ * @param parent parent view whose value changed.
+ * @param childId id identifying the virtual child inside the parent view.
+ * @param value new value of the child.
+ */
+ public void virtualValueChanged(View parent, int childId, AutoFillValue value) {
+ if (mSession == null) return;
+
+ final AutoFillId id = getAutoFillId(parent, childId);
+ updateSession(id, null, value, FLAG_VALUE_CHANGED);
+ }
+
+ /**
+ * Called to indicate the current auto-fill context should be reset.
+ *
+ * <p>For example, when a virtual view is rendering an {@code HTML} page with a form, it should
+ * call this method after the form is submitted and another page is rendered.
+ */
+ public void reset() {
+ if (mSession == null) return;
+
+ final IBinder activityToken = mSession.mToken.get();
+ if (activityToken == null) {
+ Log.wtf(TAG, "finishSession(): token already GC'ed");
+ return;
+ }
+ try {
+ mService.finishSession(activityToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ mSession = null;
+ }
+ }
+
+ /**
+ * Gets the current session, if any.
+ *
+ * @hide
+ */
+ @Nullable
+ public AutoFillSession getSession() {
+ return mSession;
+ }
+
+ private AutoFillId getAutoFillId(View view) {
+ return new AutoFillId(view.getAccessibilityViewId());
+ }
+
+ private AutoFillId getAutoFillId(View parent, int childId) {
+ return new AutoFillId(parent.getAccessibilityViewId(), childId);
+ }
+
+ private void startSession(AutoFillId id, Rect bounds, AutoFillValue value) {
+ if (VERBOSE) {
+ Log.v(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
+ }
+
+ final IBinder activityToken = mContext.getActivityToken();
+ mSession = new AutoFillSession(this, activityToken);
+ final IBinder appCallback = mSession.getCallback().asBinder();
+ try {
+ mService.startSession(activityToken, appCallback, id, bounds, value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void updateSession(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
+ if (VERBOSE) {
+ Log.v(TAG, "updateSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ + ", flags=" + flags);
+ }
+
+ final IBinder activityToken = mSession.mToken.get();
+ if (activityToken == null) {
+ return;
+ }
+ try {
+ mService.updateSession(activityToken, id, bounds, value, flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/view/autofill/AutoFillSession.java b/core/java/android/view/autofill/AutoFillSession.java
new file mode 100644
index 000000000000..e10ba373cf40
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillSession.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.IBinder;
+import android.service.autofill.IAutoFillAppCallback;
+import android.util.Log;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * An auto-fill session associated with an activity.
+ *
+ * @hide
+ */
+public final class AutoFillSession {
+
+ private static final String TAG = "AutoFillSession";
+
+ private final IAutoFillAppCallback mCallback = new IAutoFillAppCallback.Stub() {
+
+ @Override
+ public void enableSession() {
+ if (DEBUG) Log.d(TAG, "enableSession()");
+
+ mEnabled = true;
+ }
+
+ @Override
+ public void autoFill(Dataset dataset) {
+ final Activity activity = mActivity.get();
+ if (activity == null) {
+ if (DEBUG) Log.d(TAG, "autoFill(): activity already GCed");
+ return;
+ }
+ // TODO(b/33197203): must keep the dataset so subsequent calls pass the same
+ // dataset.extras to service
+ activity.runOnUiThread(() -> {
+ final View root = activity.getWindow().getDecorView().getRootView();
+ final int itemCount = dataset.getFieldIds().size();
+ for (int i = 0; i < itemCount; i++) {
+ final AutoFillId id = dataset.getFieldIds().get(i);
+ final AutoFillValue value = dataset.getFieldValues().get(i);
+ final int viewId = id.getViewId();
+ final View view = root.findViewByAccessibilityIdTraversal(viewId);
+ if (view == null) {
+ Log.w(TAG, "autoFill(): no View with id " + viewId);
+ continue;
+ }
+
+ // TODO(b/33197203): handle protected value (like credit card)
+ if (id.isVirtual()) {
+ // Delegate virtual fields.
+ final VirtualViewDelegate delegate = view
+ .getAutoFillVirtualViewDelegate();
+ if (delegate == null) {
+ Log.w(TAG, "autoFill(): cannot fill virtual " + id
+ + "; no VirtualViewDelegate for view "
+ + view.getClass());
+ continue;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "autoFill(): delegating " + id
+ + " to VirtualViewDelegate " + delegate);
+ }
+ delegate.autoFill(id.getVirtualChildId(), value);
+ } else {
+ // Handle non-virtual fields itself.
+ view.autoFill(value);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent, Intent fillInIntent) {
+ final Activity activity = mActivity.get();
+ if (activity != null) {
+ activity.runOnUiThread(() -> {
+ try {
+ activity.startIntentSender(intent, fillInIntent, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ Log.e(TAG, "startIntentSender() failed for intent:" + intent, e);
+ }
+ });
+ }
+ }
+ };
+
+ private final AutoFillManager mAfm;
+ private WeakReference<Activity> mActivity;
+
+ // Reference to the token, which is used by the server.
+ final WeakReference<IBinder> mToken;
+
+ private boolean mEnabled;
+
+ public AutoFillSession(AutoFillManager afm, IBinder token) {
+ mToken = new WeakReference<>(token);
+ mAfm = afm;
+ }
+
+ /**
+ * Called by the {@link Activity} when it was asked to provider auto-fill data.
+ */
+ public void attachActivity(Activity activity) {
+ if (mActivity != null) {
+ Log.w(TAG, "attachActivity(): already attached");
+ return;
+ }
+ mActivity = new WeakReference<>(activity);
+ }
+
+ /**
+ * Checks whether auto-fill is enabled for this session, as decided by the
+ * {@code AutoFillManagerService}.
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ /**
+ * Notifies the manager that a session finished.
+ */
+ // TODO(b/33197203): hook it to other lifecycle events like fragments transition
+ public void finishSession() {
+ if (mAfm != null) {
+ try {
+ mAfm.reset();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed to finish session for " + mToken.get() + ": " + e);
+ }
+ }
+ }
+
+ public IAutoFillAppCallback getCallback() {
+ return mCallback;
+ }
+
+ @Override
+ public String toString() {
+ if (!DEBUG) return super.toString();
+
+ return "AutoFillSession[activityoken=" + mToken.get() + "]";
+ }
+}
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
index c39f26b9b864..b31f4aff2b1c 100644
--- a/core/java/android/view/autofill/AutoFillValue.java
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -18,6 +18,7 @@ package android.view.autofill;
import static android.view.autofill.Helper.DEBUG;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View;
@@ -32,12 +33,12 @@ import android.view.View;
*/
public final class AutoFillValue implements Parcelable {
- private final CharSequence mText;
+ private final String mText;
private final int mListIndex;
private final boolean mToggle;
private AutoFillValue(CharSequence text, int listIndex, boolean toggle) {
- mText = text;
+ mText = (text == null) ? null : text.toString();
mListIndex = listIndex;
mToggle = toggle;
}
@@ -74,6 +75,32 @@ public final class AutoFillValue implements Parcelable {
/////////////////////////////////////
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mListIndex;
+ result = prime * result + ((mText == null) ? 0 : mText.hashCode());
+ result = prime * result + (mToggle ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final AutoFillValue other = (AutoFillValue) obj;
+ if (mListIndex != other.mListIndex) return false;
+ if (mText == null) {
+ if (other.mText != null) return false;
+ } else {
+ if (!mText.equals(other.mText)) return false;
+ }
+ if (mToggle != other.mToggle) return false;
+ return true;
+ }
+
+ @Override
public String toString() {
if (!DEBUG) return super.toString();
@@ -92,13 +119,13 @@ public final class AutoFillValue implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeCharSequence(mText);
+ parcel.writeString(mText);
parcel.writeInt(mListIndex);
parcel.writeInt(mToggle ? 1 : 0);
}
private AutoFillValue(Parcel parcel) {
- mText = parcel.readCharSequence();
+ mText = parcel.readString();
mListIndex = parcel.readInt();
mToggle = parcel.readInt() == 1;
}
@@ -126,8 +153,10 @@ public final class AutoFillValue implements Parcelable {
*
* <p>See {@link AutoFillType#isText()} for more info.
*/
- public static AutoFillValue forText(CharSequence value) {
- return new AutoFillValue(value, 0, false);
+ // TODO(b/33197203): use cache
+ @Nullable
+ public static AutoFillValue forText(@Nullable CharSequence value) {
+ return value == null ? null : new AutoFillValue(value, 0, false);
}
/**
diff --git a/core/java/android/view/autofill/Dataset.java b/core/java/android/view/autofill/Dataset.java
index a73eb7740e80..2708358c3143 100644
--- a/core/java/android/view/autofill/Dataset.java
+++ b/core/java/android/view/autofill/Dataset.java
@@ -17,20 +17,19 @@
package android.view.autofill;
import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.append;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.assist.AssistStructure.ViewNode;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.service.autofill.AutoFillService;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
/**
* A set of data that can be used to auto-fill an {@link Activity}.
@@ -43,104 +42,242 @@ import java.util.Objects;
* <li>An optional {@link Bundle} with extras (used only by the service creating it).
* </ol>
*
- * See {@link FillResponse} for examples.
+ * @see FillResponse for examples.
*/
public final class Dataset implements Parcelable {
-
+ private final String mId;
private final CharSequence mName;
- private final ArrayList<DatasetField> mFields;
+ private final ArrayList<AutoFillId> mFieldIds;
+ private final ArrayList<AutoFillValue> mFieldValues;
private final Bundle mExtras;
+ private final IntentSender mAuthentication;
- private Dataset(Dataset.Builder builder) {
+ private Dataset(Builder builder) {
+ mId = builder.mId;
mName = builder.mName;
- // TODO(b/33197203): make an immutable copy of mFields?
- mFields = builder.mFields;
+ mFieldIds = builder.mFieldIds;
+ mFieldValues = builder.mFieldValues;
mExtras = builder.mExtras;
+ mAuthentication = builder.mAuthentication;
+ }
+
+ /** @hide */
+ public @NonNull String getId() {
+ return mId;
}
/** @hide */
- public CharSequence getName() {
+ public @NonNull CharSequence getName() {
return mName;
}
/** @hide */
- public List<DatasetField> getFields() {
- return mFields;
+ public @Nullable ArrayList<AutoFillId> getFieldIds() {
+ return mFieldIds;
+ }
+
+ /** @hide */
+ public @Nullable ArrayList<AutoFillValue> getFieldValues() {
+ return mFieldValues;
}
/** @hide */
- public Bundle getExtras() {
+ public @Nullable Bundle getExtras() {
return mExtras;
}
+ /** @hide */
+ public @Nullable IntentSender getAuthentication() {
+ return mAuthentication;
+ }
+
+ /** @hide */
+ public boolean isEmpty() {
+ return mFieldIds == null || mFieldIds.isEmpty();
+ }
+
@Override
public String toString() {
if (!DEBUG) return super.toString();
- final StringBuilder builder = new StringBuilder("Dataset [name=").append(mName)
- .append(", fields=").append(mFields).append(", extras=");
- append(builder, mExtras);
+ final StringBuilder builder = new StringBuilder("Dataset [id=").append(mId)
+ .append(", name=").append(mName)
+ .append(", fieldIds=").append(mFieldIds)
+ .append(", fieldValues=").append(mFieldValues)
+ .append(", hasAuthentication=").append(mAuthentication != null)
+ .append(", hasExtras=").append(mExtras != null);
return builder.append(']').toString();
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Dataset other = (Dataset) obj;
+ if (mId == null) {
+ if (other.mId != null) {
+ return false;
+ }
+ } else if (!mId.equals(other.mId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return mId != null ? mId.hashCode() : 0;
+ }
+
/**
- * A builder for {@link Dataset} objects.
+ * A builder for {@link Dataset} objects. You must to provide at least
+ * one value for a field or set an authentication intent.
*/
public static final class Builder {
+ private String mId;
private CharSequence mName;
- private final ArrayList<DatasetField> mFields = new ArrayList<>();
+ private ArrayList<AutoFillId> mFieldIds;
+ private ArrayList<AutoFillValue> mFieldValues;
private Bundle mExtras;
+ private IntentSender mAuthentication;
+ private boolean mDestroyed;
+
+ /** @hide */
+ // TODO(b/33197203): Remove once GCore migrates
+ public Builder(@NonNull CharSequence name) {
+ this(String.valueOf(System.currentTimeMillis()), name);
+ }
/**
* Creates a new builder.
*
+ * @param id A required id to identify this dataset for future interactions related to it.
* @param name Name used to identify the dataset in the UI. Typically it's the same value as
- * the first field in the dataset (like username or email address) or an user-provided name
+ * the first field in the dataset (like username or email address) or a user-provided name
* (like "My Work Address").
*/
- public Builder(CharSequence name) {
+ public Builder(@NonNull String id, @NonNull CharSequence name) {
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty or null");
mName = Preconditions.checkStringNotEmpty(name, "name cannot be empty or null");
}
/**
- * Sets the value of a field.
+ * Requires a dataset authentication before auto-filling the activity with this dataset.
*
- * @param id id returned by {@link ViewNode#getAutoFillId()}.
- * @param value value to be auto filled.
+ * <p>This method is called when you need to provide an authentication
+ * UI for the dataset. For example, when a dataset contains credit card information
+ * (such as number, expiration date, and verification code), you can display UI
+ * asking for the verification code to before filing in the data). Even if the
+ * dataset is completely populated the system will launch the specified authentication
+ * intent and will need your approval to fill it in. Since the dataset is "locked"
+ * until the user authenticates it, typically this dataset name is masked
+ * (for example, "VISA....1234"). Typically you would want to store the dataset
+ * labels non-encypted and the actual sensitive data encrypted and not in memory.
+ * This allows showing the labels in the UI while involving the user if one of
+ * the items with these labels is chosen. Note that if you use sensitive data as
+ * a label, for example an email address, then it should also be encrypted.
+ *</p>
+ *
+ * <p>When a user selects this dataset, the system triggers the provided intent
+ * whose extras will have the {@link android.content.Intent#EXTRA_AUTO_FILL_ITEM_ID id}
+ * of the {@link android.view.autofill.Dataset dataset} to authenticate, the {@link
+ * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} associated with this
+ * dataset, and a {@link android.content.Intent#EXTRA_AUTO_FILL_CALLBACK callback}
+ * to dispatch the authentication result.</p>
+ *
+ * <p>Once you complete your authentication flow you should use the provided callback
+ * to notify for a failure or a success. In case of a success you need to provide
+ * only the fully populated dataset that is being authenticated. For example, if you
+ * provided a {@link FillResponse} with two {@link Dataset}s and marked that
+ * only the first dataset needs an authentication then in the provided response
+ * you need to provide only the fully populated dataset being authenticated instead
+ * of both of them.
+ * </p>
+ *
+ * <p>The indent sender mechanism allows you to have your authentication UI
+ * implemented as an activity or a service or a receiver. However, the recommended
+ * way is to do this is with an activity which the system will start in the
+ * filled activity's task meaning it will properly work with back, recent apps, and
+ * free-form multi-window, while avoiding the need for the "draw on top of other"
+ * apps special permission. You can still theme your authentication activity's
+ * UI to look like a dialog if desired.</p>
+ *
+ * <p></><strong>Note:</strong> Do not make the provided intent sender
+ * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
+ * platform needs to fill in the authentication arguments.</p>
+ *
+ * @param authentication Intent to trigger your authentication flow.
+ *
+ * @see android.app.PendingIntent#getIntentSender()
*/
- public Dataset.Builder setValue(AutoFillId id, AutoFillValue value) {
- putField(new DatasetField(id, value));
+ public @NonNull Builder setAuthentication(@Nullable IntentSender authentication) {
+ throwIfDestroyed();
+ mAuthentication = authentication;
return this;
}
/**
- * Creates a new {@link Dataset} instance.
+ * Sets the value of a field.
+ *
+ * @param id id returned by {@link ViewNode#getAutoFillId()}.
+ * @param value value to be auto filled.
*/
- public Dataset build() {
- return new Dataset(this);
+ public @NonNull Builder setValue(@NonNull AutoFillId id, @NonNull AutoFillValue value) {
+ throwIfDestroyed();
+ Preconditions.checkNotNull(id, "id cannot be null");
+ Preconditions.checkNotNull(value, "value cannot be null");
+ if (mFieldIds != null) {
+ final int existingIdx = mFieldIds.indexOf(id);
+ if (existingIdx >= 0) {
+ mFieldValues.set(existingIdx, value);
+ return this;
+ }
+ } else {
+ mFieldIds = new ArrayList<>();
+ mFieldValues = new ArrayList<>();
+ }
+ mFieldIds.add(id);
+ mFieldValues.add(value);
+ return this;
}
/**
- * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
- * methods such as
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
- * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
- * {@link AutoFillService#EXTRA_DATASET_EXTRAS} as the key.
- *
- * <p>It can be used to keep service state in between calls.
+ * Sets a {@link Bundle} that will be passed to subsequent APIs that
+ * manipulate this dataset. For example, they are passed in as {@link
+ * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} to your
+ * authentication flow.
*/
- public Builder setExtras(Bundle extras) {
- mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+ public @NonNull Builder setExtras(@Nullable Bundle extras) {
+ throwIfDestroyed();
+ mExtras = extras;
return this;
}
/**
- * Emulates {@code Map.put()} by adding a new field to the list if its id is not the yet,
- * or replacing the existing one.
+ * Creates a new {@link Dataset} instance. You should not interact
+ * with this builder once this method is called.
*/
- private void putField(DatasetField field) {
- // TODO(b/33197203): check if already exists and replaces it if so
- mFields.add(field);
+ public @NonNull Dataset build() {
+ throwIfDestroyed();
+ mDestroyed = true;
+ if (mFieldIds == null && mAuthentication == null) {
+ throw new IllegalArgumentException(
+ "at least one value or an authentication must be set");
+ }
+ return new Dataset(this);
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Already called #build()");
+ }
}
}
@@ -155,22 +292,33 @@ public final class Dataset implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mId);
parcel.writeCharSequence(mName);
- parcel.writeList(mFields);
+ parcel.writeTypedArrayList(mFieldIds, 0);
+ parcel.writeTypedArrayList(mFieldValues, 0);
parcel.writeBundle(mExtras);
- }
-
- @SuppressWarnings("unchecked")
- private Dataset(Parcel parcel) {
- mName = parcel.readCharSequence();
- mFields = parcel.readArrayList(null);
- mExtras = parcel.readBundle();
+ parcel.writeParcelable(mAuthentication, flags);
}
public static final Parcelable.Creator<Dataset> CREATOR = new Parcelable.Creator<Dataset>() {
@Override
- public Dataset createFromParcel(Parcel source) {
- return new Dataset(source);
+ public Dataset createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final Builder builder = new Builder(parcel.readString(), parcel.readCharSequence());
+ final ArrayList<AutoFillId> ids = parcel.readTypedArrayList(null);
+ final ArrayList<AutoFillValue> values = parcel.readTypedArrayList(null);
+ final int idCount = (ids != null) ? ids.size() : 0;
+ final int valueCount = (values != null) ? values.size() : 0;
+ for (int i = 0; i < idCount; i++) {
+ AutoFillId id = ids.get(i);
+ AutoFillValue value = (valueCount > i) ? values.get(i) : null;
+ builder.setValue(id, value);
+ }
+ builder.setExtras(parcel.readBundle());
+ builder.setAuthentication(parcel.readParcelable(null));
+ return builder.build();
}
@Override
diff --git a/core/java/android/view/autofill/DatasetField.java b/core/java/android/view/autofill/DatasetField.java
deleted file mode 100644
index c6b92acd5759..000000000000
--- a/core/java/android/view/autofill/DatasetField.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.autofill;
-
-import static android.view.autofill.Helper.DEBUG;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public final class DatasetField implements Parcelable {
-
- private final AutoFillId mId;
- private final AutoFillValue mValue;
-
- DatasetField(AutoFillId id, AutoFillValue value) {
- mId = id;
- mValue = value;
- }
-
- public AutoFillId getId() {
- return mId;
- }
-
- public AutoFillValue getValue() {
- return mValue;
- }
-
- /////////////////////////////////
- // Object "contract" methods. //
- /////////////////////////////////
-
- @Override
- public String toString() {
- if (!DEBUG) return super.toString();
-
- return "DatasetField [id=" + mId + ", value=" + mValue + "]";
- }
-
- /////////////////////////////////////
- // Parcelable "contract" methods. //
- /////////////////////////////////////
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeParcelable(mId, 0);
- parcel.writeParcelable(mValue, 0);
- }
-
- private DatasetField(Parcel parcel) {
- mId = parcel.readParcelable(null);
- mValue = parcel.readParcelable(null);
- }
-
- public static final Parcelable.Creator<DatasetField> CREATOR =
- new Parcelable.Creator<DatasetField>() {
- @Override
- public DatasetField createFromParcel(Parcel source) {
- return new DatasetField(source);
- }
-
- @Override
- public DatasetField[] newArray(int size) {
- return new DatasetField[size];
- }
- };
-}
diff --git a/core/java/android/view/autofill/FillResponse.java b/core/java/android/view/autofill/FillResponse.java
index 3a147674965e..596a06c28d57 100644
--- a/core/java/android/view/autofill/FillResponse.java
+++ b/core/java/android/view/autofill/FillResponse.java
@@ -16,32 +16,30 @@
package android.view.autofill;
import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.append;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.service.autofill.AutoFillService;
+import android.util.ArraySet;
import com.android.internal.util.Preconditions;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
/**
- * Response for a
- * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
- * android.os.CancellationSignal, android.service.autofill.FillCallback)}
- * request.
+ * Response for a {@link
+ * android.service.autofill.AutoFillService#onFillRequest(android.app.assist.AssistStructure,
+ * Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)} and
+ * authentication requests.
*
* <p>The response typically contains one or more {@link Dataset}s, each representing a set of
- * fields that can be auto-filled together. For example, for a login page with username/password
- * where the user only have one account in the service, the response could be:
+ * fields that can be auto-filled together, and the Android system displays a dataset picker UI
+ * affordance that the user must use before the {@link Activity} is filled with the dataset.
+ *
+ * <p>For example, for a login page with username/password where the user only has one account in
+ * the response could be:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
@@ -67,9 +65,9 @@ import java.util.Set;
* .build();
* </pre>
*
- * <p>If the user does not have any data associated with this {@link Activity} but the service
- * wants to offer the user the option to save the data that was entered, then the service could
- * populate the response with {@code savableIds} instead of {@link Dataset}s:
+ * <p>If the user does not have any data associated with this {@link Activity} but the service wants
+ * to offer the user the option to save the data that was entered, then the service could populate
+ * the response with {@code savableIds} instead of {@link Dataset}s:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
@@ -79,8 +77,8 @@ import java.util.Set;
*
* <p>Similarly, there might be cases where the user data on the service is enough to populate some
* fields but not all, and the service would still be interested on saving the other fields. In this
- * scenario, the service could populate the response with both {@link Dataset}s and
- * {@code savableIds}:
+ * scenario, the service could populate the response with both {@link Dataset}s and {@code
+ * savableIds}:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
@@ -98,12 +96,17 @@ import java.util.Set;
* <p>Notice that the ids that are part of a dataset (ids 1 to 4, in this example) are automatically
* added to the {@code savableIds} list.
*
- * <p>If the service has multiple {@link Dataset}s with multiple options for some fields on each
- * dataset (for example, multiple accounts with both a home and work address), then it should
- * "partition" the {@link Activity} in sections and populate the response with just a subset of the
- * data that would fulfill the first section; then once the user fills the first section and taps
- * a field from the next section, the Android system would issue another request for that section,
- * and so on. For example, the first response could be:
+ * <p>If the service has multiple {@link Dataset}s for different sections of the activity,
+ * for example, a user section for which there are two datasets followed by an address
+ * section for which there are two datasets for each user user, then it should "partition"
+ * the activity in sections and populate the response with just a subset of the data that would
+ * fulfill the first section (the name in our example); then once the user fills the first
+ * section and taps a field from the next section (the address in our example), the Android
+ * system would issue another request for that section, and so on. Note that if the user
+ * chooses to populate the first section with a service provided dataset, the subsequent request
+ * would contain the populated values so you don't try to provide suggestions for the first
+ * section but ony for the second one based on the context of what was already filled. For
+ * example, the first response could be:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
@@ -128,103 +131,223 @@ import java.util.Set;
* .setTextFieldValue(id4, "Springfield")
* .build())
* .add(new Dataset.Builder("Work")
- * .setTextFieldValue(id3, "Springfield Nuclear Power Plant")
+ * .setTextFieldValue(id3, "Springfield Power Plant")
* .setTextFieldValue(id4, "Springfield")
* .build())
* .build();
* </pre>
*
- * <p>Finally, the service can use the {@link FillResponse.Builder#setExtras(Bundle)} and/or
- * {@link Dataset.Builder#setExtras(Bundle)} methods to pass
- * a {@link Bundle} with service-specific data use to identify this response on future calls (like
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
- * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) - such bundle will be
- * available as the {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} extra in
- * that method's {@code extras} argument.
+ * <p>The service could require user authentication at the {@link FillResponse} or the
+ * {@link Dataset} level, prior to auto-filling an activity - see {@link FillResponse.Builder
+ * #setAuthentication(IntentSender)} and {@link Dataset.Builder#setAuthentication(IntentSender)}.
+ * It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
+ * which would allow you to provide the dataset names to the user and if they choose one
+ * them challenge the user to authenticate. For example, if the user has a home and a work
+ * address the Home and Work labels could be stored unencrypted as they don't have any sensitive
+ * data while the address data is in an encrypted storage. If the user chooses Home, then the
+ * platform will start your authentication flow. If you encrypt all data and require auth
+ * at the response level the user will have to interact with the fill UI to trigger a request
+ * for the datasets as they don't see Home and Work options which will trigger your auth
+ * flow and after successfully authenticating the user will be presented with the Home and
+ * Work options where they can pick one. Hence, you have flexibility how to implement your
+ * auth while storing labels non-encrypted and data encrypted provides a better user
+ * experience.</p>
+ *
+ * <p>Finally, the service can use {@link Dataset.Builder#setExtras(Bundle)} methods
+ * to pass {@link Bundle extras} provided to all future calls related to a dataset,
+ * for example during authentication and saving.</p>
*/
public final class FillResponse implements Parcelable {
-
- private final List<Dataset> mDatasets;
- private final AutoFillId[] mSavableIds;
+ private final String mId;
+ private final ArraySet<Dataset> mDatasets;
+ private final ArraySet<AutoFillId> mSavableIds;
private final Bundle mExtras;
+ private final IntentSender mAuthentication;
- private FillResponse(Builder builder) {
- // TODO(b/33197203): make it immutable?
+ private FillResponse(@NonNull Builder builder) {
+ mId = builder.mId;
mDatasets = builder.mDatasets;
- final int size = builder.mSavableIds.size();
- mSavableIds = new AutoFillId[size];
- int i = 0;
- for (AutoFillId id : builder.mSavableIds) {
- mSavableIds[i++] = id;
- }
+ mSavableIds = builder.mSavableIds;
mExtras = builder.mExtras;
+ mAuthentication = builder.mAuthentication;
+ }
+
+ /** @hide */
+ public @NonNull String getId() {
+ return mId;
+ }
+
+ /** @hide */
+ public @Nullable Bundle getExtras() {
+ return mExtras;
}
/** @hide */
- public List<Dataset> getDatasets() {
+ public @Nullable ArraySet<Dataset> getDatasets() {
return mDatasets;
}
/** @hide */
- public AutoFillId[] getSavableIds() {
+ public @Nullable ArraySet<AutoFillId> getSavableIds() {
return mSavableIds;
}
/** @hide */
- public Bundle getExtras() {
- return mExtras;
+ public @Nullable IntentSender getAuthentication() {
+ return mAuthentication;
}
/**
- * Builder for {@link FillResponse} objects.
+ * Builder for {@link FillResponse} objects. You must to provide at least
+ * one dataset or set an authentication intent.
*/
public static final class Builder {
- private final List<Dataset> mDatasets = new ArrayList<>();
- private final Set<AutoFillId> mSavableIds = new HashSet<>();
- private Bundle mExtras;
+ private final String mId;
+ private ArraySet<Dataset> mDatasets;
+ private ArraySet<AutoFillId> mSavableIds;
+ private Bundle mExtras;
+ private IntentSender mAuthentication;
+ private boolean mDestroyed;
+
+ /** @hide */
+ // TODO(b/33197203): Remove once GCore migrates
+ public Builder() {
+ this(String.valueOf(System.currentTimeMillis()));
+ }
+
+ /**
+ * Creates a new {@link FillResponse} builder.
+ *
+ * @param id A required id to identify this dataset for future interactions related to it.
+ */
+ public Builder(@NonNull String id) {
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty or null");
+ }
/**
- * Adds a new {@link Dataset} to this response.
+ * Requires a fill response authentication before auto-filling the activity with
+ * any dataset in this response. This is typically useful when a user interaction
+ * is required to unlock their data vault if you encrypt the dataset labels and
+ * dataset data. It is recommended to encrypt only the sensitive data and not the
+ * dataset labels which would allow auth on the dataset level leading to a better
+ * user experience. Note that if you use sensitive data as a label, for example an
+ * email address, then it should also be encrypted.
+ *
+ * <p>This method is called when you need to provide an authentication
+ * UI for the fill response. For example, when the user's data is stored
+ * encrypted and needs a user interaction to decrypt before offering fill
+ * suggestions.</p>
+ *
+ * <p>When a user initiates an auto fill, the system triggers the provided
+ * intent whose extras will have the {@link android.content.Intent
+ * #EXTRA_AUTO_FILL_ITEM_ID id} of the {@link android.view.autofill.FillResponse})
+ * to authenticate, the {@link android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras}
+ * associated with this response, and a {@link android.content.Intent
+ * #EXTRA_AUTO_FILL_CALLBACK callback} to dispatch the authentication result.</p>
+ *
+ * <p>Once you complete your authentication flow you should use the provided callback
+ * to notify for a failure or a success. In case of a success you need to provide
+ * the fully populated response that is being authenticated. For example, if you
+ * provided an empty {@link FillResponse} because the user's data was locked and
+ * marked that the response needs an authentication then in the response returned
+ * if authentication succeeds you need to provide all available datasets some of
+ * which may need to be further authenticated, for example a credit card whose
+ * CVV needs to be entered.</p>
+ *
+ * <p>The indent sender mechanism allows you to have your authentication UI
+ * implemented as an activity or a service or a receiver. However, the recommended
+ * way is to do this is with an activity which the system will start in the
+ * filled activity's task meaning it will properly work with back, recent apps, and
+ * free-form multi-window, while avoiding the need for the "draw on top of other"
+ * apps special permission. You can still theme your authentication activity's
+ * UI to look like a dialog if desired.</p>
+ *
+ * <p></><strong>Note:</strong> Do not make the provided intent sender
+ * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
+ * platform needs to fill in the authentication arguments.</p>
+ *
+ * @param authentication Intent to trigger your authentication flow.
+ *
+ * @see android.app.PendingIntent#getIntentSender()
+ */
+ public @NonNull Builder setAuthentication(@Nullable IntentSender authentication) {
+ throwIfDestroyed();
+ mAuthentication = authentication;
+ return this;
+ }
+
+ /**
+ * Adds a new {@link Dataset} to this response. Adding a dataset with the
+ * same id updates the existing one.
*
* @throws IllegalArgumentException if a dataset with same {@code name} already exists.
*/
- public Builder addDataset(Dataset dataset) {
- Preconditions.checkNotNull(dataset, "dataset cannot be null");
- // TODO(b/33197203): check if name already exists
- // TODO(b/33197203): check if authId already exists (and update javadoc)
- mDatasets.add(dataset);
- for (DatasetField field : dataset.getFields()) {
- mSavableIds.add(field.getId());
+ public@NonNull Builder addDataset(@Nullable Dataset dataset) {
+ throwIfDestroyed();
+ if (dataset == null) {
+ return this;
+ }
+ if (mDatasets == null) {
+ mDatasets = new ArraySet<>();
+ }
+ final int datasetCount = mDatasets.size();
+ for (int i = 0; i < datasetCount; i++) {
+ if (mDatasets.valueAt(i).getName().equals(dataset.getName())) {
+ throw new IllegalArgumentException("Duplicate dataset name: "
+ + dataset.getName());
+ }
+ }
+ if (!mDatasets.add(dataset)) {
+ return this;
+ }
+ final int fieldCount = dataset.getFieldIds().size();
+ for (int i = 0; i < fieldCount; i++) {
+ final AutoFillId id = dataset.getFieldIds().get(i);
+ if (mSavableIds == null) {
+ mSavableIds = new ArraySet<>();
+ }
+ mSavableIds.add(id);
}
return this;
}
/**
* Adds ids of additional fields that the service would be interested to save (through
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
- * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) but were not
- * indirectly set through {@link #addDataset(Dataset)}.
+ * {@link android.service.autofill.AutoFillService#onSaveRequest(
+ * android.app.assist.AssistStructure, Bundle, android.service.autofill.SaveCallback)})
+ * but were not indirectly set through {@link #addDataset(Dataset)}.
*
* <p>See {@link FillResponse} for examples.
*/
- public Builder addSavableFields(AutoFillId...ids) {
+ public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+ throwIfDestroyed();
+ if (ids == null) {
+ return this;
+ }
for (AutoFillId id : ids) {
+ if (mSavableIds == null) {
+ mSavableIds = new ArraySet<>();
+ }
mSavableIds.add(id);
}
return this;
}
/**
- * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
- * methods such as
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
- * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
- * {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} as the key.
- *
- * <p>It can be used when to keep service state in between calls.
+ * Sets a {@link Bundle} that will be passed to subsequent APIs that
+ * manipulate this response. For example, they are passed in as {@link
+ * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} to your
+ * authentication flow and to subsequent calls to {@link
+ * android.service.autofill.AutoFillService#onFillRequest(
+ * android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal,
+ * android.service.autofill.FillCallback)} and {@link
+ * android.service.autofill.AutoFillService#onSaveRequest(
+ * android.app.assist.AssistStructure, Bundle,
+ * android.service.autofill.SaveCallback)}.
*/
public Builder setExtras(Bundle extras) {
- mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+ throwIfDestroyed();
+ mExtras = extras;
return this;
}
@@ -232,8 +355,16 @@ public final class FillResponse implements Parcelable {
* Builds a new {@link FillResponse} instance.
*/
public FillResponse build() {
+ throwIfDestroyed();
+ mDestroyed = true;
return new FillResponse(this);
}
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Already called #build()");
+ }
+ }
}
/////////////////////////////////////
@@ -242,11 +373,12 @@ public final class FillResponse implements Parcelable {
@Override
public String toString() {
if (!DEBUG) return super.toString();
-
- final StringBuilder builder = new StringBuilder("FillResponse: [datasets=")
- .append(mDatasets).append(", savableIds=").append(Arrays.toString(mSavableIds))
- .append(", extras=");
- append(builder, mExtras);
+ final StringBuilder builder = new StringBuilder(
+ "FillResponse: [id=").append(mId)
+ .append(", datasets=").append(mDatasets)
+ .append(", savableIds=").append(mSavableIds)
+ .append(", hasExtras=").append(mExtras != null)
+ .append(", hasAuthentication=").append(mAuthentication != null);
return builder.append(']').toString();
}
@@ -261,23 +393,34 @@ public final class FillResponse implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeList(mDatasets);
- parcel.writeParcelableArray(mSavableIds, 0);
- parcel.writeBundle(mExtras);
- }
-
- private FillResponse(Parcel parcel) {
- mDatasets = new ArrayList<>();
- parcel.readList(mDatasets, null);
- mSavableIds = parcel.readParcelableArray(null, AutoFillId.class);
- mExtras = parcel.readBundle();
+ parcel.writeString(mId);
+ parcel.writeTypedArraySet(mDatasets, 0);
+ parcel.writeTypedArraySet(mSavableIds, 0);
+ parcel.writeParcelable(mExtras, 0);
+ parcel.writeParcelable(mAuthentication, 0);
}
public static final Parcelable.Creator<FillResponse> CREATOR =
new Parcelable.Creator<FillResponse>() {
@Override
- public FillResponse createFromParcel(Parcel source) {
- return new FillResponse(source);
+ public FillResponse createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final Builder builder = new Builder(parcel.readString());
+ final ArraySet<Dataset> datasets = parcel.readTypedArraySet(null);
+ final int datasetCount = (datasets != null) ? datasets.size() : 0;
+ for (int i = 0; i < datasetCount; i++) {
+ builder.addDataset(datasets.valueAt(i));
+ }
+ final ArraySet<AutoFillId> fillIds = parcel.readTypedArraySet(null);
+ final int fillIdCount = (fillIds != null) ? fillIds.size() : 0;
+ for (int i = 0; i < fillIdCount; i++) {
+ builder.addSavableFields(fillIds.valueAt(i));
+ }
+ builder.setExtras(parcel.readParcelable(null));
+ builder.setAuthentication(parcel.readParcelable(null));
+ return builder.build();
}
@Override
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 772710e31b88..a9844d7f0b47 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -18,28 +18,34 @@ package android.view.autofill;
import android.os.Bundle;
+import java.util.Arrays;
+import java.util.Objects;
import java.util.Set;
/** @hide */
public final class Helper {
- // TODO(b/33197203): set to false when stable
- static final boolean DEBUG = true;
+ static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+ static final boolean VERBOSE = false;
static final String REDACTED = "[REDACTED]";
- static void append(StringBuilder builder, Bundle bundle) {
+ static StringBuilder append(StringBuilder builder, Bundle bundle) {
if (bundle == null) {
builder.append("N/A");
} else if (!DEBUG) {
builder.append(REDACTED);
} else {
final Set<String> keySet = bundle.keySet();
- builder.append("[bundle with ").append(keySet.size()).append(" extras:");
+ builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
for (String key : keySet) {
- builder.append(' ').append(key).append('=').append(bundle.get(key)).append(',');
+ final Object value = bundle.get(key);
+ builder.append(' ').append(key).append('=');
+ builder.append((value instanceof Object[])
+ ? Arrays.toString((Objects[]) value) : value);
}
builder.append(']');
}
+ return builder;
}
private Helper() {
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
index a19b4e53ba52..3dda7f7d2782 100644
--- a/core/java/android/view/autofill/VirtualViewDelegate.java
+++ b/core/java/android/view/autofill/VirtualViewDelegate.java
@@ -15,7 +15,6 @@
*/
package android.view.autofill;
-import android.util.Log;
import android.view.View;
import android.view.ViewStructure;
@@ -25,12 +24,13 @@ import android.view.ViewStructure;
*
* <p>The view hierarchy is typically created through the
* {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)} call and client
- * add virtual children by calling {@link ViewStructure#newChild(int, int)} or
- * {@link ViewStructure#asyncNewChild(int, int)}, where the client provides the {@code virtualId}
- * of the children - the same {@code virtualId} is used in the methods of this class.
+ * add virtual children by calling {@link ViewStructure#newChild(int, int, int)} or
+ * {@link ViewStructure#asyncNewChild(int, int, int)}, where the client provides the
+ * {@code virtualId} of the children - the same {@code virtualId} is used in the methods of this
+ * class.
*
* <p>Objects of this class are typically created by overriding
- * {@link View#getAutoFillVirtualViewDelegate(Callback)} and saving the passed callback, which must
+ * {@link View#getAutoFillVirtualViewDelegate()} and saving the passed callback, which must
* be notified upon changes on the hierarchy.
*
* <p>The main use case of these API is to enable custom views that draws its content - such as
@@ -40,84 +40,22 @@ import android.view.ViewStructure;
* <li>Client populates the virtual hierarchy on
* {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}
* <li>Android System generates the proper {@link AutoFillId} - encapsulating the view and the
- * virtual node ids - and pass it to the {@link android.service.autofill.AutoFillService}.
+ * virtual child ids - and pass it to the {@link android.service.autofill.AutoFillService}.
* <li>The service uses the {@link AutoFillId} to populate the auto-fill {@link Dataset}s and pass
* it back to the Android System.
* <li>Android System uses the {@link AutoFillId} to find the proper custom view and calls
* {@link #autoFill(int, AutoFillValue)} on that view passing the virtual id.
- * <li>This provider than finds the node in the hierarchy and auto-fills it.
+ * <li>This provider than finds the child in the hierarchy and auto-fills it.
* </ol>
*
*/
public abstract class VirtualViewDelegate {
- // TODO(b/33197203): set to false once stable
- private static final boolean DEBUG = true;
-
- private static final String TAG = "VirtualViewDelegate";
-
/**
* Auto-fills a virtual view with the {@code value}.
*
- * @param virtualId id identifying the virtual node inside the custom view.
+ * @param virtualId id identifying the virtual child inside the custom view.
* @param value value to be auto-filled.
*/
public abstract void autoFill(int virtualId, AutoFillValue value);
-
- /**
- * Callback used to notify the AutoFill Framework of changes made on the view hierarchy while
- * an {@link android.app.Activity} is being auto filled.
- */
- public abstract static class Callback {
-
- /**
- * Sent when the focus inside the hierarchy changed.
- *
- * <p>Typically callled twice - for the nodes that lost and gained focus.
- *
- * <p>This method should only be called when the change was not caused by the AutoFill
- * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
- * but by external causes (for example, when the user changed the value through the view's
- * UI).
- *
- * @param virtualId id of the node whose focus changed.
- * @param hasFocus {@code true} when focus was gained, {@code false} when it was lost.
- */
- public void onFocusChanged(int virtualId, boolean hasFocus) {
- if (DEBUG) Log.d(TAG, "onFocusChanged() for " + virtualId + ": " + hasFocus);
- }
-
- /**
- * Sent when the value of a node was changed.
- *
- * <p>This method should only be called when the change was not caused by the AutoFill
- * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
- * but by external causes (for example, when the user changed the value through the view's
- * UI).
- *
- * @param virtualId id of the node whose value changed.
- */
- public void onValueChanged(int virtualId) {
- if (DEBUG) Log.d(TAG, "onValueChanged() for" + virtualId);
- }
-
- /**
- * Sent when nodes were removed (or had their ids changed) after the hierarchy has been
- * committed to
- * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}.
- *
- * <p>For example, when the view is rendering an {@code HTML} page, it should call this
- * method when:
- * <ul>
- * <li>User navigated to another page and some (or all) nodes are gone.
- * <li>The page's {@code DOM} was changed by {@code JavaScript} and some nodes moved (and
- * are now identified by different ids).
- * </ul>
- *
- * @param virtualIds id of the nodes that were removed.
- */
- public void onNodeRemoved(int... virtualIds) {
- if (DEBUG) Log.d(TAG, "onNodeRemoved(): " + virtualIds);
- }
- }
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index b6da1d8c9de3..71809bdb4393 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -42,7 +43,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
/**
* This class is used to specify meta information of an input method.
@@ -110,6 +110,19 @@ public final class InputMethodInfo implements Parcelable {
private final boolean mSupportsDismissingWindow;
/**
+ * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
+ * @return a unique ID to be returned by {@link #getId()}. We have used
+ * {@link ComponentName#flattenToShortString()} for this purpose (and it is already
+ * unrealistic to switch to a different scheme as it is already implicitly assumed in
+ * many places).
+ * @hide
+ */
+ public static String computeId(@NonNull ResolveInfo service) {
+ final ServiceInfo si = service.serviceInfo;
+ return new ComponentName(si.packageName, si.name).flattenToShortString();
+ }
+
+ /**
* Constructor.
*
* @param context The Context in which we are parsing the input method.
@@ -127,15 +140,15 @@ public final class InputMethodInfo implements Parcelable {
* @param context The Context in which we are parsing the input method.
* @param service The ResolveInfo returned from the package manager about
* this input method's component.
- * @param additionalSubtypesMap additional subtypes being added to this InputMethodInfo
+ * @param additionalSubtypes additional subtypes being added to this InputMethodInfo
* @hide
*/
public InputMethodInfo(Context context, ResolveInfo service,
- Map<String, List<InputMethodSubtype>> additionalSubtypesMap)
+ List<InputMethodSubtype> additionalSubtypes)
throws XmlPullParserException, IOException {
mService = service;
ServiceInfo si = service.serviceInfo;
- mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+ mId = computeId(service);
boolean isAuxIme = true;
boolean supportsSwitchingToNextInputMethod = false; // false as default
boolean supportsDismissingWindow = false; // false as default
@@ -233,8 +246,7 @@ public final class InputMethodInfo implements Parcelable {
isAuxIme = false;
}
- if (additionalSubtypesMap != null && additionalSubtypesMap.containsKey(mId)) {
- final List<InputMethodSubtype> additionalSubtypes = additionalSubtypesMap.get(mId);
+ if (additionalSubtypes != null) {
final int N = additionalSubtypes.size();
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = additionalSubtypes.get(i);
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 4673c50cddc9..a4e524f9882b 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -41,6 +41,9 @@ public final class TextClassificationManager {
private static final String LOG_TAG = "TextClassificationManager";
+ private final Object mTextClassifierLock = new Object();
+ private final Object mLangIdLock = new Object();
+
private final Context mContext;
// TODO: Implement a way to close the file descriptor.
private ParcelFileDescriptor mFd;
@@ -56,18 +59,20 @@ public final class TextClassificationManager {
* Returns the default text classifier.
*/
public TextClassifier getDefaultTextClassifier() {
- if (mDefault == null) {
- try {
- mFd = ParcelFileDescriptor.open(
- new File("/etc/assistant/smart-selection.model"),
- ParcelFileDescriptor.MODE_READ_ONLY);
- mDefault = new TextClassifierImpl(mContext, mFd);
- } catch (FileNotFoundException e) {
- Log.e(LOG_TAG, "Error accessing 'text classifier selection' model file.", e);
- mDefault = TextClassifier.NO_OP;
+ synchronized (mTextClassifierLock) {
+ if (mDefault == null) {
+ try {
+ mFd = ParcelFileDescriptor.open(
+ new File("/etc/assistant/smart-selection.model"),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ mDefault = new TextClassifierImpl(mContext, mFd);
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, "Error accessing 'text classifier selection' model file.", e);
+ mDefault = TextClassifier.NO_OP;
+ }
}
+ return mDefault;
}
- return mDefault;
}
/**
@@ -96,11 +101,13 @@ public final class TextClassificationManager {
}
private LangId getLanguageDetector() {
- if (mLangId == null) {
- // TODO: Use a file descriptor as soon as we start to depend on a model file
- // for language detection.
- mLangId = new LangId(0);
+ synchronized (mLangIdLock) {
+ if (mLangId == null) {
+ // TODO: Use a file descriptor as soon as we start to depend on a model file
+ // for language detection.
+ mLangId = new LangId(0);
+ }
+ return mLangId;
}
- return mLangId;
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 72796cf160d0..e2ff44cb3793 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -17,20 +17,35 @@
package android.view.textclassifier;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
+import android.icu.text.BreakIterator;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.SmartSelection;
+import android.text.Spannable;
import android.text.TextUtils;
+import android.text.method.WordIterator;
+import android.text.style.ClickableSpan;
+import android.text.util.Linkify;
import android.util.Log;
+import android.view.View;
import com.android.internal.util.Preconditions;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
/**
* Default implementation of the {@link TextClassifier} interface.
@@ -45,6 +60,8 @@ final class TextClassifierImpl implements TextClassifier {
private static final String LOG_TAG = "TextClassifierImpl";
+ private final Object mSmartSelectionLock = new Object();
+
private final Context mContext;
private final ParcelFileDescriptor mFd;
private SmartSelection mSmartSelection;
@@ -99,29 +116,7 @@ final class TextClassifierImpl implements TextClassifier {
type = type.toLowerCase().trim();
// TODO: Added this log for debug only. Remove before release.
Log.d(LOG_TAG, String.format("Classification type: %s", type));
- final Intent intent;
- final String title;
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- intent = new Intent(Intent.ACTION_SENDTO);
- intent.setData(Uri.parse(String.format("mailto:%s", text)));
- title = mContext.getString(com.android.internal.R.string.email);
- return createClassificationResult(classified, type, intent, title);
- case TextClassifier.TYPE_PHONE:
- intent = new Intent(Intent.ACTION_DIAL);
- intent.setData(Uri.parse(String.format("tel:%s", text)));
- title = mContext.getString(com.android.internal.R.string.dial);
- return createClassificationResult(classified, type, intent, title);
- case TextClassifier.TYPE_ADDRESS:
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
- title = mContext.getString(com.android.internal.R.string.map);
- return createClassificationResult(classified, type, intent, title);
- default:
- // No classification type found. Return a no-op result.
- break;
- // TODO: Add other classification types.
- }
+ return createClassificationResult(type, classified);
}
}
} catch (Throwable t) {
@@ -132,38 +127,64 @@ final class TextClassifierImpl implements TextClassifier {
return TextClassifier.NO_OP.getTextClassificationResult(text, startIndex, endIndex);
}
+
@Override
- public LinksInfo getLinks(@NonNull CharSequence text, int linkMask) {
- // TODO: Implement
+ public LinksInfo getLinks(CharSequence text, int linkMask) {
+ Preconditions.checkArgument(text != null);
+ try {
+ return LinksInfoFactory.create(
+ mContext, getSmartSelection(), text.toString(), linkMask);
+ } catch (Throwable t) {
+ // Avoid throwing from this method. Log the error.
+ Log.e(LOG_TAG, "Error getting links info.", t);
+ }
+ // Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.getLinks(text, linkMask);
}
- private synchronized SmartSelection getSmartSelection() throws FileNotFoundException {
- if (mSmartSelection == null) {
- mSmartSelection = new SmartSelection(mFd.getFd());
+ private SmartSelection getSmartSelection() throws FileNotFoundException {
+ synchronized (mSmartSelectionLock) {
+ if (mSmartSelection == null) {
+ mSmartSelection = new SmartSelection(mFd.getFd());
+ }
+ return mSmartSelection;
}
- return mSmartSelection;
}
- private TextClassificationResult createClassificationResult(
- CharSequence text, String type, Intent intent, String label) {
- TextClassificationResult.Builder builder = new TextClassificationResult.Builder()
+ private TextClassificationResult createClassificationResult(String type, CharSequence text) {
+ final Intent intent = IntentFactory.create(type, text.toString());
+ if (intent == null) {
+ return TextClassificationResult.EMPTY;
+ }
+
+ final TextClassificationResult.Builder builder = new TextClassificationResult.Builder()
.setText(text.toString())
.setEntityType(type, 1.0f /* confidence */)
.setIntent(intent)
.setOnClickListener(TextClassificationResult.createStartActivityOnClick(
- mContext, intent))
- .setLabel(label);
- PackageManager pm = mContext.getPackageManager();
- ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
- // TODO: If the resolveInfo is the "chooser", do not set the package name and use a
- // default icon for this classification type.
- intent.setPackage(resolveInfo.activityInfo.packageName);
- Drawable icon = resolveInfo.activityInfo.loadIcon(pm);
- if (icon == null) {
- icon = resolveInfo.loadIcon(pm);
+ mContext, intent));
+ final PackageManager pm = mContext.getPackageManager();
+ final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+ if (resolveInfo != null && resolveInfo.activityInfo != null) {
+ final String packageName = resolveInfo.activityInfo.packageName;
+ if ("android".equals(packageName)) {
+ // Requires the chooser to find an activity to handle the intent.
+ builder.setLabel(IntentFactory.getLabel(mContext, type));
+ } else {
+ // A default activity will handle the intent.
+ intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
+ Drawable icon = resolveInfo.activityInfo.loadIcon(pm);
+ if (icon == null) {
+ icon = resolveInfo.loadIcon(pm);
+ }
+ builder.setIcon(icon);
+ CharSequence label = resolveInfo.activityInfo.loadLabel(pm);
+ if (label == null) {
+ label = resolveInfo.loadLabel(pm);
+ }
+ builder.setLabel(label != null ? label.toString() : null);
+ }
}
- builder.setIcon(icon);
return builder.build();
}
@@ -177,4 +198,208 @@ final class TextClassifierImpl implements TextClassifier {
Preconditions.checkArgument(endIndex <= text.length());
Preconditions.checkArgument(endIndex >= startIndex);
}
+
+ /**
+ * Detects and creates links for specified text.
+ */
+ private static final class LinksInfoFactory {
+
+ private LinksInfoFactory() {}
+
+ public static LinksInfo create(
+ Context context, SmartSelection smartSelection, String text, int linkMask) {
+ final WordIterator wordIterator = new WordIterator();
+ wordIterator.setCharSequence(text, 0, text.length());
+ final List<SpanSpec> spans = new ArrayList<>();
+ int start = 0;
+ int end;
+ while ((end = wordIterator.nextBoundary(start)) != BreakIterator.DONE) {
+ final String token = text.substring(start, end);
+ if (TextUtils.isEmpty(token)) {
+ continue;
+ }
+
+ final int[] selection = smartSelection.suggest(text, start, end);
+ final int selectionStart = selection[0];
+ final int selectionEnd = selection[1];
+ if (selectionStart >= 0 && selectionEnd <= text.length()
+ && selectionStart <= selectionEnd) {
+ final String type =
+ smartSelection.classifyText(text, selectionStart, selectionEnd);
+ if (matches(type, linkMask)) {
+ final Intent intent = IntentFactory.create(
+ type, text.substring(selectionStart, selectionEnd));
+ if (hasActivityHandler(context, intent)) {
+ final ClickableSpan span = createSpan(context, intent);
+ spans.add(new SpanSpec(selectionStart, selectionEnd, span));
+ }
+ }
+ }
+ start = end;
+ }
+ return new LinksInfoImpl(text, avoidOverlaps(spans, text));
+ }
+
+ /**
+ * Returns true if the classification type matches the specified linkMask.
+ */
+ private static boolean matches(String type, int linkMask) {
+ if ((linkMask & Linkify.PHONE_NUMBERS) != 0
+ && TextClassifier.TYPE_PHONE.equals(type)) {
+ return true;
+ }
+ if ((linkMask & Linkify.EMAIL_ADDRESSES) != 0
+ && TextClassifier.TYPE_EMAIL.equals(type)) {
+ return true;
+ }
+ if ((linkMask & Linkify.MAP_ADDRESSES) != 0
+ && TextClassifier.TYPE_ADDRESS.equals(type)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Trim the number of spans so that no two spans overlap.
+ *
+ * This algorithm first ensures that there is only one span per start index, then it
+ * makes sure that no two spans overlap.
+ */
+ private static List<SpanSpec> avoidOverlaps(List<SpanSpec> spans, String text) {
+ Collections.sort(spans, Comparator.comparingInt(span -> span.mStart));
+ // Group spans by start index. Take the longest span.
+ final Map<Integer, SpanSpec> reps = new LinkedHashMap<>(); // order matters.
+ final int size = spans.size();
+ for (int i = 0; i < size; i++) {
+ final SpanSpec span = spans.get(i);
+ final LinksInfoFactory.SpanSpec rep = reps.get(span.mStart);
+ if (rep == null || rep.mEnd < span.mEnd) {
+ reps.put(span.mStart, span);
+ }
+ }
+ // Avoid span intersections. Take the longer span.
+ final LinkedList<SpanSpec> result = new LinkedList<>();
+ for (SpanSpec rep : reps.values()) {
+ if (result.isEmpty()) {
+ result.add(rep);
+ continue;
+ }
+
+ final SpanSpec last = result.getLast();
+ if (rep.mStart < last.mEnd) {
+ // Spans intersect. Use the one with characters.
+ if ((rep.mEnd - rep.mStart) > (last.mEnd - last.mStart)) {
+ result.set(result.size() - 1, rep);
+ }
+ } else {
+ result.add(rep);
+ }
+ }
+ return result;
+ }
+
+ private static ClickableSpan createSpan(final Context context, final Intent intent) {
+ return new ClickableSpan() {
+ // TODO: Style this span.
+ @Override
+ public void onClick(View widget) {
+ context.startActivity(intent);
+ }
+ };
+ }
+
+ private static boolean hasActivityHandler(Context context, @Nullable Intent intent) {
+ if (intent == null) {
+ return false;
+ }
+ final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
+ return resolveInfo != null && resolveInfo.activityInfo != null;
+ }
+
+ /**
+ * Implementation of LinksInfo that adds ClickableSpans to the specified text.
+ */
+ private static final class LinksInfoImpl implements LinksInfo {
+
+ private final CharSequence mOriginalText;
+ private final List<SpanSpec> mSpans;
+
+ LinksInfoImpl(CharSequence originalText, List<SpanSpec> spans) {
+ mOriginalText = originalText;
+ mSpans = spans;
+ }
+
+ @Override
+ public boolean apply(@NonNull CharSequence text) {
+ Preconditions.checkArgument(text != null);
+ if (text instanceof Spannable && mOriginalText.toString().equals(text.toString())) {
+ Spannable spannable = (Spannable) text;
+ final int size = mSpans.size();
+ for (int i = 0; i < size; i++) {
+ final SpanSpec span = mSpans.get(i);
+ spannable.setSpan(span.mSpan, span.mStart, span.mEnd, 0);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Span plus its start and end index.
+ */
+ private static final class SpanSpec {
+
+ private final int mStart;
+ private final int mEnd;
+ private final ClickableSpan mSpan;
+
+ SpanSpec(int start, int end, ClickableSpan span) {
+ mStart = start;
+ mEnd = end;
+ mSpan = span;
+ }
+ }
+ }
+
+ /**
+ * Creates intents based on the classification type.
+ */
+ private static final class IntentFactory {
+
+ private IntentFactory() {}
+
+ @Nullable
+ public static Intent create(String type, String text) {
+ switch (type) {
+ case TextClassifier.TYPE_EMAIL:
+ return new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("mailto:%s", text)));
+ case TextClassifier.TYPE_PHONE:
+ return new Intent(Intent.ACTION_DIAL)
+ .setData(Uri.parse(String.format("tel:%s", text)));
+ case TextClassifier.TYPE_ADDRESS:
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
+ default:
+ return null;
+ // TODO: Add other classification types.
+ }
+ }
+
+ @Nullable
+ public static String getLabel(Context context, String type) {
+ switch (type) {
+ case TextClassifier.TYPE_EMAIL:
+ return context.getString(com.android.internal.R.string.email);
+ case TextClassifier.TYPE_PHONE:
+ return context.getString(com.android.internal.R.string.dial);
+ case TextClassifier.TYPE_ADDRESS:
+ return context.getString(com.android.internal.R.string.map);
+ default:
+ return null;
+ // TODO: Add other classification types.
+ }
+ }
+ }
}
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 729eb8d131a7..2e2056cbabef 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -97,7 +97,6 @@ public class SpellCheckerSession {
private final SpellCheckerInfo mSpellCheckerInfo;
private final SpellCheckerSessionListener mSpellCheckerSessionListener;
private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
- private final SpellCheckerSubtype mSubtype;
private boolean mIsUsed;
@@ -121,8 +120,7 @@ public class SpellCheckerSession {
* @hide
*/
public SpellCheckerSession(
- SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener,
- SpellCheckerSubtype subtype) {
+ SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener) {
if (info == null || listener == null || tsm == null) {
throw new NullPointerException();
}
@@ -132,7 +130,6 @@ public class SpellCheckerSession {
mTextServicesManager = tsm;
mIsUsed = true;
mSpellCheckerSessionListener = listener;
- mSubtype = subtype;
}
/**
@@ -218,7 +215,8 @@ public class SpellCheckerSession {
mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos);
}
- private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
+ private static final class SpellCheckerSessionListenerImpl
+ extends ISpellCheckerSessionListener.Stub {
private static final int TASK_CANCEL = 1;
private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
private static final int TASK_CLOSE = 3;
@@ -366,7 +364,7 @@ public class SpellCheckerSession {
}
}
- public synchronized void onServiceConnected(ISpellCheckerSession session) {
+ public void onServiceConnected(ISpellCheckerSession session) {
synchronized (this) {
switch (mState) {
case STATE_WAIT_CONNECTION:
@@ -408,9 +406,9 @@ public class SpellCheckerSession {
+ Integer.toHexString(mISpellCheckerSession.hashCode())
+ " mPendingTasks.size()=" + mPendingTasks.size());
}
- }
- while (!mPendingTasks.isEmpty()) {
- processTask(session, mPendingTasks.poll(), false);
+ while (!mPendingTasks.isEmpty()) {
+ processTask(session, mPendingTasks.poll(), false);
+ }
}
}
@@ -529,7 +527,7 @@ public class SpellCheckerSession {
public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results);
}
- private static class InternalListener extends ITextServicesSessionListener.Stub {
+ private static final class InternalListener extends ITextServicesSessionListener.Stub {
private final SpellCheckerSessionListenerImpl mParentSpellCheckerSessionListenerImpl;
public InternalListener(SpellCheckerSessionListenerImpl spellCheckerSessionListenerImpl) {
@@ -547,7 +545,7 @@ public class SpellCheckerSession {
super.finalize();
if (mIsUsed) {
Log.e(TAG, "SpellCheckerSession was not finished properly." +
- "You should call finishShession() when you finished to use a spell checker.");
+ "You should call finishSession() when you finished to use a spell checker.");
close();
}
}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 0f168f392a20..b4e6c5699007 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -171,8 +171,7 @@ public final class TextServicesManager {
if (subtypeInUse == null) {
return null;
}
- final SpellCheckerSession session = new SpellCheckerSession(
- sci, mService, listener, subtypeInUse);
+ final SpellCheckerSession session = new SpellCheckerSession(sci, mService, listener);
try {
mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(),
session.getTextServicesSessionListener(),
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 404bcf453aaf..f53b5d6a7cd7 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -20,6 +20,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
+import android.os.Build;
import android.os.UserManager;
import java.util.ArrayList;
@@ -77,6 +78,15 @@ public class UserPackage {
& ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
}
+ /**
+ * Returns whether the package represented by {@param packageInfo} targets a sdk version
+ * supported by the current framework version.
+ */
+ public static boolean hasCorrectTargetSdkVersion(PackageInfo packageInfo) {
+ // TODO(gsennton) use Build.VERSION_CODES.O when that has been updated.
+ return packageInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1;
+ }
+
public UserInfo getUserInfo() {
return mUserInfo;
}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 8703468a74a7..0a73e17dd6e4 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -488,7 +488,8 @@ public class WebViewClient {
* @param view The WebView which needs to be cleaned up.
* @param detail the reason why it exited.
* @return true if the host application handled the situation that process has
- * exited, otherwise, application will crash.
+ * exited, otherwise, application will crash if render process crashed,
+ * or be killed if render process was killed by the system.
*/
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
return false;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index d7a49e46a236..0906d1a1e034 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -145,18 +145,10 @@ public final class WebViewFactory {
/**
* @hide
*/
- public static Class<WebViewFactoryProvider> getWebViewProviderClass( ClassLoader clazzLoader)
- throws ClassNotFoundException{
- try {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
- true, clazzLoader);
- } catch (ClassNotFoundException e) {
- // TODO: This loads the provider which is not built for O, should be removed
- // before the release.
- return (Class<WebViewFactoryProvider>) Class.forName(
- "com.android.webview.chromium.WebViewChromiumFactoryProvider",
- true, clazzLoader);
- }
+ public static Class<WebViewFactoryProvider> getWebViewProviderClass(ClassLoader clazzLoader)
+ throws ClassNotFoundException {
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
+ true, clazzLoader);
}
/**
@@ -225,15 +217,10 @@ public final class WebViewFactory {
}
}
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
try {
- if (staticFactory != null) {
- sProviderInstance = (WebViewFactoryProvider)
- staticFactory.invoke(null, new WebViewDelegate());
- } else {
- sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
- .newInstance(new WebViewDelegate());
- }
+ sProviderInstance = (WebViewFactoryProvider)
+ staticFactory.invoke(null, new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
@@ -384,8 +371,7 @@ public final class WebViewFactory {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
try {
return getWebViewProviderClass(clazzLoader);
- }
- finally {
+ } finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (ClassNotFoundException e) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 8cedb1712820..47c4cf383e61 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2548,7 +2548,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private boolean isItemClickable(View view) {
- return !view.hasFocusable();
+ return !view.hasFocusable(false);
}
/**
@@ -2824,7 +2824,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final View v = getChildAt(mSelectedPosition - mFirstPosition);
if (v != null) {
- if (v.hasFocusable()) return;
+ if (v.hasFocusable(false)) return;
v.setPressed(true);
}
setPressed(true);
@@ -3428,7 +3428,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mTouchMode == TOUCH_MODE_DOWN) {
mTouchMode = TOUCH_MODE_TAP;
final View child = getChildAt(mMotionPosition - mFirstPosition);
- if (child != null && !child.hasFocusable()) {
+ if (child != null && !child.hasFocusable(false)) {
mLayoutMode = LAYOUT_NORMAL;
if (!mDataChanged) {
@@ -4005,7 +4005,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final float x = ev.getX();
final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
- if (inList && !child.hasFocusable()) {
+ if (inList && !child.hasFocusable(false)) {
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 718070d0d49a..6f687fe5f14c 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -561,10 +561,14 @@ public abstract class CompoundButton extends Button implements Checkable {
stream.addProperty("checked", isChecked());
}
- // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ // TODO(b/33197203): override onProvideAutoFillStructure and add a change listener
@Override
public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
setChecked(value.getToggleValue());
}
@@ -572,4 +576,9 @@ public abstract class CompoundButton extends Button implements Checkable {
public AutoFillType getAutoFillType() {
return AutoFillType.forToggle();
}
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? null : AutoFillValue.forToggle(isChecked());
+ }
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index faf037964897..07ad872bd8f0 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -24,10 +24,7 @@ import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.autofill.AutoFillType;
-import android.view.autofill.AutoFillValue;
/*
* This is supposed to be a *very* thin veneer over TextView.
@@ -158,26 +155,4 @@ public class EditText extends TextView {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
}
}
-
- // TODO(b/33197203): add unit/CTS tests for auto-fill methods
-
- @Override
- public void autoFill(AutoFillValue value) {
- final CharSequence text = value.getTextValue();
-
- if (text == null) {
- Log.w(VIEW_LOG_TAG, "EditText.autoFill(): no text on AutoFillValue");
- return;
- }
- // TODO(b/33197203): once auto-fill is triggered by the IME, we'll need a new setText()
- // or setAutoFillText() method on TextView to avoid re-triggering it.
- setText(text);
- }
-
- @Override
- public AutoFillType getAutoFillType() {
- // TODO(b/33197203): ideally it should return a constant, but value returned by
- // getInputType() can change.
- return AutoFillType.forText(getInputType());
- }
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f7f9a81e45c1..8cb2d23a0636 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -95,7 +95,6 @@ import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -107,7 +106,6 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassificationResult;
-import android.view.textclassifier.TextSelection;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView.Drawables;
import android.widget.TextView.OnEditorActionListener;
@@ -140,7 +138,6 @@ public class Editor {
private static final boolean DEBUG_UNDO = false;
static final int BLINK = 500;
- private static final float[] TEMP_POSITION = new float[2];
private static final int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f;
private static final int UNSET_X_VALUE = -1;
@@ -171,7 +168,7 @@ public class Editor {
private InsertionPointCursorController mInsertionPointCursorController;
SelectionModifierCursorController mSelectionModifierCursorController;
// Action mode used when text is selected or when actions on an insertion cursor are triggered.
- ActionMode mTextActionMode;
+ private ActionMode mTextActionMode;
private boolean mInsertionControllerEnabled;
private boolean mSelectionControllerEnabled;
@@ -238,7 +235,7 @@ public class Editor {
private boolean mPreserveSelection;
private boolean mRestartActionModeOnNextRefresh;
- private TextClassificationResult mTextClassificationResult;
+ private SelectionActionModeHelper mSelectionActionModeHelper;
boolean mIsBeingLongClicked;
@@ -294,7 +291,7 @@ public class Editor {
private Rect mTempRect;
- private TextView mTextView;
+ private final TextView mTextView;
final ProcessTextIntentActionsHandler mProcessTextIntentActionsHandler;
@@ -1032,46 +1029,6 @@ public class Editor {
boolean parentPositionChanged, boolean parentScrolled);
}
- private boolean isPositionVisible(final float positionX, final float positionY) {
- synchronized (TEMP_POSITION) {
- final float[] position = TEMP_POSITION;
- position[0] = positionX;
- position[1] = positionY;
- View view = mTextView;
-
- while (view != null) {
- if (view != mTextView) {
- // Local scroll is already taken into account in positionX/Y
- position[0] -= view.getScrollX();
- position[1] -= view.getScrollY();
- }
-
- if (position[0] < 0 || position[1] < 0 || position[0] > view.getWidth()
- || position[1] > view.getHeight()) {
- return false;
- }
-
- if (!view.getMatrix().isIdentity()) {
- view.getMatrix().mapPoints(position);
- }
-
- position[0] += view.getLeft();
- position[1] += view.getTop();
-
- final ViewParent parent = view.getParent();
- if (parent instanceof View) {
- view = (View) parent;
- } else {
- // We've reached the ViewRoot, stop iterating
- view = null;
- }
- }
- }
-
- // We've been able to walk up the view hierarchy and the position was never clipped
- return true;
- }
-
private boolean isOffsetVisible(int offset) {
Layout layout = mTextView.getLayout();
if (layout == null) return false;
@@ -1079,7 +1036,8 @@ public class Editor {
final int line = layout.getLineForOffset(offset);
final int lineBottom = layout.getLineBottom(line);
final int primaryHorizontal = (int) layout.getPrimaryHorizontal(offset);
- return isPositionVisible(primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
+ return mTextView.isPositionVisible(
+ primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
lineBottom + mTextView.viewportToContentVerticalOffset());
}
@@ -1891,7 +1849,7 @@ public class Editor {
mInsertionPointCursorController.invalidateHandle();
}
if (mTextActionMode != null) {
- invalidateActionMode(getTextClassifierInfo(false));
+ invalidateActionModeAsync();
}
}
@@ -1984,12 +1942,12 @@ public class Editor {
if (mRestartActionModeOnNextRefresh) {
// To avoid distraction, newly start action mode only when selection action
// mode is being restarted.
- startSelectionActionMode(getTextClassifierInfo(true));
+ startSelectionActionMode();
}
} else if (selectionController == null || !selectionController.isActive()) {
// Insertion action mode is active. Avoid dismissing the selection.
stopTextActionModeWithPreservingSelection();
- startSelectionActionMode(getTextClassifierInfo(true));
+ startSelectionActionMode();
} else {
mTextActionMode.invalidateContentRect();
}
@@ -2026,55 +1984,46 @@ public class Editor {
}
}
+ @NonNull
+ TextView getTextView() {
+ return mTextView;
+ }
+
+ @Nullable
+ ActionMode getTextActionMode() {
+ return mTextActionMode;
+ }
+
+ void setRestartActionModeOnNextRefresh(boolean value) {
+ mRestartActionModeOnNextRefresh = value;
+ }
+
/**
- * Starts a Selection Action Mode with the current selection and ensures the selection handles
- * are shown if there is a selection. This should be used when the mode is started from a
- * non-touch event.
- *
- * @return true if the selection mode was actually started.
+ * Asynchronously starts a selection action mode using the TextClassifier.
*/
- boolean startSelectionActionMode(@Nullable TextClassificationResult textClassificationResult) {
- mTextClassificationResult = textClassificationResult;
- boolean selectionStarted = startSelectionActionModeInternal();
- if (selectionStarted) {
- getSelectionController().show();
- }
- mRestartActionModeOnNextRefresh = false;
- return selectionStarted;
+ void startSelectionActionModeAsync() {
+ getSelectionActionModeHelper().startActionModeAsync();
}
- private boolean startSelectionActionModeWithTextAssistant() {
- return startSelectionActionMode(getTextClassifierInfo(true));
+ /**
+ * Synchronously starts a selection action mode without the TextClassifier.
+ */
+ void startSelectionActionMode() {
+ getSelectionActionModeHelper().startActionMode();
}
- private void invalidateActionMode(TextClassificationResult textClassificationResult) {
- mTextClassificationResult = textClassificationResult;
- mTextActionMode.invalidate();
+ /**
+ * Asynchronously invalidates an action mode using the TextClassifier.
+ */
+ private void invalidateActionModeAsync() {
+ getSelectionActionModeHelper().invalidateActionModeAsync();
}
- // TODO: Make this a non-blocking call.
- private TextClassificationResult getTextClassifierInfo(boolean updateSelection) {
- // TODO: Trim the text so that only text necessary to provide context of the selected
- // text is sent to the assistant.
- final int trimStartIndex = 0;
- final int trimEndIndex = mTextView.getText().length();
- CharSequence trimmedText =
- mTextView.getText().subSequence(trimStartIndex, trimEndIndex);
- int startIndex = mTextView.getSelectionStart() - trimStartIndex;
- int endIndex = mTextView.getSelectionEnd() - trimStartIndex;
-
- if (updateSelection) {
- TextSelection textSelection = mTextView.getTextClassifier()
- .suggestSelection(trimmedText, startIndex, endIndex);
- startIndex = Math.max(0, textSelection.getSelectionStartIndex() + trimStartIndex);
- endIndex = Math.min(mTextView.getText().length(),
- textSelection.getSelectionEndIndex() + trimStartIndex);
- Selection.setSelection((Spannable) mTextView.getText(), startIndex, endIndex);
- return getTextClassifierInfo(false);
+ private SelectionActionModeHelper getSelectionActionModeHelper() {
+ if (mSelectionActionModeHelper == null) {
+ mSelectionActionModeHelper = new SelectionActionModeHelper(this);
}
-
- return mTextView.getTextClassifier()
- .getTextClassificationResult(trimmedText, startIndex, endIndex);
+ return mSelectionActionModeHelper;
}
/**
@@ -2117,13 +2066,13 @@ public class Editor {
return true;
}
- private boolean startSelectionActionModeInternal() {
+ boolean startSelectionActionModeInternal() {
if (extractedTextModeWillBeStarted()) {
return false;
}
if (mTextActionMode != null) {
// Text action mode is already started
- invalidateActionMode(getTextClassifierInfo(false));
+ invalidateActionModeAsync();
return false;
}
@@ -2314,7 +2263,8 @@ public class Editor {
return mInsertionPointCursorController;
}
- private SelectionModifierCursorController getSelectionController() {
+ @Nullable
+ SelectionModifierCursorController getSelectionController() {
if (!mSelectionControllerEnabled) {
return null;
}
@@ -3813,7 +3763,7 @@ public class Editor {
mode.setSubtitle(null);
mode.setTitleOptionalHint(true);
populateMenuWithItems(menu);
- updateAssistMenuItem(menu, mTextClassificationResult);
+ updateAssistMenuItem(menu);
Callback customCallback = getCustomCallback();
if (customCallback != null) {
@@ -3881,7 +3831,7 @@ public class Editor {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
updateSelectAllItem(menu);
updateReplaceItem(menu);
- updateAssistMenuItem(menu, mTextClassificationResult);
+ updateAssistMenuItem(menu);
Callback customCallback = getCustomCallback();
if (customCallback != null) {
@@ -3914,15 +3864,22 @@ public class Editor {
}
}
- private void updateAssistMenuItem(
- Menu menu, TextClassificationResult textClassificationResult) {
+ private void updateAssistMenuItem(Menu menu) {
menu.removeItem(TextView.ID_ASSIST);
- if (textClassificationResult != null
- && textClassificationResult.getIcon() != null
- && textClassificationResult.getOnClickListener() != null) {
- menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, null)
- .setIcon(textClassificationResult.getIcon())
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ final TextClassificationResult textClassificationResult =
+ getSelectionActionModeHelper().getTextClassificationResult();
+ if (textClassificationResult != null) {
+ final Drawable icon = textClassificationResult.getIcon();
+ final CharSequence label = textClassificationResult.getLabel();
+ final OnClickListener onClickListener =
+ textClassificationResult.getOnClickListener();
+ final Intent intent = textClassificationResult.getIntent();
+ if ((icon != null || !TextUtils.isEmpty(label))
+ && (onClickListener != null || intent != null)) {
+ menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label)
+ .setIcon(icon)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
}
}
@@ -3935,9 +3892,23 @@ public class Editor {
if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
return true;
}
- if (TextView.ID_ASSIST == item.getItemId() && mTextClassificationResult != null) {
- mTextClassificationResult.getOnClickListener().onClick(mTextView);
+ final TextClassificationResult textClassificationResult =
+ getSelectionActionModeHelper().getTextClassificationResult();
+ if (TextView.ID_ASSIST == item.getItemId() && textClassificationResult != null) {
+ final OnClickListener onClickListener =
+ textClassificationResult.getOnClickListener();
+ if (onClickListener != null) {
+ onClickListener.onClick(mTextView);
+ } else {
+ final Intent intent = textClassificationResult.getIntent();
+ if (intent != null) {
+ TextClassificationResult.createStartActivityOnClick(
+ mTextView.getContext(), intent)
+ .onClick(mTextView);
+ }
+ }
stopTextActionMode();
+ return true;
}
return mTextView.onTextContextMenuItem(item.getItemId());
}
@@ -3945,8 +3916,8 @@ public class Editor {
@Override
public void onDestroyActionMode(ActionMode mode) {
// Clear mTextActionMode not to recursively destroy action mode by clearing selection.
+ getSelectionActionModeHelper().cancelAsyncTask();
mTextActionMode = null;
- mTextClassificationResult = null;
Callback customCallback = getCustomCallback();
if (customCallback != null) {
customCallback.onDestroyActionMode(mode);
@@ -4080,69 +4051,9 @@ public class Editor {
final CharSequence composingText = text.subSequence(composingTextStart,
composingTextEnd);
builder.setComposingText(composingTextStart, composingText);
-
- final int minLine = layout.getLineForOffset(composingTextStart);
- final int maxLine = layout.getLineForOffset(composingTextEnd - 1);
- for (int line = minLine; line <= maxLine; ++line) {
- final int lineStart = layout.getLineStart(line);
- final int lineEnd = layout.getLineEnd(line);
- final int offsetStart = Math.max(lineStart, composingTextStart);
- final int offsetEnd = Math.min(lineEnd, composingTextEnd);
- final boolean ltrLine =
- layout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
- final float[] widths = new float[offsetEnd - offsetStart];
- layout.getPaint().getTextWidths(text, offsetStart, offsetEnd, widths);
- final float top = layout.getLineTop(line);
- final float bottom = layout.getLineBottom(line);
- for (int offset = offsetStart; offset < offsetEnd; ++offset) {
- final float charWidth = widths[offset - offsetStart];
- final boolean isRtl = layout.isRtlCharAt(offset);
- final float primary = layout.getPrimaryHorizontal(offset);
- final float secondary = layout.getSecondaryHorizontal(offset);
- // TODO: This doesn't work perfectly for text with custom styles and
- // TAB chars.
- final float left;
- final float right;
- if (ltrLine) {
- if (isRtl) {
- left = secondary - charWidth;
- right = secondary;
- } else {
- left = primary;
- right = primary + charWidth;
- }
- } else {
- if (!isRtl) {
- left = secondary;
- right = secondary + charWidth;
- } else {
- left = primary - charWidth;
- right = primary;
- }
- }
- // TODO: Check top-right and bottom-left as well.
- final float localLeft = left + viewportToContentHorizontalOffset;
- final float localRight = right + viewportToContentHorizontalOffset;
- final float localTop = top + viewportToContentVerticalOffset;
- final float localBottom = bottom + viewportToContentVerticalOffset;
- final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
- final boolean isBottomRightVisible =
- isPositionVisible(localRight, localBottom);
- int characterBoundsFlags = 0;
- if (isTopLeftVisible || isBottomRightVisible) {
- characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
- }
- if (!isTopLeftVisible || !isBottomRightVisible) {
- characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
- }
- if (isRtl) {
- characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
- }
- // Here offset is the index in Java chars.
- builder.addCharacterBounds(offset, localLeft, localTop, localRight,
- localBottom, characterBoundsFlags);
- }
- }
+ mTextView.populateCharacterBounds(builder, composingTextStart,
+ composingTextEnd, viewportToContentHorizontalOffset,
+ viewportToContentVerticalOffset);
}
}
@@ -4158,10 +4069,10 @@ public class Editor {
+ viewportToContentVerticalOffset;
final float insertionMarkerBottom = layout.getLineBottom(line)
+ viewportToContentVerticalOffset;
- final boolean isTopVisible =
- isPositionVisible(insertionMarkerX, insertionMarkerTop);
- final boolean isBottomVisible =
- isPositionVisible(insertionMarkerX, insertionMarkerBottom);
+ final boolean isTopVisible = mTextView
+ .isPositionVisible(insertionMarkerX, insertionMarkerTop);
+ final boolean isBottomVisible = mTextView
+ .isPositionVisible(insertionMarkerX, insertionMarkerBottom);
int insertionMarkerFlags = 0;
if (isTopVisible || isBottomVisible) {
insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
@@ -4369,7 +4280,8 @@ public class Editor {
return false;
}
- return isPositionVisible(mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
+ return mTextView.isPositionVisible(
+ mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
}
public abstract int getCurrentCursorOffset();
@@ -4764,7 +4676,7 @@ public class Editor {
}
positionAtCursorOffset(offset, false);
if (mTextActionMode != null) {
- invalidateActionMode(getTextClassifierInfo(false));
+ invalidateActionModeAsync();
}
}
@@ -4848,7 +4760,7 @@ public class Editor {
}
updateDrawable();
if (mTextActionMode != null) {
- invalidateActionMode(getTextClassifierInfo(false));
+ invalidateActionModeAsync();
}
}
@@ -5496,8 +5408,13 @@ public class Editor {
resetDragAcceleratorState();
if (mTextView.hasSelection()) {
- // TODO: Do not invoke the text assistant if this was a drag selection.
- startSelectionActionMode(getTextClassifierInfo(true));
+ // Do not invoke the text assistant if this was a drag selection.
+ if (mHaventMovedEnoughToStartDrag) {
+ startSelectionActionModeAsync();
+ } else {
+ startSelectionActionMode();
+ }
+
}
break;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e52c13b19534..80780a6fe0f1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3735,9 +3735,9 @@ public class ListView extends AbsListView {
}
}
- /* (non-Javadoc)
+ /**
* @see android.view.View#findViewById(int)
- * First look in our children, then in any header and footer views that may be scrolled off.
+ * @removed For internal use only. This should have been hidden.
*/
@Override
protected View findViewTraversal(@IdRes int id) {
@@ -3756,11 +3756,8 @@ public class ListView extends AbsListView {
return v;
}
- /* (non-Javadoc)
- *
- * Look in the passed in list of headers or footers for the view.
- */
View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
+ // Look in the passed in list of headers or footers for the view.
if (where != null) {
int len = where.size();
View v;
@@ -3780,9 +3777,9 @@ public class ListView extends AbsListView {
return null;
}
- /* (non-Javadoc)
+ /**
* @see android.view.View#findViewWithTag(Object)
- * First look in our children, then in any header and footer views that may be scrolled off.
+ * @removed For internal use only. This should have been hidden.
*/
@Override
protected View findViewWithTagTraversal(Object tag) {
@@ -3802,11 +3799,9 @@ public class ListView extends AbsListView {
return v;
}
- /* (non-Javadoc)
- *
- * Look in the passed in list of headers or footers for the view with the tag.
- */
View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
+ // Look in the passed in list of headers or footers for the view with
+ // the tag.
if (where != null) {
int len = where.size();
View v;
@@ -3827,9 +3822,11 @@ public class ListView extends AbsListView {
}
/**
- * @hide
+ * First look in our children, then in any header and footer views that may
+ * be scrolled off.
+ *
* @see android.view.View#findViewByPredicate(Predicate)
- * First look in our children, then in any header and footer views that may be scrolled off.
+ * @hide
*/
@Override
protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
@@ -3849,10 +3846,9 @@ public class ListView extends AbsListView {
return v;
}
- /* (non-Javadoc)
- *
- * Look in the passed in list of headers or footers for the first view that matches
- * the predicate.
+ /**
+ * Look in the passed in list of headers or footers for the first view that
+ * matches the predicate.
*/
View findViewByPredicateInHeadersOrFooters(ArrayList<FixedViewInfo> where,
Predicate<View> predicate, View childToSkip) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 46324a3807e7..989927e0c22d 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -35,8 +35,8 @@ import android.os.IBinder;
import android.transition.Transition;
import android.transition.Transition.EpicenterCallback;
import android.transition.Transition.TransitionListener;
-import android.transition.Transition.TransitionListenerAdapter;
import android.transition.TransitionInflater;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.AttributeSet;
@@ -232,7 +232,7 @@ public class PopupWindow {
mDecorView.getLayoutParams();
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
- p.width, p.height, mAnchoredGravity));
+ p.width, p.height, mAnchoredGravity, false));
update(p.x, p.y, -1, -1, true);
}
}
@@ -1237,7 +1237,7 @@ public class PopupWindow {
preparePopup(p);
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
- p.width, p.height, gravity);
+ p.width, p.height, gravity, mAllowScrollingAnchorParent);
updateAboveAnchor(aboveAnchor);
p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
@@ -1529,10 +1529,12 @@ public class PopupWindow {
* @param xOffset absolute horizontal offset from the left of the anchor
* @param yOffset absolute vertical offset from the top of the anchor
* @param gravity horizontal gravity specifying popup alignment
+ * @param allowScroll whether the anchor view's parent may be scrolled
+ * when the popup window doesn't fit on screen
* @return true if the popup is translated upwards to fit on screen
*/
private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
- int xOffset, int yOffset, int width, int height, int gravity) {
+ int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
final int anchorHeight = anchor.getHeight();
final int anchorWidth = anchor.getWidth();
if (mOverlapAnchor) {
@@ -1586,7 +1588,7 @@ public class PopupWindow {
final int scrollY = anchor.getScrollY();
final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
scrollY + height + anchorHeight + yOffset);
- if (mAllowScrollingAnchorParent && anchor.requestRectangleOnScreen(r, true)) {
+ if (allowScroll && anchor.requestRectangleOnScreen(r, true)) {
// Reset for the new anchor position.
anchor.getLocationInWindow(drawingLocation);
outParams.x = drawingLocation[0] + xOffset;
@@ -2182,15 +2184,19 @@ public class PopupWindow {
}
final boolean aboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
- width, height, gravity);
+ width, height, gravity, mAllowScrollingAnchorParent);
updateAboveAnchor(aboveAnchor);
final boolean paramsChanged = oldGravity != p.gravity || oldX != p.x || oldY != p.y
|| oldWidth != p.width || oldHeight != p.height;
- // If width and mWidth were both < 0 then we have a MATCH_PARENT/WRAP_CONTENT case.
- // findDropDownPosition will have resolved this to absolute values,
- // but we don't want to update mWidth/mHeight to these absolute values.
- update(p.x, p.y, width < 0 ? width : p.width, height < 0 ? height : p.height, paramsChanged);
+
+ // If width and mWidth were both < 0 then we have a MATCH_PARENT or
+ // WRAP_CONTENT case. findDropDownPosition will have resolved this to
+ // absolute values, but we don't want to update mWidth/mHeight to these
+ // absolute values.
+ final int newWidth = width < 0 ? width : p.width;
+ final int newHeight = height < 0 ? height : p.height;
+ update(p.x, p.y, newWidth, newHeight, paramsChanged);
}
/**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 266ff7520d91..ec2adfbd6552 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -2058,6 +2058,18 @@ public class ProgressBar extends View {
}
/**
+ * Returns whether the ProgressBar is animating or not. This is essentially the same
+ * as whether the ProgressBar is {@link #isIndeterminate() indeterminate} and visible,
+ * as indeterminate ProgressBars are always animating, and non-indeterminate
+ * ProgressBars are not animating.
+ *
+ * @return true if the ProgressBar is animating, false otherwise.
+ */
+ public boolean isAnimating() {
+ return isIndeterminate() && getWindowVisibility() == VISIBLE && isShown();
+ }
+
+ /**
* Command for sending an accessibility event.
*/
private class AccessibilityEventSender implements Runnable {
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 45fd9e6ef5a7..8ba4694c331c 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -403,10 +403,14 @@ public class RadioGroup extends LinearLayout {
}
}
- // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ // TODO(b/33197203): override onProvideAutoFillStructure and add a change listener
@Override
public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
final int index = value.getListValue();
final View child = getChildAt(index);
if (child == null) {
@@ -420,4 +424,9 @@ public class RadioGroup extends LinearLayout {
public AutoFillType getAutoFillType() {
return AutoFillType.forList();
}
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forList(getCheckedRadioButtonId()) : null;
+ }
}
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 3b7fe86a5fa1..70b70bcb36ea 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -150,7 +150,11 @@ public class RatingBar extends AbsSeekBar {
*/
public void setIsIndicator(boolean isIndicator) {
mIsUserSeekable = !isIndicator;
- setFocusable(!isIndicator);
+ if (isIndicator) {
+ setFocusable(FOCUSABLE_AUTO);
+ } else {
+ setFocusable(FOCUSABLE);
+ }
}
/**
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index b424101d0470..67bfe5e606c5 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1013,7 +1013,8 @@ public class RelativeLayout extends ViewGroup {
while (v.getVisibility() == View.GONE) {
rules = ((LayoutParams) v.getLayoutParams()).getRules(v.getLayoutDirection());
node = mGraph.mKeyNodes.get((rules[relation]));
- if (node == null) return null;
+ // ignore self dependency. for more info look in git commit: da3003
+ if (node == null || v == node.view) return null;
v = node.view;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index eb46b9f43b2d..359d04e71969 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3302,7 +3302,7 @@ public class RemoteViews implements Parcelable, Filter {
* Applies the views asynchronously, moving as much of the task on the background
* thread as possible.
*
- * @see {@link #apply(Context, ViewGroup)}
+ * @see #apply(Context, ViewGroup)
* @param context Default context to use
* @param parent Parent that the resulting view hierarchy will be attached to. This method
* does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate.
@@ -3457,7 +3457,7 @@ public class RemoteViews implements Parcelable, Filter {
* Applies all the actions to the provided view, moving as much of the task on the background
* thread as possible.
*
- * @see {@link #reapply(Context, View)}
+ * @see #reapply(Context, View)
* @param context Default context to use
* @param v The view to apply the actions to. This should be the result of
* the {@link #apply(Context,ViewGroup)} call.
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 9139361eda7c..38221383df3f 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -357,9 +357,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
setInputType(inputType);
}
- boolean focusable = true;
- focusable = a.getBoolean(R.styleable.SearchView_focusable, focusable);
- setFocusable(focusable);
+ if (getFocusable() == FOCUSABLE_AUTO) {
+ setFocusable(FOCUSABLE);
+ }
a.recycle();
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
new file mode 100644
index 000000000000..770d9eec792a
--- /dev/null
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -0,0 +1,288 @@
+/*
+ * 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.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UiThread;
+import android.annotation.WorkerThread;
+import android.os.AsyncTask;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.view.ActionMode;
+import android.view.textclassifier.TextClassificationResult;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
+import android.widget.Editor.SelectionModifierCursorController;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Helper class for starting selection action mode
+ * (synchronously without the TextClassifier, asynchronously with the TextClassifier).
+ */
+@UiThread
+final class SelectionActionModeHelper {
+
+ /**
+ * Maximum time (in milliseconds) to wait for a result before timing out.
+ */
+ // TODO: Consider making this a ViewConfiguration.
+ private static final int TIMEOUT_DURATION = 200;
+
+ private final Editor mEditor;
+ private final TextClassificationHelper mTextClassificationHelper;
+
+ private TextClassificationResult mTextClassificationResult;
+ private AsyncTask mTextClassificationAsyncTask;
+
+ SelectionActionModeHelper(@NonNull Editor editor) {
+ mEditor = Preconditions.checkNotNull(editor);
+ final TextView textView = mEditor.getTextView();
+ mTextClassificationHelper = new TextClassificationHelper(
+ textView.getTextClassifier(), textView.getText(),
+ textView.getSelectionStart(), textView.getSelectionEnd());
+ }
+
+ public void startActionModeAsync() {
+ cancelAsyncTask();
+ if (isNoOpTextClassifier()) {
+ // No need to make an async call for a no-op TextClassifier.
+ startActionMode(null);
+ } else {
+ resetTextClassificationHelper();
+ mTextClassificationAsyncTask = new TextClassificationAsyncTask(
+ mEditor.getTextView(), TIMEOUT_DURATION,
+ mTextClassificationHelper::suggestSelection, this::startActionMode)
+ .execute();
+ }
+ }
+
+ public void startActionMode() {
+ startActionMode(null);
+ }
+
+ public void invalidateActionModeAsync() {
+ cancelAsyncTask();
+ if (isNoOpTextClassifier()) {
+ // No need to make an async call for a no-op TextClassifier.
+ invalidateActionMode(null);
+ } else {
+ resetTextClassificationHelper();
+ mTextClassificationAsyncTask = new TextClassificationAsyncTask(
+ mEditor.getTextView(), TIMEOUT_DURATION,
+ mTextClassificationHelper::classifyText, this::invalidateActionMode)
+ .execute();
+ }
+ }
+
+ public void cancelAsyncTask() {
+ if (mTextClassificationAsyncTask != null) {
+ mTextClassificationAsyncTask.cancel(true);
+ mTextClassificationAsyncTask = null;
+ }
+ mTextClassificationResult = null;
+ }
+
+ @Nullable
+ public TextClassificationResult getTextClassificationResult() {
+ return mTextClassificationResult;
+ }
+
+ private boolean isNoOpTextClassifier() {
+ return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
+ }
+
+ private void startActionMode(@Nullable SelectionResult result) {
+ final CharSequence text = mEditor.getTextView().getText();
+ if (result != null && text instanceof Spannable) {
+ Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+ mTextClassificationResult = result.mResult;
+ } else {
+ mTextClassificationResult = null;
+ }
+ if (mEditor.startSelectionActionModeInternal()) {
+ final SelectionModifierCursorController controller = mEditor.getSelectionController();
+ if (controller != null) {
+ controller.show();
+ }
+ }
+ mEditor.setRestartActionModeOnNextRefresh(false);
+ mTextClassificationAsyncTask = null;
+ }
+
+ private void invalidateActionMode(@Nullable SelectionResult result) {
+ mTextClassificationResult = result != null ? result.mResult : null;
+ final ActionMode actionMode = mEditor.getTextActionMode();
+ if (actionMode != null) {
+ actionMode.invalidate();
+ }
+ mTextClassificationAsyncTask = null;
+ }
+
+ private void resetTextClassificationHelper() {
+ final TextView textView = mEditor.getTextView();
+ mTextClassificationHelper.reset(textView.getTextClassifier(), textView.getText(),
+ textView.getSelectionStart(), textView.getSelectionEnd());
+ }
+
+ /**
+ * AsyncTask for running a query on a background thread and returning the result on the
+ * UiThread. The AsyncTask times out after a specified time, returning a null result if the
+ * query has not yet returned.
+ */
+ private static final class TextClassificationAsyncTask
+ extends AsyncTask<Void, Void, SelectionResult> {
+
+ private final int mTimeOutDuration;
+ private final Supplier<SelectionResult> mSelectionResultSupplier;
+ private final Consumer<SelectionResult> mSelectionResultCallback;
+ private final TextView mTextView;
+ private final String mOriginalText;
+
+ /**
+ * @param textView the TextView
+ * @param timeOut time in milliseconds to timeout the query if it has not completed
+ * @param selectionResultSupplier fetches the selection results. Runs on a background thread
+ * @param selectionResultCallback receives the selection results. Runs on the UiThread
+ */
+ TextClassificationAsyncTask(
+ @NonNull TextView textView, int timeOut,
+ @NonNull Supplier<SelectionResult> selectionResultSupplier,
+ @NonNull Consumer<SelectionResult> selectionResultCallback) {
+ mTextView = Preconditions.checkNotNull(textView);
+ mTimeOutDuration = timeOut;
+ mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
+ mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
+ // Make a copy of the original text.
+ mOriginalText = mTextView.getText().toString();
+ }
+
+ @Override
+ @WorkerThread
+ protected SelectionResult doInBackground(Void... params) {
+ final Runnable onTimeOut = this::onTimeOut;
+ mTextView.postDelayed(onTimeOut, mTimeOutDuration);
+ final SelectionResult result = mSelectionResultSupplier.get();
+ mTextView.removeCallbacks(onTimeOut);
+ return result;
+ }
+
+ @Override
+ @UiThread
+ protected void onPostExecute(SelectionResult result) {
+ result = TextUtils.equals(mOriginalText, mTextView.getText()) ? result : null;
+ mSelectionResultCallback.accept(result);
+ }
+
+ private void onTimeOut() {
+ if (getStatus() == Status.RUNNING) {
+ onPostExecute(null);
+ }
+ cancel(true);
+ }
+ }
+
+ /**
+ * Helper class for querying the TextClassifier.
+ * It trims text so that only text necessary to provide context of the selected text is
+ * sent to the TextClassifier.
+ */
+ private static final class TextClassificationHelper {
+
+ private static final int TRIM_DELTA = 50; // characters
+
+ private TextClassifier mTextClassifier;
+
+ /** The original TextView text. **/
+ private String mText;
+ /** Start index relative to mText. */
+ private int mSelectionStart;
+ /** End index relative to mText. */
+ private int mSelectionEnd;
+
+ /** Trimmed text starting from mTrimStart in mText. */
+ private CharSequence mTrimmedText;
+ /** Index indicating the start of mTrimmedText in mText. */
+ private int mTrimStart;
+ /** Start index relative to mTrimmedText */
+ private int mRelativeStart;
+ /** End index relative to mTrimmedText */
+ private int mRelativeEnd;
+
+ TextClassificationHelper(TextClassifier textClassifier,
+ CharSequence text, int selectionStart, int selectionEnd) {
+ reset(textClassifier, text, selectionStart, selectionEnd);
+ }
+
+ @UiThread
+ public void reset(TextClassifier textClassifier,
+ CharSequence text, int selectionStart, int selectionEnd) {
+ mTextClassifier = Preconditions.checkNotNull(textClassifier);
+ mText = Preconditions.checkNotNull(text).toString();
+ mSelectionStart = selectionStart;
+ mSelectionEnd = selectionEnd;
+ }
+
+ @WorkerThread
+ public SelectionResult classifyText() {
+ trimText();
+ return new SelectionResult(
+ mSelectionStart,
+ mSelectionEnd,
+ mTextClassifier.getTextClassificationResult(
+ mTrimmedText, mRelativeStart, mRelativeEnd));
+ }
+
+ @WorkerThread
+ public SelectionResult suggestSelection() {
+ trimText();
+ final TextSelection sel = mTextClassifier.suggestSelection(
+ mTrimmedText, mRelativeStart, mRelativeEnd);
+ mSelectionStart = Math.max(0, sel.getSelectionStartIndex() + mTrimStart);
+ mSelectionEnd = Math.min(mText.length(), sel.getSelectionEndIndex() + mTrimStart);
+ return classifyText();
+ }
+
+ private void trimText() {
+ mTrimStart = Math.max(0, mSelectionStart - TRIM_DELTA);
+ final int referenceEnd = Math.min(mText.length(), mSelectionEnd + TRIM_DELTA);
+ mTrimmedText = mText.subSequence(mTrimStart, referenceEnd);
+ mRelativeStart = mSelectionStart - mTrimStart;
+ mRelativeEnd = mSelectionEnd - mTrimStart;
+ }
+ }
+
+ /**
+ * Selection result.
+ */
+ private static final class SelectionResult {
+ private final int mStart;
+ private final int mEnd;
+ private final TextClassificationResult mResult;
+
+ SelectionResult(int start, int end, TextClassificationResult result) {
+ mStart = start;
+ mEnd = end;
+ mResult = Preconditions.checkNotNull(result);
+ }
+ }
+}
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
new file mode 100644
index 000000000000..ef91576c0e27
--- /dev/null
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -0,0 +1,249 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.MathUtils;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * View to show text input based time picker with hour and minute fields and an optional AM/PM
+ * spinner.
+ *
+ * @hide
+ */
+public class TextInputTimePickerView extends RelativeLayout {
+ public static final int HOURS = 0;
+ public static final int MINUTES = 1;
+ public static final int AMPM = 2;
+
+ private static final int AM = 0;
+ private static final int PM = 1;
+
+ private final EditText mHourEditText;
+ private final EditText mMinuteEditText;
+ private final TextView mInputSeparatorView;
+ private final Spinner mAmPmSpinner;
+ private final TextView mErrorLabel;
+ private final TextView mHourLabel;
+ private final TextView mMinuteLabel;
+
+ private boolean mIs24Hour;
+ private boolean mHourFormatStartsAtZero;
+ private OnValueTypedListener mListener;
+
+ private boolean mErrorShowing;
+
+ interface OnValueTypedListener {
+ void onValueChanged(int inputType, int newValue);
+ }
+
+ public TextInputTimePickerView(Context context) {
+ this(context, null);
+ }
+
+ public TextInputTimePickerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle,
+ int defStyleRes) {
+ super(context, attrs, defStyle, defStyleRes);
+
+ inflate(context, R.layout.time_picker_text_input_material, this);
+
+ mHourEditText = (EditText) findViewById(R.id.input_hour);
+ mMinuteEditText = (EditText) findViewById(R.id.input_minute);
+ mInputSeparatorView = (TextView) findViewById(R.id.input_separator);
+ mErrorLabel = (TextView) findViewById(R.id.label_error);
+ mHourLabel = (TextView) findViewById(R.id.label_hour);
+ mMinuteLabel = (TextView) findViewById(R.id.label_minute);
+
+ mHourEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ parseAndSetHourInternal(editable.toString());
+ }
+ });
+
+ mMinuteEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ parseAndSetMinuteInternal(editable.toString());
+ }
+ });
+
+ mAmPmSpinner = (Spinner) findViewById(R.id.am_pm_spinner);
+ final String[] amPmStrings = TimePicker.getAmPmStrings(context);
+ ArrayAdapter<CharSequence> adapter =
+ new ArrayAdapter<CharSequence>(context, R.layout.simple_spinner_dropdown_item);
+ adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[0]));
+ adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[1]));
+ mAmPmSpinner.setAdapter(adapter);
+ mAmPmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapterView, View view, int position,
+ long id) {
+ if (position == 0) {
+ mListener.onValueChanged(AMPM, AM);
+ } else {
+ mListener.onValueChanged(AMPM, PM);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapterView) {}
+ });
+ }
+
+ void setListener(OnValueTypedListener listener) {
+ mListener = listener;
+ }
+
+ void setHourFormat(int maxCharLength) {
+ mHourEditText.setFilters(new InputFilter[] {
+ new InputFilter.LengthFilter(maxCharLength)});
+ mMinuteEditText.setFilters(new InputFilter[] {
+ new InputFilter.LengthFilter(maxCharLength)});
+ }
+
+ boolean validateInput() {
+ final boolean inputValid = parseAndSetHourInternal(mHourEditText.getText().toString())
+ && parseAndSetMinuteInternal(mMinuteEditText.getText().toString());
+ setError(!inputValid);
+ return inputValid;
+ }
+
+ void updateSeparator(String separatorText) {
+ mInputSeparatorView.setText(separatorText);
+ }
+
+ private void setError(boolean enabled) {
+ mErrorShowing = enabled;
+
+ mErrorLabel.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
+ mHourLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
+ mMinuteLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ /**
+ * Computes the display value and updates the text of the view.
+ * <p>
+ * This method should be called whenever the current value or display
+ * properties (leading zeroes, max digits) change.
+ */
+ void updateTextInputValues(int localizedHour, int minute, int amOrPm, boolean is24Hour,
+ boolean hourFormatStartsAtZero) {
+ final String format = "%d";
+
+ mIs24Hour = is24Hour;
+ mHourFormatStartsAtZero = hourFormatStartsAtZero;
+
+ mAmPmSpinner.setVisibility(is24Hour ? View.INVISIBLE : View.VISIBLE);
+
+ mHourEditText.setText(String.format(format, localizedHour));
+ mMinuteEditText.setText(String.format(format, minute));
+
+ if (amOrPm == AM) {
+ mAmPmSpinner.setSelection(0);
+ } else {
+ mAmPmSpinner.setSelection(1);
+ }
+
+ if (mErrorShowing) {
+ validateInput();
+ }
+ }
+
+ private boolean parseAndSetHourInternal(String input) {
+ try {
+ final int hour = Integer.parseInt(input);
+ if (!isValidLocalizedHour(hour)) {
+ final int minHour = mHourFormatStartsAtZero ? 0 : 1;
+ final int maxHour = mIs24Hour ? 23 : 11 + minHour;
+ mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(
+ MathUtils.constrain(hour, minHour, maxHour)));
+ return false;
+ }
+ mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(hour));
+ return true;
+ } catch (NumberFormatException e) {
+ // Do nothing since we cannot parse the input.
+ return false;
+ }
+ }
+
+ private boolean parseAndSetMinuteInternal(String input) {
+ try {
+ final int minutes = Integer.parseInt(input);
+ if (minutes < 0 || minutes > 59) {
+ mListener.onValueChanged(MINUTES, MathUtils.constrain(minutes, 0, 59));
+ return false;
+ }
+ mListener.onValueChanged(MINUTES, minutes);
+ return true;
+ } catch (NumberFormatException e) {
+ // Do nothing since we cannot parse the input.
+ return false;
+ }
+ }
+
+ private boolean isValidLocalizedHour(int localizedHour) {
+ final int minHour = mHourFormatStartsAtZero ? 0 : 1;
+ final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
+ return localizedHour >= minHour && localizedHour <= maxHour;
+ }
+
+ private int getHourOfDayFromLocalizedHour(int localizedHour) {
+ int hourOfDay = localizedHour;
+ if (mIs24Hour) {
+ if (!mHourFormatStartsAtZero && localizedHour == 24) {
+ hourOfDay = 0;
+ }
+ } else {
+ if (!mHourFormatStartsAtZero && localizedHour == 12) {
+ hourOfDay = 0;
+ }
+ if (mAmPmSpinner.getSelectedItemPosition() == 1) {
+ hourOfDay += 12;
+ }
+ }
+ return hourOfDay;
+ }
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2f303cdba301..28c5c60686ed 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,10 @@
package android.widget;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+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;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
+import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
import android.R;
import android.annotation.ColorInt;
@@ -136,9 +140,13 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -163,6 +171,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Locale;
/**
@@ -264,6 +273,8 @@ import java.util.Locale;
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
static final String LOG_TAG = "TextView";
static final boolean DEBUG_EXTRACT = false;
+ static final boolean DEBUG_AUTOFILL = false;
+ private static final float[] TEMP_POSITION = new float[2];
// Enum for the "typeface" XML parameter.
// TODO: How can we get this from the XML instead of hardcoding it here?
@@ -707,6 +718,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text.
private int[] mAutoSizeTextSizesInPx;
+ // Watcher used to notify changes to auto-fill manager.
+ private AutoFillChangeWatcher mAutoFillChangeWatcher;
+
/**
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -783,6 +797,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
ColorStateList textColorLink = null;
int textSize = 15;
String fontFamily = null;
+ Typeface fontTypeface = null;
boolean fontFamilyExplicit = false;
int typefaceIndex = -1;
int styleIndex = -1;
@@ -845,7 +860,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextAppearance_fontFamily:
- fontFamily = appearance.getString(attr);
+ try {
+ fontTypeface = appearance.getFont(attr);
+ } catch (UnsupportedOperationException e) {
+ // Expected if it is not a font resource.
+ }
+ if (fontTypeface == null) {
+ fontFamily = appearance.getString(attr);
+ }
break;
case com.android.internal.R.styleable.TextAppearance_textStyle:
@@ -1149,7 +1171,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_fontFamily:
- fontFamily = a.getString(attr);
+ try {
+ fontTypeface = a.getFont(attr);
+ } catch (UnsupportedOperationException e) {
+ // Expected if it is not a font resource.
+ }
+ if (fontTypeface == null) {
+ fontFamily = a.getString(attr);
+ }
fontFamilyExplicit = true;
break;
@@ -1499,7 +1528,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (typefaceIndex != -1 && !fontFamilyExplicit) {
fontFamily = null;
}
- setTypefaceFromAttrs(fontFamily, typefaceIndex, styleIndex);
+ setTypefaceFromAttrs(fontTypeface, fontFamily, typefaceIndex, styleIndex);
if (shadowcolor != 0) {
setShadowLayer(r, dx, dy, shadowcolor);
@@ -1515,26 +1544,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (hint != null) setHint(hint);
/*
- * Views are not normally focusable unless specified to be.
+ * Views are not normally clickable unless specified to be.
* However, TextViews that have input or movement methods *are*
- * focusable by default.
+ * clickable by default. By setting clickable here, we implicitly set focusable as well
+ * if not overridden by the developer.
*/
a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
-
- boolean focusable = mMovement != null || getKeyListener() != null;
- boolean clickable = focusable || isClickable();
- boolean longClickable = focusable || isLongClickable();
+ boolean canInputOrMove = (mMovement != null || getKeyListener() != null);
+ boolean clickable = canInputOrMove || isClickable();
+ boolean longClickable = canInputOrMove || isLongClickable();
n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
- case com.android.internal.R.styleable.View_focusable:
- focusable = a.getBoolean(attr, focusable);
- break;
-
case com.android.internal.R.styleable.View_clickable:
clickable = a.getBoolean(attr, clickable);
break;
@@ -1546,7 +1571,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
a.recycle();
- setFocusable(focusable);
setClickable(clickable);
setLongClickable(longClickable);
@@ -1797,14 +1821,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- private void setTypefaceFromAttrs(String familyName, int typefaceIndex, int styleIndex) {
- Typeface tf = null;
- if (familyName != null) {
+ private void setTypefaceFromAttrs(Typeface fontTypeface, String familyName, int typefaceIndex,
+ int styleIndex) {
+ Typeface tf = fontTypeface;
+ if (tf == null && familyName != null) {
tf = Typeface.create(familyName, styleIndex);
- if (tf != null) {
- setTypeface(tf);
- return;
- }
+ }
+ if (tf != null) {
+ setTypeface(tf);
+ return;
}
switch (typefaceIndex) {
case SANS:
@@ -2155,11 +2180,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private void fixFocusableAndClickableSettings() {
if (mMovement != null || (mEditor != null && mEditor.mKeyListener != null)) {
- setFocusable(true);
+ setFocusable(FOCUSABLE);
setClickable(true);
setLongClickable(true);
} else {
- setFocusable(false);
+ setFocusable(FOCUSABLE_AUTO);
setClickable(false);
setLongClickable(false);
}
@@ -3102,10 +3127,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setLinkTextColor(textColorLink);
}
- final String fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily);
+ Typeface fontTypeface = null;
+ String fontFamily = null;
+ try {
+ fontTypeface = ta.getFont(R.styleable.TextAppearance_fontFamily);
+ } catch (UnsupportedOperationException e) {
+ // Expected if it is not a font resource.
+ }
+ if (fontTypeface == null) {
+ fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily);
+ }
final int typefaceIndex = ta.getInt(R.styleable.TextAppearance_typeface, -1);
final int styleIndex = ta.getInt(R.styleable.TextAppearance_textStyle, -1);
- setTypefaceFromAttrs(fontFamily, typefaceIndex, styleIndex);
+ setTypefaceFromAttrs(fontTypeface, fontFamily, typefaceIndex, styleIndex);
final int shadowColor = ta.getInt(R.styleable.TextAppearance_shadowColor, 0);
if (shadowColor != 0) {
@@ -3434,6 +3468,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns the font variation settings.
+ *
+ * @return the currently set font variation settings. Returns null if no variation is
+ * specified.
+ *
+ * @see #setFontVariationSettings(String)
+ * @see Paint#setFontVariationSettings(String) Paint.setFontVariationSettings(String)
+ */
+ @Nullable
+ public String getFontVariationSettings() {
+ return mTextPaint.getFontVariationSettings();
+ }
+
+ /**
* Sets the break strategy for breaking paragraphs into lines. The default value for
* TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
* EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
@@ -3540,6 +3588,41 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
+ * Sets TrueType or OpenType font variation settings. The settings string is constructed from
+ * multiple pairs of axis tag and style values. The axis tag must contain four ASCII characters
+ * and must be wrapped with single quotes (U+0027) or double quotes (U+0022). Axis strings that
+ * are longer or shorter than four characters, or contain characters outside of U+0020..U+007E
+ * are invalid. If a specified axis name is not defined in the font, the settings will be
+ * ignored.
+ *
+ * <pre>
+ * textView.setFontVariationSettings("'wdth' 1.0");
+ * textView.setFontVariationSettings("'AX ' 1.8, 'FB ' 2.0");
+ * </pre>
+ *
+ * @param fontVariationSettings font variation settings. You can pass null or empty string as
+ * no variation settings.
+ *
+ * @see #getFontVariationSettings()
+ * @see Paint#getFontVariationSettings() Paint.getFontVariationSettings()
+ */
+ public void setFontVariationSettings(@Nullable String fontVariationSettings) {
+ final String existingSettings = mTextPaint.getFontVariationSettings();
+ if (fontVariationSettings == existingSettings
+ || (fontVariationSettings != null
+ && fontVariationSettings.equals(existingSettings))) {
+ return;
+ }
+ mTextPaint.setFontVariationSettings(fontVariationSettings);
+
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
* Sets the text color for all the states (normal, selected,
* focused) to be this color.
*
@@ -5166,15 +5249,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean forceUpdate = false;
if (isPassword) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
- setTypefaceFromAttrs(null /* fontFamily */, MONOSPACE, 0);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0);
} else if (isVisiblePassword) {
if (mTransformation == PasswordTransformationMethod.getInstance()) {
forceUpdate = true;
}
- setTypefaceFromAttrs(null /* fontFamily */, MONOSPACE, 0);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0);
} else if (wasPassword || wasVisiblePassword) {
// not in password mode, clean up typeface and transformation
- setTypefaceFromAttrs(null /* fontFamily */, -1, -1);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, -1, -1);
if (mTransformation == PasswordTransformationMethod.getInstance()) {
forceUpdate = true;
}
@@ -6126,7 +6209,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mEditor.mTextIsSelectable = selectable;
setFocusableInTouchMode(selectable);
- setFocusable(selectable);
+ setFocusable(FOCUSABLE_AUTO);
setClickable(selectable);
setLongClickable(selectable);
@@ -6559,7 +6642,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public boolean handleBackInTextActionModeIfNeeded(KeyEvent event) {
// Do nothing unless mEditor is in text action mode.
- if (mEditor == null || mEditor.mTextActionMode == null) {
+ if (mEditor == null || mEditor.getTextActionMode() == null) {
return false;
}
@@ -6743,7 +6826,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Has to be done on key down (and not on key up) to correctly be intercepted.
case KeyEvent.KEYCODE_BACK:
- if (mEditor != null && mEditor.mTextActionMode != null) {
+ if (mEditor != null && mEditor.getTextActionMode() != null) {
stopTextActionMode();
return KEY_EVENT_HANDLED;
}
@@ -8936,7 +9019,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mEditor != null) {
mEditor.refreshTextActionMode();
- if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+ if (!hasSelection()
+ && mEditor.getTextActionMode() == null && hasTransientState()) {
// User generated selection has been removed.
setHasTransientState(false);
}
@@ -9563,7 +9647,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return new GestureDetector(mContext,
new GestureDetector.SimpleOnGestureListener() {
@Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
+ public boolean onSingleTapUp(MotionEvent e) {
if (shouldUseClickableSpanOnClickGestureDetector()) {
ClickableSpan[] links = ((Spannable) mText).getSpans(
getSelectionStart(), getSelectionEnd(),
@@ -9626,24 +9710,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
- onProvideAutoStructureForAssistOrAutoFill(structure, 0);
+ onProvideAutoStructureForAssistOrAutoFill(structure, false);
}
@Override
public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
super.onProvideAutoFillStructure(structure, flags);
- onProvideAutoStructureForAssistOrAutoFill(structure, flags);
+ onProvideAutoStructureForAssistOrAutoFill(structure, true);
}
- private void onProvideAutoStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
- final boolean forAutoFillSave =
- (flags & AUTO_FILL_FLAG_TYPE_SAVE) != 0;
-
+ private void onProvideAutoStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
final boolean isPassword = hasPasswordTransformationMethod()
|| isPasswordInputType(getInputType());
- if (!isPassword || forAutoFillSave) {
+ if (forAutoFill) {
+ // TODO(b/33197203, b/33269702): temporary set it as not sanitized until
+ // AssistStructure automaticaly sets sanitization based on text coming from resources
+ structure.setSanitized(!isPassword);
+ if (mAutoFillChangeWatcher == null && isTextEditable()) {
+ mAutoFillChangeWatcher = new AutoFillChangeWatcher();
+ addTextChangedListener(mAutoFillChangeWatcher);
+ // TODO(b/33197203): remove mAutoFillValueListener auto-fill session is finished
+ }
+ }
+
+ if (!isPassword || forAutoFill) {
if (mLayout == null) {
assumeLayout();
}
@@ -9651,7 +9742,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int lineCount = layout.getLineCount();
if (lineCount <= 1) {
// Simple case: this is a single line.
- structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+ final CharSequence text = getText();
+ structure.setText(text, getSelectionStart(), getSelectionEnd());
} else {
// Complex case: multi-line, could be scrolled or within a scroll container
// so some lines are not visible.
@@ -9748,6 +9840,29 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
structure.setHint(getHint());
}
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ final CharSequence text = value.getTextValue();
+
+ if (text != null && isTextEditable()) {
+ setText(text, mBufferType, true, 0);
+ }
+ }
+
+ @Override
+ @Nullable
+ public AutoFillType getAutoFillType() {
+ return isTextEditable() ? AutoFillType.forText(getInputType()) : null;
+ }
+
+ @Override
+ @Nullable
+ public AutoFillValue getAutoFillValue() {
+ return isTextEditable() ? AutoFillValue.forText(getText()) : null;
+ }
+
/** @hide */
@Override
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
@@ -9799,6 +9914,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
+ info.setAvailableExtraData(
+ Arrays.asList(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY));
}
if (isFocused()) {
@@ -9835,6 +9952,164 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ @Override
+ public void addExtraDataToAccessibilityNodeInfo(
+ AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+ if (extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) {
+ int positionInfoStartIndex = arguments.getInt(
+ EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, -1);
+ int positionInfoLength = arguments.getInt(
+ EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, -1);
+ if ((positionInfoLength <= 0) || (positionInfoStartIndex < 0)
+ || (positionInfoStartIndex >= mText.length())) {
+ Log.e(LOG_TAG, "Invalid arguments for accessibility character locations");
+ return;
+ }
+ RectF[] boundingRects = new RectF[positionInfoLength];
+ final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+ populateCharacterBounds(builder, positionInfoStartIndex,
+ positionInfoStartIndex + positionInfoLength,
+ viewportToContentHorizontalOffset(), viewportToContentVerticalOffset());
+ CursorAnchorInfo cursorAnchorInfo = builder.setMatrix(null).build();
+ if (mTempRect == null) mTempRect = new Rect();
+ Rect viewBoundsInScreen = mTempRect;
+ info.getBoundsInScreen(viewBoundsInScreen);
+ for (int i = 0; i < positionInfoLength; i++) {
+ int flags = cursorAnchorInfo.getCharacterBoundsFlags(positionInfoStartIndex + i);
+ if ((flags & FLAG_HAS_VISIBLE_REGION) == FLAG_HAS_VISIBLE_REGION) {
+ RectF bounds = cursorAnchorInfo
+ .getCharacterBounds(positionInfoStartIndex + i);
+ if (bounds != null) {
+ bounds.offset(viewBoundsInScreen.left, viewBoundsInScreen.top);
+ boundingRects[i] = bounds;
+ }
+ }
+ }
+ info.getExtras().putParcelableArray(extraDataKey, boundingRects);
+ }
+ }
+
+ /**
+ * Populate requested character bounds in a {@link CursorAnchorInfo.Builder}
+ *
+ * @param builder The builder to populate
+ * @param startIndex The starting character index to populate
+ * @param endIndex The ending character index to populate
+ * @param viewportToContentHorizontalOffset The horizontal offset from the viewport to the
+ * content
+ * @param viewportToContentVerticalOffset The vertical offset from the viewport to the content
+ * @hide
+ */
+ public void populateCharacterBounds(CursorAnchorInfo.Builder builder,
+ int startIndex, int endIndex, float viewportToContentHorizontalOffset,
+ float viewportToContentVerticalOffset) {
+ final int minLine = mLayout.getLineForOffset(startIndex);
+ final int maxLine = mLayout.getLineForOffset(endIndex - 1);
+ for (int line = minLine; line <= maxLine; ++line) {
+ final int lineStart = mLayout.getLineStart(line);
+ final int lineEnd = mLayout.getLineEnd(line);
+ final int offsetStart = Math.max(lineStart, startIndex);
+ final int offsetEnd = Math.min(lineEnd, endIndex);
+ final boolean ltrLine =
+ mLayout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
+ final float[] widths = new float[offsetEnd - offsetStart];
+ mLayout.getPaint().getTextWidths(mText, offsetStart, offsetEnd, widths);
+ final float top = mLayout.getLineTop(line);
+ final float bottom = mLayout.getLineBottom(line);
+ for (int offset = offsetStart; offset < offsetEnd; ++offset) {
+ final float charWidth = widths[offset - offsetStart];
+ final boolean isRtl = mLayout.isRtlCharAt(offset);
+ final float primary = mLayout.getPrimaryHorizontal(offset);
+ final float secondary = mLayout.getSecondaryHorizontal(offset);
+ // TODO: This doesn't work perfectly for text with custom styles and
+ // TAB chars.
+ final float left;
+ final float right;
+ if (ltrLine) {
+ if (isRtl) {
+ left = secondary - charWidth;
+ right = secondary;
+ } else {
+ left = primary;
+ right = primary + charWidth;
+ }
+ } else {
+ if (!isRtl) {
+ left = secondary;
+ right = secondary + charWidth;
+ } else {
+ left = primary - charWidth;
+ right = primary;
+ }
+ }
+ // TODO: Check top-right and bottom-left as well.
+ final float localLeft = left + viewportToContentHorizontalOffset;
+ final float localRight = right + viewportToContentHorizontalOffset;
+ final float localTop = top + viewportToContentVerticalOffset;
+ final float localBottom = bottom + viewportToContentVerticalOffset;
+ final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
+ final boolean isBottomRightVisible =
+ isPositionVisible(localRight, localBottom);
+ int characterBoundsFlags = 0;
+ if (isTopLeftVisible || isBottomRightVisible) {
+ characterBoundsFlags |= FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopLeftVisible || !isBottomRightVisible) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
+ if (isRtl) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
+ // Here offset is the index in Java chars.
+ builder.addCharacterBounds(offset, localLeft, localTop, localRight,
+ localBottom, characterBoundsFlags);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean isPositionVisible(final float positionX, final float positionY) {
+ synchronized (TEMP_POSITION) {
+ final float[] position = TEMP_POSITION;
+ position[0] = positionX;
+ position[1] = positionY;
+ View view = this;
+
+ while (view != null) {
+ if (view != this) {
+ // Local scroll is already taken into account in positionX/Y
+ position[0] -= view.getScrollX();
+ position[1] -= view.getScrollY();
+ }
+
+ if (position[0] < 0 || position[1] < 0 || position[0] > view.getWidth()
+ || position[1] > view.getHeight()) {
+ return false;
+ }
+
+ if (!view.getMatrix().isIdentity()) {
+ view.getMatrix().mapPoints(position);
+ }
+
+ position[0] += view.getLeft();
+ position[1] += view.getTop();
+
+ final ViewParent parent = view.getParent();
+ if (parent instanceof View) {
+ view = (View) parent;
+ } else {
+ // We've reached the ViewRoot, stop iterating
+ view = null;
+ }
+ }
+ }
+
+ // We've been able to walk up the view hierarchy and the position was never clipped
+ return true;
+ }
+
/**
* Performs an accessibility action after it has been offered to the
* delegate.
@@ -9892,7 +10167,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) text, start, end);
// Make sure selection mode is engaged.
if (mEditor != null) {
- mEditor.startSelectionActionMode(null);
+ mEditor.startSelectionActionModeAsync();
}
return true;
}
@@ -11085,6 +11360,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ // TODO(b/33197203): implements SpanWatcher too?
+ private final class AutoFillChangeWatcher implements TextWatcher {
+
+ private final AutoFillManager mAfm = mContext.getSystemService(AutoFillManager.class);
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (mAfm != null) {
+ if (DEBUG_AUTOFILL) {
+ Log.v(LOG_TAG, "AutoFillChangeWatcher.afterTextChanged(): s=" + s);
+ }
+ mAfm.valueChanged(TextView.this);
+ }
+ }
+ }
+
private class ChangeWatcher implements TextWatcher, SpanWatcher {
private CharSequence mBeforeText;
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index e6cd7987d59a..9f38b04d4e09 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -278,6 +278,16 @@ public class TimePicker extends FrameLayout {
return mDelegate.getBaseline();
}
+ /**
+ * Validates whether current input by the user is a valid time based on the locale. TimePicker
+ * will show an error message to the user if the time is not valid.
+ *
+ * @return {@code true} if the input is valid, {@code false} otherwise
+ */
+ public boolean validateInput() {
+ return mDelegate.validateInput();
+ }
+
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
@@ -341,6 +351,8 @@ public class TimePicker extends FrameLayout {
void setIs24Hour(boolean is24Hour);
boolean is24Hour();
+ boolean validateInput();
+
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
void setEnabled(boolean enabled);
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1d37a21c1e7e..3a0906393b97 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -16,12 +16,14 @@
package android.widget;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.icu.text.DecimalFormatSymbols;
import android.os.Parcelable;
import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
@@ -40,11 +42,14 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.RadialTimePickerView.OnValueSelectedListener;
+import android.widget.TextInputTimePickerView.OnValueTypedListener;
import com.android.internal.R;
import com.android.internal.widget.NumericTextView;
import com.android.internal.widget.NumericTextView.OnValueChangedListener;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Calendar;
/**
@@ -58,6 +63,13 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
*/
private static final long DELAY_COMMIT_MILLIS = 2000;
+ @IntDef({FROM_EXTERNAL_API, FROM_RADIAL_PICKER, FROM_INPUT_PICKER})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface ChangeSource {}
+ private static final int FROM_EXTERNAL_API = 0;
+ private static final int FROM_RADIAL_PICKER = 1;
+ private static final int FROM_INPUT_PICKER = 2;
+
// Index used by RadialPickerLayout
private static final int HOUR_INDEX = RadialTimePickerView.HOURS;
private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES;
@@ -78,6 +90,15 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private final RadialTimePickerView mRadialTimePickerView;
private final TextView mSeparatorView;
+ private boolean mRadialPickerModeEnabled = true;
+ private final ImageButton mRadialTimePickerModeButton;
+ private final String mRadialTimePickerModeEnabledDescription;
+ private final String mTextInputPickerModeEnabledDescription;
+ private final View mRadialTimePickerHeader;
+ private final View mTextInputPickerHeader;
+
+ private final TextInputTimePickerView mTextInputPickerView;
+
private final Calendar mTempCalendar;
// Accessibility strings.
@@ -116,8 +137,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_material);
final View mainView = inflater.inflate(layoutResourceId, delegator);
- final View headerView = mainView.findViewById(R.id.time_header);
- headerView.setOnTouchListener(new NearestTouchDelegate());
+ mRadialTimePickerHeader = mainView.findViewById(R.id.time_header);
+ mRadialTimePickerHeader.setOnTouchListener(new NearestTouchDelegate());
// Set up hour/minute labels.
mHourView = (NumericTextView) mainView.findViewById(R.id.hours);
@@ -170,6 +191,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
headerTextColor = a.getColorStateList(R.styleable.TimePicker_headerTextColor);
}
+ mTextInputPickerHeader = mainView.findViewById(R.id.input_header);
+
if (headerTextColor != null) {
mHourView.setTextColor(headerTextColor);
mSeparatorView.setTextColor(headerTextColor);
@@ -180,7 +203,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
// Set up header background, if available.
if (a.hasValueOrEmpty(R.styleable.TimePicker_headerBackground)) {
- headerView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
+ mRadialTimePickerHeader.setBackground(a.getDrawable(
+ R.styleable.TimePicker_headerBackground));
+ mTextInputPickerHeader.setBackground(a.getDrawable(
+ R.styleable.TimePicker_headerBackground));
}
a.recycle();
@@ -189,6 +215,22 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes);
mRadialTimePickerView.setOnValueSelectedListener(mOnValueSelectedListener);
+ mTextInputPickerView = (TextInputTimePickerView) mainView.findViewById(R.id.input_mode);
+ mTextInputPickerView.setListener(mOnValueTypedListener);
+
+ mRadialTimePickerModeButton =
+ (ImageButton) mainView.findViewById(R.id.toggle_mode);
+ mRadialTimePickerModeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleRadialPickerMode();
+ }
+ });
+ mRadialTimePickerModeEnabledDescription = context.getResources().getString(
+ R.string.time_picker_radial_mode_description);
+ mTextInputPickerModeEnabledDescription = context.getResources().getString(
+ R.string.time_picker_text_input_mode_description);
+
mAllowAutoAdvance = true;
updateHourFormat();
@@ -200,6 +242,34 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
initialize(currentHour, currentMinute, mIs24Hour, HOUR_INDEX);
}
+ private void toggleRadialPickerMode() {
+ if (mRadialPickerModeEnabled) {
+ mRadialTimePickerView.setVisibility(View.GONE);
+ mRadialTimePickerHeader.setVisibility(View.GONE);
+ mTextInputPickerHeader.setVisibility(View.VISIBLE);
+ mTextInputPickerView.setVisibility(View.VISIBLE);
+ mRadialTimePickerModeButton.setImageResource(R.drawable.btn_event_material);
+ mRadialTimePickerModeButton.setContentDescription(
+ mRadialTimePickerModeEnabledDescription);
+ mRadialPickerModeEnabled = false;
+ } else {
+ mRadialTimePickerView.setVisibility(View.VISIBLE);
+ mRadialTimePickerHeader.setVisibility(View.VISIBLE);
+ mTextInputPickerHeader.setVisibility(View.GONE);
+ mTextInputPickerView.setVisibility(View.GONE);
+ mRadialTimePickerModeButton.setImageResource(R.drawable.btn_keyboard_key_material);
+ mRadialTimePickerModeButton.setContentDescription(
+ mTextInputPickerModeEnabledDescription);
+ updateTextInputPicker();
+ mRadialPickerModeEnabled = true;
+ }
+ }
+
+ @Override
+ public boolean validateInput() {
+ return mTextInputPickerView.validateInput();
+ }
+
/**
* Ensures that a TextView is wide enough to contain its text without
* wrapping or clipping. Measures the specified view and sets the minimum
@@ -249,9 +319,16 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
mHourView.setRange(minHour, maxHour);
mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero);
+
+ final String[] digits = DecimalFormatSymbols.getInstance(mLocale).getDigitStrings();
+ int maxCharLength = 0;
+ for (int i = 0; i < 10; i++) {
+ maxCharLength = Math.max(maxCharLength, digits[i].length());
+ }
+ mTextInputPickerView.setHourFormat(maxCharLength * 2);
}
- private static final CharSequence obtainVerbatim(String text) {
+ static final CharSequence obtainVerbatim(String text) {
return new SpannableStringBuilder().append(text,
new TtsSpan.VerbatimBuilder(text).build(), 0);
}
@@ -333,10 +410,16 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
updateHeaderSeparator();
updateHeaderMinute(mCurrentMinute, false);
updateRadialPicker(index);
+ updateTextInputPicker();
mDelegator.invalidate();
}
+ private void updateTextInputPicker() {
+ mTextInputPickerView.updateTextInputValues(getLocalizedHour(mCurrentHour), mCurrentMinute,
+ mCurrentHour < 12 ? AM : PM, mIs24Hour, mHourFormatStartsAtZero);
+ }
+
private void updateRadialPicker(int index) {
mRadialTimePickerView.initialize(mCurrentHour, mCurrentMinute, mIs24Hour);
setCurrentItemShowing(index, false, true);
@@ -381,10 +464,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
*/
@Override
public void setHour(int hour) {
- setHourInternal(hour, false, true);
+ setHourInternal(hour, FROM_EXTERNAL_API, true);
}
- private void setHourInternal(int hour, boolean isFromPicker, boolean announce) {
+ private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
if (mCurrentHour == hour) {
return;
}
@@ -393,10 +476,13 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
updateHeaderHour(hour, announce);
updateHeaderAmPm();
- if (!isFromPicker) {
+ if (source != FROM_RADIAL_PICKER) {
mRadialTimePickerView.setCurrentHour(hour);
mRadialTimePickerView.setAmOrPm(hour < 12 ? AM : PM);
}
+ if (source != FROM_INPUT_PICKER) {
+ updateTextInputPicker();
+ }
mDelegator.invalidate();
onTimeChanged();
@@ -424,10 +510,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
*/
@Override
public void setMinute(int minute) {
- setMinuteInternal(minute, false);
+ setMinuteInternal(minute, FROM_EXTERNAL_API);
}
- private void setMinuteInternal(int minute, boolean isFromPicker) {
+ private void setMinuteInternal(int minute, @ChangeSource int source) {
if (mCurrentMinute == minute) {
return;
}
@@ -435,9 +521,12 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
mCurrentMinute = minute;
updateHeaderMinute(minute, true);
- if (!isFromPicker) {
+ if (source != FROM_RADIAL_PICKER) {
mRadialTimePickerView.setCurrentMinute(minute);
}
+ if (source != FROM_INPUT_PICKER) {
+ updateTextInputPicker();
+ }
mDelegator.invalidate();
onTimeChanged();
@@ -661,6 +750,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
}
mSeparatorView.setText(separatorText);
+ mTextInputPickerView.updateSeparator(separatorText);
}
static private int lastIndexOfAny(String str, char[] any) {
@@ -712,7 +802,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
if (mRadialTimePickerView.setAmOrPm(amOrPm)) {
mCurrentHour = getHour();
-
+ updateTextInputPicker();
if (mOnTimeChangedListener != null) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
@@ -726,7 +816,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
switch (pickerType) {
case RadialTimePickerView.HOURS:
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
- setHourInternal(newValue, true, !isTransition);
+ setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
if (isTransition) {
setCurrentItemShowing(MINUTE_INDEX, true, false);
@@ -735,7 +825,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
break;
case RadialTimePickerView.MINUTES:
- setMinuteInternal(newValue, true);
+ setMinuteInternal(newValue, FROM_RADIAL_PICKER);
break;
}
@@ -745,6 +835,23 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
};
+ private final OnValueTypedListener mOnValueTypedListener = new OnValueTypedListener() {
+ @Override
+ public void onValueChanged(int pickerType, int newValue) {
+ switch (pickerType) {
+ case TextInputTimePickerView.HOURS:
+ setHourInternal(newValue, FROM_INPUT_PICKER, false);
+ break;
+ case TextInputTimePickerView.MINUTES:
+ setMinuteInternal(newValue, FROM_INPUT_PICKER);
+ break;
+ case TextInputTimePickerView.AMPM:
+ setAmOrPm(newValue);
+ break;
+ }
+ }
+ };
+
/** Listener for keyboard interaction. */
private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() {
@Override
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 6a68f60b2c7a..7ef54a5c69ca 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -219,6 +219,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
}
}
+ @Override
+ public boolean validateInput() {
+ return true;
+ }
+
private void getHourFormatData() {
final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mLocale,
(mIs24HourView) ? "Hm" : "hm");
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ab1d9b9c6f6e..40142173ece3 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -36,7 +36,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import android.app.ActivityManager;
-import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -115,6 +114,7 @@ public class ResolverActivity extends Activity {
private static final String TAG = "ResolverActivity";
private static final boolean DEBUG = false;
+ private Runnable mPostListBuildRunnable;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -419,7 +419,9 @@ public class ResolverActivity extends Activity {
protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
final ActionTitle title = mResolvingHome ? ActionTitle.HOME : ActionTitle.forAction(action);
- final boolean named = mAdapter.hasFilteredItem();
+ // While there may already be a filtered item, we can only use it in the title if the list
+ // is already sorted and all information relevant to it is already in the list.
+ final boolean named = mAdapter.getFilteredPosition() > 0;
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
return getString(defaultTitleRes);
} else {
@@ -510,6 +512,9 @@ public class ResolverActivity extends Activity {
if (!isChangingConfigurations() && mPickOptionRequest != null) {
mPickOptionRequest.cancel();
}
+ if (mPostListBuildRunnable != null) {
+ getMainThreadHandler().removeCallbacks(mPostListBuildRunnable);
+ }
}
@Override
@@ -590,6 +595,9 @@ public class ResolverActivity extends Activity {
}
TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
+ if (target == null) {
+ return;
+ }
if (onTargetSelected(target, always)) {
if (always && filtered) {
MetricsLogger.action(
@@ -880,15 +888,15 @@ public class ResolverActivity extends Activity {
}
setContentView(mLayoutId);
- if (count > 0 || !rebuildCompleted) {
- mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
- onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
- } else {
+ mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+
+ if (count == 0 && mAdapter.mPlaceholderCount == 0) {
final TextView empty = (TextView) findViewById(R.id.empty);
empty.setVisibility(View.VISIBLE);
-
- mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
mAdapterView.setVisibility(View.GONE);
+ } else {
+ mAdapterView.setVisibility(View.VISIBLE);
+ onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
}
return false;
}
@@ -917,16 +925,23 @@ public class ResolverActivity extends Activity {
}
public void setTitleAndIcon() {
- if (mTitle == null) {
- mTitle = getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
+ if (mAdapter.getCount() == 0 && mAdapter.mPlaceholderCount == 0) {
+ final TextView titleView = (TextView) findViewById(R.id.title);
+ if (titleView != null) {
+ titleView.setVisibility(View.GONE);
+ }
}
- if (!TextUtils.isEmpty(mTitle)) {
+ CharSequence title = mTitle != null
+ ? mTitle
+ : getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
+
+ if (!TextUtils.isEmpty(title)) {
final TextView titleView = (TextView) findViewById(R.id.title);
if (titleView != null) {
- titleView.setText(mTitle);
+ titleView.setText(title);
}
- setTitle(mTitle);
+ setTitle(title);
// Try to initialize the title icon if we have a view for it and a title to match
final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
@@ -963,9 +978,17 @@ public class ResolverActivity extends Activity {
}
}
- if (mAdapter.hasFilteredItem()) {
+ if (mAdapter.getFilteredPosition() >= 0) {
setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
mOnceButton.setEnabled(true);
+ return;
+ }
+
+ // When the items load in, if an item was already selected, enable the buttons
+ if (mAdapterView != null
+ && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
+ setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true);
+ mOnceButton.setEnabled(true);
}
}
@@ -1234,6 +1257,7 @@ public class ResolverActivity extends Activity {
private DisplayResolveInfo mOtherProfile;
private boolean mHasExtendedInfo;
private ResolverListController mResolverListController;
+ private int mPlaceholderCount;
protected final LayoutInflater mInflater;
@@ -1265,6 +1289,10 @@ public class ResolverActivity extends Activity {
}
}
+ public void setPlaceholderCount(int count) {
+ mPlaceholderCount = count;
+ }
+
public DisplayResolveInfo getFilteredItem() {
if (mFilterLastUsed && mLastChosenPosition >= 0) {
// Not using getItem since it offsets to dodge this position for the list
@@ -1350,6 +1378,7 @@ public class ResolverActivity extends Activity {
}
if (N > 1) {
+ setPlaceholderCount(currentResolveList.size());
AsyncTask<List<ResolvedComponentInfo>,
Void,
List<ResolvedComponentInfo>> sortingTask =
@@ -1366,13 +1395,26 @@ public class ResolverActivity extends Activity {
@Override
protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
processSortedList(sortedComponents);
- onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
if (mProfileView != null) {
bindProfileView();
}
+ notifyDataSetChanged();
}
};
sortingTask.execute(currentResolveList);
+ if (mPostListBuildRunnable == null) {
+ mPostListBuildRunnable = new Runnable() {
+ @Override
+ public void run() {
+ setTitleAndIcon();
+ resetAlwaysOrOnceButtonBar();
+ onListRebuilt();
+ disableLastChosenIfNeeded();
+ mPostListBuildRunnable = null;
+ }
+ };
+ getMainThreadHandler().post(mPostListBuildRunnable);
+ }
return false;
} else {
processSortedList(currentResolveList);
@@ -1563,21 +1605,33 @@ public class ResolverActivity extends Activity {
}
}
+ @Nullable
public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
- return (filtered ? getItem(position) : mDisplayList.get(position))
- .getResolveInfo();
+ TargetInfo target = targetInfoForPosition(position, filtered);
+ if (target != null) {
+ return target.getResolveInfo();
+ }
+ return null;
}
+ @Nullable
public TargetInfo targetInfoForPosition(int position, boolean filtered) {
- return filtered ? getItem(position) : mDisplayList.get(position);
+ if (filtered) {
+ return getItem(position);
+ }
+ if (mDisplayList.size() > position) {
+ return mDisplayList.get(position);
+ }
+ return null;
}
public int getCount() {
- int result = mDisplayList.size();
+ int totalSize = mDisplayList == null || mDisplayList.isEmpty() ? mPlaceholderCount :
+ mDisplayList.size();
if (mFilterLastUsed && mLastChosenPosition >= 0) {
- result--;
+ totalSize--;
}
- return result;
+ return totalSize;
}
public int getUnfilteredCount() {
@@ -1592,11 +1646,16 @@ public class ResolverActivity extends Activity {
return mDisplayList.get(index);
}
+ @Nullable
public TargetInfo getItem(int position) {
if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
position++;
}
- return mDisplayList.get(position);
+ if (mDisplayList.size() > position) {
+ return mDisplayList.get(position);
+ } else {
+ return null;
+ }
}
public long getItemId(int position) {
@@ -1660,6 +1719,11 @@ public class ResolverActivity extends Activity {
private void onBindView(View view, TargetInfo info) {
final ViewHolder holder = (ViewHolder) view.getTag();
+ if (info == null) {
+ holder.icon.setImageDrawable(
+ getDrawable(R.drawable.resolver_icon_placeholder));
+ return;
+ }
final CharSequence label = info.getDisplayLabel();
if (!TextUtils.equals(holder.text.getText(), label)) {
holder.text.setText(info.getDisplayLabel());
@@ -1770,6 +1834,11 @@ public class ResolverActivity extends Activity {
// Header views don't count.
return;
}
+ // If we're still loading, we can't yet enable the buttons.
+ if (mAdapter.resolveInfoForPosition(position, true) == null) {
+ return;
+ }
+
final int checkedPos = mAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 00faf65d004c..4071ff4ebd5a 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -69,14 +69,14 @@ public class ResolverListController {
}
@VisibleForTesting
- ResolveInfo getLastChosen() throws RemoteException {
+ public ResolveInfo getLastChosen() throws RemoteException {
return AppGlobals.getPackageManager().getLastChosenActivity(
mTargetIntent, mTargetIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
PackageManager.MATCH_DEFAULT_ONLY);
}
@VisibleForTesting
- void setLastChosen(Intent intent, IntentFilter filter, int match)
+ public void setLastChosen(Intent intent, IntentFilter filter, int match)
throws RemoteException {
AppGlobals.getPackageManager().setLastChosenActivity(intent,
intent.resolveType(mContext.getContentResolver()),
diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java
index b6df983d2ac8..de5f67330423 100644
--- a/core/java/com/android/internal/app/procstats/PssTable.java
+++ b/core/java/com/android/internal/app/procstats/PssTable.java
@@ -96,7 +96,7 @@ public class PssTable extends SparseMappingTable.Table {
}
val = getValue(key, PSS_USS_AVERAGE);
- setValue(key, PSS_AVERAGE,
+ setValue(key, PSS_USS_AVERAGE,
(long)(((val*(double)count)+(avgUss*(double)inCount)) / (count+inCount)));
val = getValue(key, PSS_USS_MAXIMUM);
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index a1eac363a6e8..81db93d05aab 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -69,5 +69,6 @@ interface IAppWidgetService {
boolean isBoundWidgetPackage(String packageName, int userId);
boolean requestPinAppWidget(String packageName, in ComponentName providerComponent,
in IntentSender resultIntent);
+ boolean isRequestPinAppWidgetSupported();
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index c08cd7284876..3e231d0aaa8b 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -266,43 +266,6 @@ public class InputMethodUtils {
}
}
- private static InputMethodListBuilder getMinimumKeyboardSetWithoutSystemLocale(
- final ArrayList<InputMethodInfo> imis, final Context context,
- @Nullable final Locale fallbackLocale) {
- // Before the system becomes ready, we pick up at least one keyboard in the following order.
- // The first user (device owner) falls into this category.
- // 1. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
- // 2. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
- // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
- // 4. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
-
- final InputMethodListBuilder builder = new InputMethodListBuilder();
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
- false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
- false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
- + " fallbackLocale=" + fallbackLocale);
- return builder;
- }
-
private static InputMethodListBuilder getMinimumKeyboardSetWithSystemLocale(
final ArrayList<InputMethodInfo> imis, final Context context,
@Nullable final Locale systemLocale, @Nullable final Locale fallbackLocale) {
@@ -353,21 +316,10 @@ public class InputMethodUtils {
}
public static ArrayList<InputMethodInfo> getDefaultEnabledImes(final Context context,
- final boolean isSystemReady, final ArrayList<InputMethodInfo> imis) {
+ final ArrayList<InputMethodInfo> imis) {
final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
- if (!isSystemReady) {
- // When the system is not ready, the system locale is not stable and reliable. Hence
- // we will pick up IMEs that support software keyboard based on the fallback locale.
- // Also pick up suitable IMEs regardless of the software keyboard support.
- // (e.g. Voice IMEs)
- return getMinimumKeyboardSetWithoutSystemLocale(imis, context, fallbackLocale)
- .fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_ANY)
- .build();
- }
-
- // When the system is ready, we will primarily rely on the system locale, but also keep
- // relying on the fallback locale as a last resort.
+ // We will primarily rely on the system locale, but also keep relying on the fallback locale
+ // as a last resort.
// Also pick up suitable IMEs regardless of the software keyboard support (e.g. Voice IMEs),
// then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
// subtype)
diff --git a/core/java/com/android/internal/logging/legacy/CounterParser.java b/core/java/com/android/internal/logging/legacy/CounterParser.java
deleted file mode 100644
index f318503db5e6..000000000000
--- a/core/java/com/android/internal/logging/legacy/CounterParser.java
+++ /dev/null
@@ -1,54 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-/**
- * Parse the Android counter event logs.
- * @hide
- */
-public class CounterParser extends TagParser {
- private static final String TAG = "CounterParser";
- private static final int EVENTLOG_TAG = 524290;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 2) {
- try {
- String name = ((String) operands[0]);
- int value = (Integer) operands[1];
- logCount(logger, name, value);
- } catch (ClassCastException e) {
- if (debug) {
- Log.d(TAG, "unexpected operand type", e);
- }
- }
- } else if (debug) {
- Log.d(TAG, "wrong number of operands: " + operands.length);
- }
- }
-
- protected void logCount(TronLogger logger, String name, int value) {
- logger.incrementBy(TronCounters.TRON_AOSP_PREFIX + name, value);
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/EventLogCollector.java b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
index eba7d0f5f532..598f0d51c1b9 100644
--- a/core/java/com/android/internal/logging/legacy/EventLogCollector.java
+++ b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
@@ -45,21 +45,6 @@ public class EventLogCollector {
private EventLogCollector() {
mTagParsers = new ArrayMap<>();
- addParser(new SysuiViewVisibilityParser());
- addParser(new SysuiActionParser());
- addParser(new SysuiQueryParser());
- addParser(new NotificationPanelRevealedParser());
- addParser(new NotificationPanelHiddenParser());
- addParser(new NotificationClickedParser());
- addParser(new NotificationActionClickedParser());
- addParser(new NotificationCanceledParser());
- addParser(new NotificationVisibilityParser());
- addParser(new NotificationAlertParser());
- addParser(new NotificationExpansionParser());
- addParser(new CounterParser());
- addParser(new HistogramParser());
- addParser(new LockscreenGestureParser());
- addParser(new StatusBarStateParser());
addParser(new PowerScreenStateParser());
addParser(new SysuiMultiActionParser());
diff --git a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
index 91e968b5b250..1209e4d8dc8c 100644
--- a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
+++ b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
@@ -24,14 +24,6 @@ import java.util.Queue;
/** @hide */
public class LegacyConversionLogger implements TronLogger {
- public static final String VIEW_KEY = "view";
- public static final String TYPE_KEY = "type";
- public static final String EVENT_KEY = "data";
-
- public static final int TYPE_COUNTER = 1;
- public static final int TYPE_HISTOGRAM = 2;
- public static final int TYPE_EVENT = 3;
-
private final Queue<LogMaker> mQueue;
private HashMap<String, Boolean> mConfig;
diff --git a/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java b/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
deleted file mode 100644
index df08ee067087..000000000000
--- a/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
+++ /dev/null
@@ -1,80 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android lockscreen gesture logs.
- * @hide
- */
-public class LockscreenGestureParser extends TagParser {
- private static final String TAG = "LockscreenGestureParser";
- private static final int EVENTLOG_TAG = 36021;
-
- // source of truth is com.android.systemui.EventLogConstants
- public static final int[] GESTURE_TYPE_MAP = {
- MetricsEvent.VIEW_UNKNOWN, // there is no type 0
- MetricsEvent.ACTION_LS_UNLOCK, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1
- MetricsEvent.ACTION_LS_SHADE, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2
- MetricsEvent.ACTION_LS_HINT, // SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3
- MetricsEvent.ACTION_LS_CAMERA, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4
- MetricsEvent.ACTION_LS_DIALER, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5
- MetricsEvent.ACTION_LS_LOCK, // SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6
- MetricsEvent.ACTION_LS_NOTE, // SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7
- MetricsEvent.ACTION_LS_QS, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8
- MetricsEvent.ACTION_SHADE_QS_PULL, // SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9
- MetricsEvent.ACTION_SHADE_QS_TAP // SYSUI_TAP_TO_OPEN_QS = 10
- };
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 1) {
- try {
- int type = ((Integer) operands[0]).intValue();
- // ignore gesture length in operands[1]
- // ignore gesture velocity in operands[2]
-
- int category = MetricsEvent.VIEW_UNKNOWN;
- if (type < GESTURE_TYPE_MAP.length) {
- category = GESTURE_TYPE_MAP[type];
- }
- if (category != MetricsEvent.VIEW_UNKNOWN) {
- LogMaker proto = logger.obtain();
- proto.setCategory(category);
- proto.setType(MetricsEvent.TYPE_ACTION);
- proto.setTimestamp(eventTimeMs);
- logger.addEvent(proto);
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java
deleted file mode 100644
index 79f3eb88805d..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java
+++ /dev/null
@@ -1,72 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification action button interaction event logs.
- * @hide
- */
-public class NotificationActionClickedParser extends TagParser {
- private static final String TAG = "NotificationAction";
- private static final int EVENTLOG_TAG = 27521;
-
- private final NotificationKey mKey;
-
- public NotificationActionClickedParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 1) {
- try {
- if (mKey.parse((String) operands[0])) {
- int index = (Integer) operands[1];
- parseTimes(operands, 2);
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION);
- proto.setType(MetricsEvent.TYPE_ACTION);
- proto.setSubtype(index);
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- filltimes(proto);
- logger.addEvent(proto);
- } else if (debug) {
- Log.e(TAG, "unable to parse key.");
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java b/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
deleted file mode 100644
index 9548fb0be452..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
+++ /dev/null
@@ -1,86 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the new Android notification alert event logs.
- * @hide
- */
-public class NotificationAlertParser extends TagParser {
- private static final String TAG = "NotificationAlertParser";
- private static final int EVENTLOG_TAG = 27532;
-
- @VisibleForTesting
- static final int BUZZ = 0x00000001;
- @VisibleForTesting
- static final int BEEP = 0x00000002;
- @VisibleForTesting
- static final int BLINK = 0x00000004;
-
- private final NotificationKey mKey;
-
- public NotificationAlertParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 3) {
- try {
- final String keyString = (String) operands[0];
- final boolean buzz = ((Integer) operands[1]) == 1;
- final boolean beep = ((Integer) operands[2]) == 1;
- final boolean blink = ((Integer) operands[3]) == 1;
-
- if (mKey.parse(keyString)) {
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ALERT);
- proto.setType(MetricsEvent.TYPE_OPEN);
- proto.setSubtype((buzz ? BUZZ : 0) | (beep ? BEEP : 0) | (blink ? BLINK : 0));
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- filltimes(proto);
- logger.addEvent(proto);
- } else {
- if (debug) {
- Log.e(TAG, "unable to parse key: " + keyString);
- }
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- return;
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java b/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
deleted file mode 100644
index 80eb004277f5..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
+++ /dev/null
@@ -1,102 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification cancellation event logs.
- * @hide
- */
-public class NotificationCanceledParser extends TagParser {
- private static final String TAG = "NotificationCanceled";
- private static final int EVENTLOG_TAG = 27530;
-
- // from com.android.server.notification.NotificationManagerService
- static final int REASON_DELEGATE_CLICK = 1;
- static final int REASON_DELEGATE_CANCEL = 2;
- static final int REASON_DELEGATE_CANCEL_ALL = 3;
- static final int REASON_PACKAGE_BANNED = 7;
- static final int REASON_LISTENER_CANCEL = 10;
- static final int REASON_LISTENER_CANCEL_ALL = 11;
-
- private final NotificationKey mKey;
-
- public NotificationCanceledParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 1) {
- try {
- final String keyString = (String) operands[0];
- final int reason = (Integer) operands[1];
- parseTimes(operands, 2);
-
- // handle old style log
- // TODO: delete once M is launched
- if (operands.length < 5) {
- mSinceVisibleMillis = mSinceUpdateMillis;
- mSinceUpdateMillis = 0;
- }
-
- boolean intentional = true;
- switch (reason) {
- case REASON_DELEGATE_CANCEL:
- case REASON_DELEGATE_CANCEL_ALL:
- case REASON_LISTENER_CANCEL:
- case REASON_LISTENER_CANCEL_ALL:
- case REASON_DELEGATE_CLICK:
- case REASON_PACKAGE_BANNED:
- break;
- default:
- intentional = false;
- }
-
- if (mKey.parse(keyString)) {
- if (intentional) {
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
- proto.setType(MetricsEvent.TYPE_DISMISS);
- proto.setSubtype(reason);
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- filltimes(proto);
- logger.addEvent(proto);
- }
- } else if (debug) {
- Log.e(TAG, "unable to parse key: " + keyString);
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
deleted file mode 100644
index eee4701cc743..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
+++ /dev/null
@@ -1,70 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification interaction event logs.
- * @hide
- */
-public class NotificationClickedParser extends TagParser {
- private static final String TAG = "NotificationClicked";
- private static final int EVENTLOG_TAG = 27520;
-
- private final NotificationKey mKey;
-
- public NotificationClickedParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 0) {
- try {
- if (mKey.parse((String) operands[0])) {
- parseTimes(operands, 1);
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
- proto.setType(MetricsEvent.TYPE_ACTION);
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- filltimes(proto);
- logger.addEvent(proto);
- } else if (debug) {
- Log.e(TAG, "unable to parse key.");
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java b/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java
deleted file mode 100644
index 84cd9993e2e3..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java
+++ /dev/null
@@ -1,76 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification expansion event logs.
- * @hide
- */
-public class NotificationExpansionParser extends TagParser {
- private static final String TAG = "NotificationExpansion";
- private static final int EVENTLOG_TAG = 27511;
-
- private final NotificationKey mKey;
-
- public NotificationExpansionParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 2) {
- try {
- if (mKey.parse((String) operands[0])) {
- boolean byUser = ((Integer) operands[1]) == 1;
- boolean expanded = ((Integer) operands[2]) == 1;
- parseTimes(operands, 3);
-
- if (!byUser || !expanded) {
- return;
- }
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
- proto.setType(MetricsEvent.TYPE_DETAIL);
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- filltimes(proto);
- logger.addEvent(proto);
- } else if (debug) {
- Log.e(TAG, "unable to parse key.");
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationKey.java b/core/java/com/android/internal/logging/legacy/NotificationKey.java
deleted file mode 100644
index f8cac346fcec..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationKey.java
+++ /dev/null
@@ -1,60 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-/**
- * Parse Android notification keys
- * @hide
- */
-public class NotificationKey {
-
- private static final String TAG = "NotificationKey";
-
- public int mUser;
- public String mPackageName;
- public int mId;
- public String mTag;
- public int mUid;
-
- public boolean parse(String key) {
- if (key == null) {
- return false;
- }
- boolean debug = Util.debug();
- String[] parts = key.split("\\|");
- if (parts.length == 5) {
- try {
- mUser = Integer.valueOf(parts[0]);
- mPackageName = parts[1];
- mId = Integer.valueOf(parts[2]);
- mTag = parts[3].equals("null") ? "" : parts[3];
- mUid = Integer.valueOf(parts[4]);
- return true;
- } catch (NumberFormatException e) {
- if (debug) {
- Log.w(TAG, "could not parse notification key.", e);
- }
- return false;
- }
- }
- if (debug) {
- Log.w(TAG, "wrong number of parts in notification key: " + key);
- }
- return false;
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
deleted file mode 100644
index a064a2ebca46..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
+++ /dev/null
@@ -1,42 +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.internal.logging.legacy;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification panel visibility event logs.
- * @hide
- */
-public class NotificationPanelHiddenParser extends TagParser {
- private static final String TAG = "NotificationPanelHidden";
- private static final int EVENTLOG_TAG = 27501;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
- proto.setType(MetricsEvent.TYPE_CLOSE);
- proto.setTimestamp(eventTimeMs);
- logger.addEvent(proto);
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
deleted file mode 100644
index 4d19564e21e3..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
+++ /dev/null
@@ -1,56 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android notification panel visibility event logs.
- * @hide
- */
-public class NotificationPanelRevealedParser extends TagParser {
- private static final String TAG = "NotificationPanelRevea";
- private static final int EVENTLOG_TAG = 27500;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 1) {
- try {
- int load = ((Integer) operands[0]).intValue();
- //logger.incrementBy(TronCounters.TRON_NOTIFICATION_LOAD, load);
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- }
-
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
- proto.setType(MetricsEvent.TYPE_OPEN);
- proto.setTimestamp(eventTimeMs);
- logger.addEvent(proto);
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java b/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
deleted file mode 100644
index 2d2cd909e2a7..000000000000
--- a/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
+++ /dev/null
@@ -1,81 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the new Android notification visibility event logs.
- * @hide
- */
-public class NotificationVisibilityParser extends TagParser {
- private static final String TAG = "NotificationVisibility";
- private static final int EVENTLOG_TAG = 27531;
-
- private final NotificationKey mKey;
-
- public NotificationVisibilityParser() {
- mKey = new NotificationKey();
- }
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length > 1) {
- try {
- final String keyString = (String) operands[0];
- final boolean visible = ((Integer) operands[1]) == 1;
- parseTimes(operands, 2);
- int index = 0;
- if (operands.length > 5 && operands[5] instanceof Integer) {
- index = (Integer) operands[5];
- }
-
- if (mKey.parse(keyString)) {
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
- proto.setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
- proto.setTimestamp(eventTimeMs);
- proto.setPackageName(mKey.mPackageName);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
- proto.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, index);
- filltimes(proto);
- logger.addEvent(proto);
- } else {
- if (debug) {
- Log.e(TAG, "unable to parse key: " + keyString);
- }
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- return;
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java b/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java
deleted file mode 100644
index 226253f3322f..000000000000
--- a/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java
+++ /dev/null
@@ -1,74 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android lockscreen gesture logs.
- * @hide
- */
-public class StatusBarStateParser extends TagParser {
- private static final String TAG = "StatusBarStateParser";
- private static final int EVENTLOG_TAG = 36004;
-
- // source of truth is com.android.systemui.statusbar.StatusBarState
- public static final int SHADE = 0;
- public static final int KEYGUARD = 1;
- public static final int SHADE_LOCKED = 2;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 6) {
- try {
- // [state, isShowing, isOccluded, isBouncerShowing, isSecure, isCurrentlyInsecure]
- int state = ((Integer) operands[0]).intValue();
- boolean isBouncerShowing = (((Integer) operands[3]).intValue()) == 1;
- int isSecure = ((Integer) operands[4]).intValue();
-
- int view = MetricsEvent.LOCKSCREEN;
- int type = MetricsEvent.TYPE_OPEN;
- if (state == SHADE) {
- type = MetricsEvent.TYPE_CLOSE;
- } else if (isBouncerShowing) {
- view = MetricsEvent.BOUNCER;
- }
-
- LogMaker proto = logger.obtain();
- proto.setCategory(view);
- proto.setType(type);
- proto.setTimestamp(eventTimeMs);
- proto.setSubtype(isSecure);
- logger.addEvent(proto);
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
deleted file mode 100644
index 1148ee5865bb..000000000000
--- a/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
+++ /dev/null
@@ -1,81 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android framework sysui action logs.
- * @hide
- */
-public class SysuiActionParser extends TagParser {
- private static final String TAG = "SysuiActionParser";
- private static final int EVENTLOG_TAG = 524288;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- try {
- String packageName = null;
- int subType = -1;
- boolean hasSubType = false;
- if (operands.length > 1) {
- String arg = (String) operands[1];
- if (arg.equals("true")) {
- hasSubType = true;
- subType = 1;
- } else if (arg.equals("false")) {
- hasSubType = true;
- subType = 0;
- } else if (arg.matches("^-?\\d+$")) {
- try {
- subType = Integer.valueOf(arg);
- hasSubType = true;
- } catch (NumberFormatException e) {
- }
- } else {
- packageName = arg;
- }
- }
- if (operands.length > 0) {
- int category = ((Integer) operands[0]).intValue();
- LogMaker proto = logger.obtain();
- proto.setCategory(category);
- proto.setType(MetricsEvent.TYPE_ACTION);
- proto.setTimestamp(eventTimeMs);
- if (packageName != null) {
- proto.setPackageName(packageName);
- }
- if (hasSubType) {
- proto.setSubtype(subType);
- }
- logger.addEvent(proto);
- }
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java b/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
deleted file mode 100644
index 1223b8d216bf..000000000000
--- a/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
+++ /dev/null
@@ -1,58 +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.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android framework sysui view visibility logs.
- * @hide
- */
-public class SysuiViewVisibilityParser extends TagParser {
- private static final String TAG = "SysuiViewVisibility";
- private static final int EVENTLOG_TAG = 524287;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 2) {
- try {
- int category = ((Integer) operands[0]).intValue();
- boolean visibility = ((Integer) operands[1]).intValue() != 0;
-
- LogMaker proto = logger.obtain();
- proto.setCategory(category);
- proto.setType(visibility ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
- proto.setTimestamp(eventTimeMs);
- logger.addEvent(proto);
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5fd68e6ff1e6..9dca5ea6eaa6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -377,6 +377,8 @@ public class BatteryStatsImpl extends BatteryStats {
int mScreenBrightnessBin = -1;
final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
+ boolean mPretendScreenOff;
+
boolean mInteractive;
StopwatchTimer mInteractiveTimer;
@@ -3395,6 +3397,11 @@ public class BatteryStatsImpl extends BatteryStats {
mNoAutoReset = enabled;
}
+ public void setPretendScreenOff(boolean pretendScreenOff) {
+ mPretendScreenOff = pretendScreenOff;
+ noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON);
+ }
+
private String mInitialAcquireWakeName;
private int mInitialAcquireWakeUid = -1;
@@ -3698,6 +3705,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void noteScreenStateLocked(int state) {
+ state = mPretendScreenOff ? Display.STATE_OFF : state;
if (mScreenState != state) {
recordDailyStatsIfNeededLocked(true);
final int oldState = mScreenState;
@@ -9554,7 +9562,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
});
- if (DEBUG_ENERGY_CPU) {
+ // TODO: STOPSHIP, remove the "true" below after b/34961340 is fixed
+ if (DEBUG_ENERGY_CPU || true) {
Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
" ms");
}
@@ -9711,9 +9720,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
doWrite = true;
resetAllStatsLocked();
- if (chargeUAh > 0) {
+ if (chargeUAh > 0 && level > 0) {
// Only use the reported coulomb charge value if it is supported and reported.
- mEstimatedBatteryCapacity = (int) ((level / 100.0) * (chargeUAh / 1000));
+ mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0));
}
mDischargeStartLevel = level;
reset = true;
@@ -10382,10 +10391,9 @@ public class BatteryStatsImpl extends BatteryStats {
if (next == null) {
return;
}
-
- mWriteLock.lock();
}
+ mWriteLock.lock();
try {
FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
stream.write(next.marshall());
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e1e0a21eb7f5..59416dd06cdc 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -33,7 +33,7 @@ public final class Zygote {
*/
/** enable debugging over JDWP */
- public static final int DEBUG_ENABLE_DEBUGGER = 1;
+ public static final int DEBUG_ENABLE_JDWP = 1;
/** enable JNI checks */
public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1;
/** enable Java programming language "assert" statements */
@@ -46,8 +46,10 @@ public final class Zygote {
public static final int DEBUG_GENERATE_DEBUG_INFO = 1 << 5;
/** Always use JIT-ed code. */
public static final int DEBUG_ALWAYS_JIT = 1 << 6;
- /** Make the code debuggable with turning off some optimizations. */
+ /** Make the code native debuggable by turning off some optimizations. */
public static final int DEBUG_NATIVE_DEBUGGABLE = 1 << 7;
+ /** Make the code Java debuggable by turning off some optimizations. */
+ public static final int DEBUG_JAVA_DEBUGGABLE = 1 << 8;
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = 0;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 83e3cff360f4..8fe374c9266f 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -342,8 +342,9 @@ class ZygoteConnection {
int[] gids;
/**
- * From --enable-debugger, --enable-checkjni, --enable-assert,
- * --enable-safemode, --generate-debug-info and --enable-jni-logging.
+ * From --enable-jdwp, --enable-checkjni, --enable-assert,
+ * --enable-safemode, --generate-debug-info, --enable-jni-logging,
+ * --java-debuggable, and --native-debuggable.
*/
int debugFlags;
@@ -453,8 +454,8 @@ class ZygoteConnection {
targetSdkVersionSpecified = true;
targetSdkVersion = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
- } else if (arg.equals("--enable-debugger")) {
- debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ } else if (arg.equals("--enable-jdwp")) {
+ debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
} else if (arg.equals("--enable-safemode")) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
} else if (arg.equals("--enable-checkjni")) {
@@ -465,6 +466,8 @@ class ZygoteConnection {
debugFlags |= Zygote.DEBUG_ALWAYS_JIT;
} else if (arg.equals("--native-debuggable")) {
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;
+ } else if (arg.equals("--java-debuggable")) {
+ debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
} else if (arg.equals("--enable-jni-logging")) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
} else if (arg.equals("--enable-assert")) {
@@ -676,14 +679,14 @@ class ZygoteConnection {
* Applies debugger system properties to the zygote arguments.
*
* If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
- * the debugger state is specified via the "--enable-debugger" flag
+ * the debugger state is specified via the "--enable-jdwp" flag
* in the spawn request.
*
* @param args non-null; zygote spawner args
*/
public static void applyDebuggerSystemProperty(Arguments args) {
if (RoSystemProperties.DEBUGGABLE) {
- args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ args.debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
@@ -705,7 +708,7 @@ class ZygoteConnection {
int peerUid = peer.getUid();
if (args.invokeWith != null && peerUid != 0 &&
- (args.debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) == 0) {
+ (args.debugFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an"
+ "explicit invoke-with wrapper command only for debuggable"
+ "applications.");
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index a3b066a45c54..5049738f076a 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -28,6 +28,7 @@ import android.net.LocalServerSocket;
import android.os.IInstalld;
import android.os.Process;
import android.os.RemoteException;
+import android.os.Seccomp;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
@@ -712,6 +713,9 @@ public class ZygoteInit {
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
+ // Set seccomp policy
+ Seccomp.setPolicy();
+
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 789e9d4b0353..7ff115bee1d2 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2243,6 +2243,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
@Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ super.dispatchPointerCaptureChanged(hasCapture);
+ if (!mWindow.isDestroyed() && mWindow.getCallback() != null) {
+ mWindow.getCallback().onPointerCaptureChanged(hasCapture);
+ }
+ }
+
+ @Override
public String toString() {
return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
+ getTitleSuffix(mWindow.getAttributes()) + "]";
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index cf14471f381a..11e71026bf09 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -53,6 +53,11 @@ public class DividerSnapAlgorithm {
*/
private static final int SNAP_ONLY_1_1 = 2;
+ /**
+ * 1 snap target: minimized height, (1 - minimized height)
+ */
+ private static final int SNAP_MODE_MINIMIZED = 3;
+
private final float mMinFlingVelocityPxPerSecond;
private final float mMinDismissVelocityPxPerSecond;
private final int mDisplayWidth;
@@ -62,6 +67,7 @@ public class DividerSnapAlgorithm {
private final Rect mInsets = new Rect();
private final int mSnapMode;
private final int mMinimalSizeResizableTask;
+ private final int mTaskHeightInMinimizedMode;
private final float mFixedRatio;
private boolean mIsHorizontalDivision;
@@ -93,6 +99,11 @@ public class DividerSnapAlgorithm {
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
boolean isHorizontalDivision, Rect insets) {
+ this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
+ }
+
+ public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
+ boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
mMinFlingVelocityPxPerSecond =
MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
mMinDismissVelocityPxPerSecond =
@@ -102,12 +113,14 @@ public class DividerSnapAlgorithm {
mDisplayHeight = displayHeight;
mIsHorizontalDivision = isHorizontalDivision;
mInsets.set(insets);
- mSnapMode = res.getInteger(
- com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+ mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
+ res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
mFixedRatio = res.getFraction(
com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
mMinimalSizeResizableTask = res.getDimensionPixelSize(
com.android.internal.R.dimen.default_minimal_size_resizable_task);
+ mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.task_height_of_minimized_mode);
calculateTargets(isHorizontalDivision);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
@@ -246,6 +259,7 @@ public class DividerSnapAlgorithm {
int dividerMax = isHorizontalDivision
? mDisplayHeight
: mDisplayWidth;
+ int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
mTargets.add(new SnapTarget(-mDividerSize, -mDividerSize, SnapTarget.FLAG_DISMISS_START,
0.35f));
switch (mSnapMode) {
@@ -258,8 +272,10 @@ public class DividerSnapAlgorithm {
case SNAP_ONLY_1_1:
addMiddleTarget(isHorizontalDivision);
break;
+ case SNAP_MODE_MINIMIZED:
+ addMinimizedTarget(isHorizontalDivision);
+ break;
}
- int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
SnapTarget.FLAG_DISMISS_END, 0.35f));
}
@@ -315,6 +331,12 @@ public class DividerSnapAlgorithm {
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
+ private void addMinimizedTarget(boolean isHorizontalDivision) {
+ int position = mTaskHeightInMinimizedMode;
+ position += isHorizontalDivision ? mInsets.top : mInsets.left;
+ mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
+ }
+
public SnapTarget getMiddleTarget() {
return mMiddleTarget;
}
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index fb0edea398ce..ebc2c716493a 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -84,7 +84,8 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
return true;
}
@@ -215,7 +216,8 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (!event.isCanceled()) {
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
}
return true;
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index e68ebc4342fd..84195b2a270a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1856,27 +1856,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- int direction = 0;
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- direction = AudioManager.ADJUST_TOGGLE_MUTE;
- break;
- }
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
+ int direction = 0;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ direction = AudioManager.ADJUST_RAISE;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ direction = AudioManager.ADJUST_LOWER;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ direction = AudioManager.ADJUST_TOGGLE_MUTE;
+ break;
+ }
mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
} else {
- MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
- mVolumeControlStreamType, direction,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
- | AudioManager.FLAG_FROM_KEY);
+ MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
+ event, mVolumeControlStreamType, false);
}
return true;
}
@@ -1954,15 +1952,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN: {
- final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
- | AudioManager.FLAG_FROM_KEY;
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
+ final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
+ | AudioManager.FLAG_FROM_KEY;
mMediaController.adjustVolume(0, flags);
} else {
- MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
- mVolumeControlStreamType, 0, flags);
+ MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
+ event, mVolumeControlStreamType, false);
}
return true;
}
@@ -1971,7 +1969,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
+ MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
return true;
}
// These are all the recognized media key codes in
diff --git a/core/java/com/android/internal/policy/PipMotionHelper.java b/core/java/com/android/internal/policy/PipMotionHelper.java
deleted file mode 100644
index 944cd323b295..000000000000
--- a/core/java/com/android/internal/policy/PipMotionHelper.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * A helper to animate the PIP.
- */
-public class PipMotionHelper {
-
- private static final String TAG = "PipMotionHelper";
-
- private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
- private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
- private static final int DEFAULT_DURATION = 225;
-
- private IActivityManager mActivityManager;
- private Handler mHandler;
-
- public PipMotionHelper(Handler handler) {
- mHandler = handler;
- }
-
- /**
- * Moves the PIP to give given {@param bounds}.
- */
- public void resizeToBounds(Rect toBounds) {
- mHandler.post(() -> {
- if (mActivityManager == null) {
- mActivityManager = ActivityManager.getService();
- }
- try {
- mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e);
- }
- });
- }
-
- /**
- * Creates an animation to move the PIP to give given {@param toBounds} with the default
- * animation properties.
- */
- public ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds) {
- return createAnimationToBounds(fromBounds, toBounds, DEFAULT_DURATION, FAST_OUT_SLOW_IN,
- null);
- }
-
- /**
- * Creates an animation to move the PIP to give given {@param toBounds}.
- */
- public ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
- Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
- ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
- anim.setDuration(duration);
- anim.setInterpolator(interpolator);
- anim.addUpdateListener((ValueAnimator animation) -> {
- resizeToBounds((Rect) animation.getAnimatedValue());
- });
- if (updateListener != null) {
- anim.addUpdateListener(updateListener);
- }
- return anim;
- }
-
-
-}
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 6d1374358321..bf047c1538dc 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -39,20 +39,27 @@ public class PipSnapAlgorithm {
private static final int SNAP_MODE_CORNERS_AND_SIDES = 1;
// Allows snapping to anywhere along the edge of the screen
private static final int SNAP_MODE_EDGE = 2;
+ // Allows snapping to four corners on a fling towards a corner or slow move near a corner
+ // snaps anywhere along the edge of screen otherwise
+ private static final int SNAP_MODE_CORNERS_AND_EDGES = 3;
// The friction multiplier to control how slippery the PIP is when flung
private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
+ // Threshold to magnet to a corner
+ private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
+
private final Context mContext;
private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
- private final int mDefaultSnapMode = SNAP_MODE_CORNERS_ONLY;
+ private final int mDefaultSnapMode = SNAP_MODE_CORNERS_AND_EDGES;
private int mSnapMode = mDefaultSnapMode;
private Scroller mScroller;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
private final int mMinimizedVisibleSize;
+ private boolean mIsMinimized;
public PipSnapAlgorithm(Context context) {
mContext = context;
@@ -70,10 +77,10 @@ public class PipSnapAlgorithm {
}
/**
- * Enables snapping to the closest edge.
+ * Sets the PIP's minimized state.
*/
- public void setSnapToEdge(boolean snapToEdge) {
- mSnapMode = snapToEdge ? SNAP_MODE_EDGE : mDefaultSnapMode;
+ public void setMinimized(boolean isMinimized) {
+ mIsMinimized = isMinimized;
}
/**
@@ -107,7 +114,24 @@ public class PipSnapAlgorithm {
movementBounds.right + stackBounds.width(),
movementBounds.bottom + stackBounds.height());
final Rect newBounds = new Rect(stackBounds);
- if (mSnapMode == SNAP_MODE_EDGE) {
+ if (mSnapMode == SNAP_MODE_CORNERS_AND_EDGES) {
+ final Rect tmpBounds = new Rect();
+ final Point[] snapTargets = new Point[mSnapGravities.size()];
+ for (int i = 0; i < mSnapGravities.size(); i++) {
+ Gravity.apply(mSnapGravities.get(i), stackBounds.width(), stackBounds.height(),
+ pipBounds, 0, 0, tmpBounds);
+ snapTargets[i] = new Point(tmpBounds.left, tmpBounds.top);
+ }
+ Point snapTarget = findClosestPoint(stackBounds.left, stackBounds.top, snapTargets);
+ float distance = distanceToPoint(snapTarget, stackBounds.left, stackBounds.top);
+ final float thresh = stackBounds.width() * CORNER_MAGNET_THRESHOLD;
+ if (distance < thresh) {
+ newBounds.offsetTo(snapTarget.x, snapTarget.y);
+ } else {
+ // Otherwise we snap to the edge
+ snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
+ }
+ } else if (mSnapMode == SNAP_MODE_EDGE) {
// Find the closest edge to the given stack bounds and snap to it
snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
} else {
@@ -202,6 +226,21 @@ public class PipSnapAlgorithm {
}
/**
+ * Adjusts {@param movementBoundsOut} so that it is the movement bounds for the given
+ * {@param stackBounds}.
+ */
+ public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut,
+ int imeHeight) {
+ // Adjust the right/bottom to ensure the stack bounds never goes offscreen
+ movementBoundsOut.set(insetBounds);
+ movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right -
+ stackBounds.width());
+ movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom -
+ stackBounds.height());
+ movementBoundsOut.bottom -= imeHeight;
+ }
+
+ /**
* @return the closest point in {@param points} to the given {@param x} and {@param y}.
*/
private Point findClosestPoint(int x, int y, Point[] points) {
@@ -228,8 +267,7 @@ public class PipSnapAlgorithm {
final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
stackBounds.top));
boundsOut.set(stackBounds);
- if (stackBounds.left < movementBounds.left ||
- stackBounds.left > movementBounds.right) {
+ if (mIsMinimized) {
boundsOut.offsetTo(boundedLeft, boundsOut.top);
return;
}
@@ -273,6 +311,7 @@ public class PipSnapAlgorithm {
}
// Fall through
case SNAP_MODE_CORNERS_ONLY:
+ case SNAP_MODE_CORNERS_AND_EDGES:
mSnapGravities.add(Gravity.TOP | Gravity.LEFT);
mSnapGravities.add(Gravity.TOP | Gravity.RIGHT);
mSnapGravities.add(Gravity.BOTTOM | Gravity.LEFT);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 20f10b33343b..9cbbc5a48c0d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -53,9 +53,6 @@ oneway interface IStatusBar
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void setWindowState(int window, int state);
- void buzzBeepBlinked();
- void notificationLightOff();
- void notificationLightPulse(int argb, int millisOn, int millisOff);
void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index a9a6364eb3fe..cb3a250a377d 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -435,10 +435,6 @@ public class ArrayUtils {
}
}
- public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
- return (cur != null) ? cur.contains(val) : false;
- }
-
public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
cur = new ArrayList<>();
@@ -459,6 +455,16 @@ public class ArrayUtils {
}
}
+ /**
+ * Returns the given list, or an immutable empty list if the provided list is null
+ *
+ * @see Collections#emptyList
+ */
+
+ public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
+ return cur == null ? Collections.emptyList() : cur;
+ }
+
public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
return (cur != null) ? cur.contains(val) : false;
}
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
index 184245ef538d..e733c30ae84a 100644
--- a/core/java/com/android/internal/util/MessageUtils.java
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -42,10 +42,11 @@ public class MessageUtils {
/**
* Finds the names of integer constants. Searches the specified {@code classes}, looking for
- * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+ * accessible static integer fields whose names begin with one of the specified
+ * {@code prefixes}.
*
* @param classes the classes to examine.
- * @prefixes only consider fields names starting with one of these prefixes.
+ * @param prefixes only consider fields names starting with one of these prefixes.
* @return a {@link SparseArray} mapping integer constants to their names.
*/
public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
@@ -122,7 +123,6 @@ public class MessageUtils {
* accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
*
* @param classNames the classes to examine.
- * @prefixes only consider fields names starting with one of these prefixes.
* @return a {@link SparseArray} mapping integer constants to their names.
*/
public static SparseArray<String> findMessageNames(Class[] classNames) {
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 087383df405d..0fe580a23983 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -33,6 +33,8 @@ import android.graphics.drawable.Icon;
import android.graphics.drawable.VectorDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.Pair;
@@ -184,8 +186,24 @@ public class NotificationColorUtil {
SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
for (Object span : spans) {
Object resultSpan = span;
- if (span instanceof TextAppearanceSpan) {
- resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
+ if (resultSpan instanceof CharacterStyle) {
+ resultSpan = ((CharacterStyle) span).getUnderlying();
+ }
+ if (resultSpan instanceof TextAppearanceSpan) {
+ TextAppearanceSpan processedSpan = processTextAppearanceSpan(
+ (TextAppearanceSpan) span);
+ if (processedSpan != resultSpan) {
+ resultSpan = processedSpan;
+ } else {
+ // we need to still take the orgininal for wrapped spans
+ resultSpan = span;
+ }
+ } else if (resultSpan instanceof ForegroundColorSpan) {
+ ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
+ int foregroundColor = originalSpan.getForegroundColor();
+ resultSpan = new ForegroundColorSpan(processColor(foregroundColor));
+ } else {
+ resultSpan = span;
}
builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
ss.getSpanFlags(span));
@@ -416,6 +434,48 @@ public class NotificationColorUtil {
return color;
}
+ public static int resolvePrimaryColor(Context context, int backgroundColor) {
+ boolean useDark = shouldUseDark(backgroundColor);
+ if (useDark) {
+ return context.getColor(
+ com.android.internal.R.color.notification_primary_text_color_light);
+ } else {
+ return context.getColor(
+ com.android.internal.R.color.notification_primary_text_color_dark);
+ }
+ }
+
+ public static int resolveSecondaryColor(Context context, int backgroundColor) {
+ boolean useDark = shouldUseDark(backgroundColor);
+ if (useDark) {
+ return context.getColor(
+ com.android.internal.R.color.notification_secondary_text_color_light);
+ } else {
+ return context.getColor(
+ com.android.internal.R.color.notification_secondary_text_color_dark);
+ }
+ }
+
+ public static int resolveActionBarColor(int backgroundColor) {
+ boolean useDark = shouldUseDark(backgroundColor);
+ final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
+ ColorUtilsFromCompat.colorToLAB(backgroundColor, result);
+ if (useDark && result[0] < 97 || !useDark && result[0] < 4) {
+ result[0] = Math.min(100, result[0] + 7);
+ } else {
+ result[0] = Math.max(0, result[0] - 7);
+ }
+ return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
+ }
+
+ private static boolean shouldUseDark(int backgroundColor) {
+ boolean useDark = backgroundColor == Notification.COLOR_DEFAULT;
+ if (!useDark) {
+ useDark = ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.5;
+ }
+ return useDark;
+ }
+
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
new file mode 100644
index 000000000000..518cf41ee37a
--- /dev/null
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.util;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+import java.util.Objects;
+
+/**
+ * A util to look up messaging related functions for notifications. This is used for both the
+ * ranking and the actual layout.
+ */
+public class NotificationMessagingUtil {
+
+ private static final String DEFAULT_SMS_APP_SETTING = Settings.Secure.SMS_DEFAULT_APPLICATION;
+ private final Context mContext;
+ private ArrayMap<Integer, String> mDefaultSmsApp = new ArrayMap<>();
+
+ public NotificationMessagingUtil(Context context) {
+ mContext = context;
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver);
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isDefaultMessagingApp(StatusBarNotification sbn) {
+ final int userId = sbn.getUserId();
+ if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
+ if (mDefaultSmsApp.get(userId) == null) {
+ cacheDefaultSmsApp(userId);
+ }
+ return Objects.equals(mDefaultSmsApp.get(userId), sbn.getPackageName());
+ }
+
+ private void cacheDefaultSmsApp(int userId) {
+ mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.SMS_DEFAULT_APPLICATION, userId));
+ }
+
+ private final ContentObserver mSmsContentObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
+ cacheDefaultSmsApp(userId);
+ }
+ }
+ };
+
+ public boolean isImportantMessaging(StatusBarNotification sbn, int importance) {
+ if (importance < NotificationManager.IMPORTANCE_LOW) {
+ return false;
+ }
+
+ Class<? extends Notification.Style> style = sbn.getNotification().getNotificationStyle();
+ if (Notification.MessagingStyle.class.equals(style)) {
+ return true;
+ }
+
+ if (Notification.CATEGORY_MESSAGE.equals(sbn.getNotification().category)
+ && isDefaultMessagingApp(sbn)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
new file mode 100644
index 000000000000..d109a5a1cae5
--- /dev/null
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/** @hide */
+public class ObjectUtils {
+ private ObjectUtils() {}
+
+ @NonNull
+ public static <T> T firstNotNull(@Nullable T a, @NonNull T b) {
+ return a != null ? a : Preconditions.checkNotNull(b);
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index c9c8292fafc3..dd91d2f2cfaf 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -122,4 +122,8 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ }
}
diff --git a/core/java/com/android/internal/view/InputMethodClient.java b/core/java/com/android/internal/view/InputMethodClient.java
index c27e9aa3f2bb..802ce3e734d7 100644
--- a/core/java/com/android/internal/view/InputMethodClient.java
+++ b/core/java/com/android/internal/view/InputMethodClient.java
@@ -32,13 +32,14 @@ public final class InputMethodClient {
public static final int START_INPUT_REASON_UNBOUND_FROM_IMMS = 6;
public static final int START_INPUT_REASON_ACTIVATED_BY_IMMS = 7;
public static final int START_INPUT_REASON_DEACTIVATED_BY_IMMS = 8;
+ public static final int START_INPUT_REASON_SESSION_CREATED_BY_IME = 9;
@Retention(SOURCE)
@IntDef({START_INPUT_REASON_UNSPECIFIED, START_INPUT_REASON_WINDOW_FOCUS_GAIN,
START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY,
START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, START_INPUT_REASON_CHECK_FOCUS,
START_INPUT_REASON_BOUND_TO_IMMS, START_INPUT_REASON_ACTIVATED_BY_IMMS,
- START_INPUT_REASON_DEACTIVATED_BY_IMMS})
+ START_INPUT_REASON_DEACTIVATED_BY_IMMS, START_INPUT_REASON_SESSION_CREATED_BY_IME})
public @interface StartInputReason {}
public static String getStartInputReason(@StartInputReason final int reason) {
@@ -61,6 +62,8 @@ public final class InputMethodClient {
return "ACTIVATED_BY_IMMS";
case START_INPUT_REASON_DEACTIVATED_BY_IMMS:
return "DEACTIVATED_BY_IMMS";
+ case START_INPUT_REASON_SESSION_CREATED_BY_IME:
+ return "SESSION_CREATED_BY_IME";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/widget/DrawingSpace.java b/core/java/com/android/internal/widget/DrawingSpace.java
deleted file mode 100644
index b8222dba183c..000000000000
--- a/core/java/com/android/internal/widget/DrawingSpace.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * Implementation of {@link android.widget.Space} that uses normal View drawing
- * rather than a no-op. Useful for dialogs and other places where the base View
- * class is too greedy when measured with AT_MOST.
- */
-public final class DrawingSpace extends View {
- public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public DrawingSpace(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DrawingSpace(Context context) {
- this(context, null);
- }
-
- /**
- * Compare to: {@link View#getDefaultSize(int, int)}
- * <p>
- * If mode is AT_MOST, return the child size instead of the parent size
- * (unless it is too big).
- */
- private static int getDefaultSizeNonGreedy(int size, int measureSpec) {
- int result = size;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- switch (specMode) {
- case MeasureSpec.UNSPECIFIED:
- result = size;
- break;
- case MeasureSpec.AT_MOST:
- result = Math.min(size, specSize);
- break;
- case MeasureSpec.EXACTLY:
- result = specSize;
- break;
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(
- getDefaultSizeNonGreedy(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSizeNonGreedy(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
-}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ece5540443ce..58fb145db556 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -43,6 +43,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
import libcore.util.HexEncoding;
@@ -239,7 +240,8 @@ public class LockPatternUtils {
mHandler = looper != null ? new Handler(looper) : null;
}
- private ILockSettings getLockSettings() {
+ @VisibleForTesting
+ public ILockSettings getLockSettings() {
if (mLockSettingsService == null) {
ILockSettings service = ILockSettings.Stub.asInterface(
ServiceManager.getService("lock_settings"));
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 327f142fc319..db3ea8c51bf4 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -91,6 +91,7 @@ LOCAL_SRC_FILES:= \
android_os_MessageQueue.cpp \
android_os_Parcel.cpp \
android_os_SELinux.cpp \
+ android_os_seccomp.cpp \
android_os_SystemClock.cpp \
android_os_SystemProperties.cpp \
android_os_Trace.cpp \
@@ -118,6 +119,7 @@ LOCAL_SRC_FILES:= \
android/graphics/ColorFilter.cpp \
android/graphics/DrawFilter.cpp \
android/graphics/FontFamily.cpp \
+ android/graphics/FontUtils.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
android/graphics/GIFMovie.cpp \
android/graphics/GraphicBuffer.cpp \
@@ -229,6 +231,7 @@ LOCAL_C_INCLUDES += \
LOCAL_STATIC_LIBRARIES := \
libgif \
+ libseccomp_policy \
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 340f2eefa37a..407e69c2421a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -159,6 +159,7 @@ extern int register_android_os_HwRemoteBinder(JNIEnv *env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
+extern int register_android_os_seccomp(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_Trace(JNIEnv* env);
@@ -1360,6 +1361,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_GraphicsEnvironment),
REG_JNI(register_android_os_MessageQueue),
REG_JNI(register_android_os_SELinux),
+ REG_JNI(register_android_os_seccomp),
REG_JNI(register_android_os_Trace),
REG_JNI(register_android_os_UEventObserver),
REG_JNI(register_android_net_LocalSocketImpl),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ac8f413c2677..6ec658b9b916 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -30,6 +30,7 @@
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include "Utils.h"
+#include "FontUtils.h"
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
@@ -39,27 +40,60 @@
namespace android {
-static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
- if (lang == NULL) {
- return (jlong)new minikin::FontFamily(variant);
+struct NativeFamilyBuilder {
+ uint32_t langId;
+ int variant;
+ std::vector<minikin::Font> fonts;
+};
+
+static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
+ NativeFamilyBuilder* builder = new NativeFamilyBuilder();
+ if (lang != nullptr) {
+ ScopedUtfChars str(env, lang);
+ builder->langId = minikin::FontStyle::registerLanguageList(str.c_str());
+ } else {
+ builder->langId = minikin::FontStyle::registerLanguageList("");
+ }
+ builder->variant = variant;
+ return reinterpret_cast<jlong>(builder);
+}
+
+static jlong FontFamily_create(jlong builderPtr) {
+ if (builderPtr == 0) {
+ return 0;
}
- ScopedUtfChars str(env, lang);
- uint32_t langId = minikin::FontStyle::registerLanguageList(str.c_str());
- return (jlong)new minikin::FontFamily(langId, variant);
+ NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ minikin::FontFamily* family = new minikin::FontFamily(
+ builder->langId, builder->variant, std::move(builder->fonts));
+ delete builder;
+ return reinterpret_cast<jlong>(family);
+}
+
+static void FontFamily_abort(jlong builderPtr) {
+ NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ minikin::Font::clearElementsWithLock(&builder->fonts);
+ delete builder;
}
-static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
+static void FontFamily_unref(jlong familyPtr) {
minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
fontFamily->Unref();
}
-static jboolean addSkTypeface(minikin::FontFamily* family, sk_sp<SkTypeface> face,
- const void* fontData, size_t fontSize, int ttcIndex) {
+static void addSkTypeface(jlong builderPtr, sk_sp<SkTypeface> face, const void* fontData,
+ size_t fontSize, int ttcIndex) {
minikin::MinikinFont* minikinFont =
new MinikinFontSkia(std::move(face), fontData, fontSize, ttcIndex);
- bool result = family->addFont(minikinFont);
+ NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ int weight;
+ bool italic;
+ if (!minikin::FontFamily::analyzeStyle(minikinFont, &weight, &italic)) {
+ ALOGE("analyzeStyle failed. Using default style");
+ weight = 400;
+ italic = false;
+ }
+ builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight / 100, italic)));
minikinFont->Unref();
- return result;
}
static void release_global_ref(const void* /*data*/, void* context) {
@@ -85,7 +119,7 @@ static void release_global_ref(const void* /*data*/, void* context) {
}
}
-static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jobject bytebuf,
+static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, jobject bytebuf,
jint ttcIndex) {
NPE_CHECK_RETURN_ZERO(env, bytebuf);
const void* fontPtr = env->GetDirectBufferAddress(bytebuf);
@@ -112,21 +146,11 @@ static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr,
ALOGE("addFont failed to create font");
return false;
}
- minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
- return addSkTypeface(fontFamily, std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
+ addSkTypeface(builderPtr, std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
+ return true;
}
-static struct {
- jmethodID mGet;
- jmethodID mSize;
-} gListClassInfo;
-
-static struct {
- jfieldID mTag;
- jfieldID mStyleValue;
-} gAxisClassInfo;
-
-static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
+static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr,
jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
NPE_CHECK_RETURN_ZERO(env, font);
@@ -134,20 +158,22 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong
std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
int skiaAxesLength = 0;
if (listOfAxis) {
- jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
+ ListHelper list(env, listOfAxis);
+ jint listSize = list.size();
skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
skiaAxesLength = listSize;
for (jint i = 0; i < listSize; ++i) {
- jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
+ jobject axisObject = list.get(i);
if (!axisObject) {
skiaAxes[i].fTag = 0;
skiaAxes[i].fStyleValue = 0;
continue;
}
+ AxisHelper axis(env, axisObject);
- jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
- jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
+ jint tag = axis.getTag();
+ jfloat stylevalue = axis.getStyleValue();
skiaAxes[i].fTag = tag;
skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
}
@@ -178,10 +204,11 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong
ALOGE("addFont failed to create font, invalid request");
return false;
}
- minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
minikin::MinikinFont* minikinFont =
- new MinikinFontSkia(std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
- fontFamily->addFont(minikinFont, minikin::FontStyle(weight / 100, isItalic));
+ new MinikinFontSkia(std::move(face), fontPtr, fontSize, ttcIndex);
+ NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ builder->fonts.push_back(minikin::Font(minikinFont,
+ minikin::FontStyle(weight / 100, isItalic)));
minikinFont->Unref();
return true;
}
@@ -190,7 +217,7 @@ static void releaseAsset(const void* ptr, void* context) {
delete static_cast<Asset*>(context);
}
-static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong familyPtr,
+static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong builderPtr,
jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset) {
NPE_CHECK_RETURN_ZERO(env, jassetMgr);
NPE_CHECK_RETURN_ZERO(env, jpath);
@@ -233,14 +260,17 @@ static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong f
ALOGE("addFontFromAsset failed to create font %s", str.c_str());
return false;
}
- minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
- return addSkTypeface(fontFamily, std::move(face), buf, bufSize, /* ttcIndex */ 0);
+
+ addSkTypeface(builderPtr, std::move(face), buf, bufSize, 0 /* ttc index */);
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gFontFamilyMethods[] = {
- { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
+ { "nInitBuilder", "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
+ { "nCreateFamily", "(J)J", (void*)FontFamily_create },
+ { "nAbort", "(J)V", (void*)FontFamily_abort },
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
{ "nAddFont", "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont },
{ "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
@@ -254,14 +284,7 @@ int register_android_graphics_FontFamily(JNIEnv* env)
int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
NELEM(gFontFamilyMethods));
- jclass listClass = FindClassOrDie(env, "java/util/List");
- gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
- gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
-
- jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
- gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
- gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
-
+ init_FontUtils(env);
return err;
}
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
new file mode 100644
index 000000000000..8f44b1e82de8
--- /dev/null
+++ b/core/jni/android/graphics/FontUtils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_GRAPHICS_FONT_UTILS_H_
+#define _ANDROID_GRAPHICS_FONT_UTILS_H_
+
+#include <jni.h>
+
+namespace android {
+
+// Utility wrapper for java.util.List
+class ListHelper {
+public:
+ ListHelper(JNIEnv* env, jobject list) : mEnv(env), mList(list) {}
+
+ jint size() const;
+ jobject get(jint index) const;
+
+private:
+ JNIEnv* mEnv;
+ jobject mList;
+};
+
+// Utility wrapper for android.graphics.FontConfig$Axis
+class AxisHelper {
+public:
+ AxisHelper(JNIEnv* env, jobject axis) : mEnv(env), mAxis(axis) {}
+
+ jint getTag() const;
+ jfloat getStyleValue() const;
+
+private:
+ JNIEnv* mEnv;
+ jobject mAxis;
+};
+
+void init_FontUtils(JNIEnv* env);
+
+}; // namespace android
+
+#endif // _ANDROID_GRAPHICS_FONT_UTILS_H_
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index c920b8d653ab..0a0fce3ecfab 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -17,12 +17,14 @@
#include "jni.h"
#include "core_jni_helpers.h"
+#include "FontUtils.h"
#include "GraphicsJNI.h"
#include "ScopedPrimitiveArray.h"
#include "SkTypeface.h"
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include <hwui/Typeface.h>
+#include <minikin/FontFamily.h>
using namespace android;
@@ -40,6 +42,23 @@ static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandl
return reinterpret_cast<jlong>(face);
}
+static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
+ jobject listOfAxis) {
+ std::vector<minikin::FontVariation> variations;
+ ListHelper list(env, listOfAxis);
+ for (jint i = 0; i < list.size(); i++) {
+ jobject axisObject = list.get(i);
+ if (axisObject == nullptr) {
+ continue;
+ }
+ AxisHelper axis(env, axisObject);
+ variations.push_back(minikin::FontVariation(axis.getTag(), axis.getStyleValue()));
+ }
+ Typeface* baseTypeface = reinterpret_cast<Typeface*>(familyHandle);
+ Typeface* result = Typeface::createFromTypefaceWithVariation(baseTypeface, variations);
+ return reinterpret_cast<jlong>(result);
+}
+
static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
Typeface* face = Typeface::createWeightAlias(family, weight);
@@ -77,6 +96,8 @@ static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
static const JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
+ { "nativeCreateFromTypefaceWithVariation", "(JLjava/util/List;)J",
+ (void*)Typeface_createFromTypefaceWithVariation },
{ "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias },
{ "nativeUnref", "(J)V", (void*)Typeface_unref },
{ "nativeGetStyle", "(J)I", (void*)Typeface_getStyle },
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 74527d97e119..6cf5ccfa2d15 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -30,6 +30,7 @@
#include <binder/Parcel.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
+#include <hardware/gralloc1.h>
#include <ui/GraphicBuffer.h>
#include <private/gui/ComposerService.h>
@@ -96,10 +97,15 @@ static jlong android_hardware_HardwareBuffer_create(JNIEnv* env, jobject clazz,
}
return NULL;
}
- uint32_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0);
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0, &producerUsage,
+ &consumerUsage);
status_t error;
sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, pixelFormat,
- layers, grallocUsage, &error));
+ layers, producerUsage, consumerUsage,
+ std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]",
+ &error));
if (buffer == NULL) {
if (kDebugGraphicBuffer) {
ALOGW("createGraphicBuffer() failed in HardwareBuffer.create()");
@@ -158,7 +164,7 @@ static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
jobject clazz, jlong nativeObject) {
GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
return android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- buffer->getUsage());
+ buffer->getUsage(), buffer->getUsage());
}
// ----------------------------------------------------------------------------
@@ -223,16 +229,18 @@ jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) {
switch (format) {
- case PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- case PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
- case PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGB_565:
return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
- case PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_RGB_888:
return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
- case PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
+ case HAL_PIXEL_FORMAT_BLOB:
+ return AHARDWAREBUFFER_FORMAT_BLOB;
default:
ALOGE("Unknown pixel format %u", format);
return 0;
@@ -242,67 +250,75 @@ uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format)
uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) {
switch (format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
- return PIXEL_FORMAT_RGBA_8888;
+ return HAL_PIXEL_FORMAT_RGBA_8888;
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
- return PIXEL_FORMAT_RGBX_8888;
+ return HAL_PIXEL_FORMAT_RGBX_8888;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
- return PIXEL_FORMAT_RGB_565;
+ return HAL_PIXEL_FORMAT_RGB_565;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
- return PIXEL_FORMAT_RGB_888;
+ return HAL_PIXEL_FORMAT_RGB_888;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT:
- return PIXEL_FORMAT_RGBA_FP16;
+ return HAL_PIXEL_FORMAT_RGBA_FP16;
+ case AHARDWAREBUFFER_FORMAT_BLOB:
+ return HAL_PIXEL_FORMAT_BLOB;
default:
ALOGE("Unknown AHardwareBuffer format %u", format);
return 0;
}
}
-uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
- uint64_t usage1) {
- uint32_t bits = 0;
+void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
+ uint64_t usage1, uint64_t* outProducerUsage,
+ uint64_t* outConsumerUsage) {
+ *outProducerUsage = 0;
+ *outConsumerUsage = 0;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ))
- bits |= GRALLOC_USAGE_SW_READ_RARELY;
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
- bits |= GRALLOC_USAGE_SW_READ_OFTEN;
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
- bits |= GRALLOC_USAGE_SW_WRITE_RARELY;
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
- bits |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
- bits |= GRALLOC_USAGE_HW_TEXTURE;
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
- bits |= GRALLOC_USAGE_HW_RENDER;
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
// Not sure what this should be.
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
- //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER) bits |= 0;
+ //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
+ if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE))
- bits |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER;
if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
- bits |= GRALLOC_USAGE_PROTECTED;
-
- (void)usage1;
-
- return bits;
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
+ if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
}
-uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t usage0) {
+uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+ uint64_t producerUsage, uint64_t consumerUsage) {
uint64_t bits = 0;
- if (containsBits(usage0, GRALLOC_USAGE_SW_READ_RARELY))
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ))
bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
- if (containsBits(usage0, GRALLOC_USAGE_SW_READ_OFTEN))
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN))
bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
- if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_RARELY))
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE))
bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
- if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_OFTEN))
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN))
bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
- if (containsBits(usage0, GRALLOC_USAGE_HW_TEXTURE))
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE))
bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
- if (containsBits(usage0, GRALLOC_USAGE_HW_RENDER))
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))
bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
- if (containsBits(usage0, GRALLOC_USAGE_HW_VIDEO_ENCODER))
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER))
+ bits |= AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER))
bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
- if (containsBits(usage0, GRALLOC_USAGE_PROTECTED))
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_PROTECTED))
bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA))
+ bits |= AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA;
return bits;
}
diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp
index 397e67bab488..b6b1ac75f0e9 100644
--- a/core/jni/android_hardware_Radio.cpp
+++ b/core/jni/android_hardware_Radio.cpp
@@ -23,7 +23,7 @@
#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include <system/radio.h>
-#include <system/radio_metadata.h>
+#include <system/RadioMetadataWrapper.h>
#include <radio/RadioCallback.h>
#include <radio/Radio.h>
#include <utils/RefBase.h>
@@ -752,7 +752,7 @@ android_hardware_Radio_getProgramInformation(JNIEnv *env, jobject thiz, jobjectA
}
struct radio_program_info nInfo;
- radio_metadata_allocate(&nInfo.metadata, 0, 0);
+ RadioMetadataWrapper metadataWrapper(&nInfo.metadata);
jobject jInfo = NULL;
int jStatus;
@@ -770,7 +770,6 @@ exit:
if (jInfo != NULL) {
env->DeleteLocalRef(jInfo);
}
- radio_metadata_deallocate(nInfo.metadata);
return jStatus;
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 271f24b13052..bc2fc1c39890 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -26,6 +26,7 @@
#include <gui/Sensor.h>
#include <gui/SensorEventQueue.h>
#include <gui/SensorManager.h>
+#include <cutils/native_handle.h>
#include <utils/Log.h>
#include <utils/Looper.h>
#include <utils/Vector.h>
@@ -243,6 +244,54 @@ static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong s
return mgr->isDataInjectionEnabled();
}
+static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
+ jlong size, jint channelType, jlongArray channelData) {
+ jint ret = -1;
+ jsize len = _env->GetArrayLength(channelData);
+ if (len > 2) {
+ jlong *data = _env->GetLongArrayElements(channelData, NULL);
+ if (data != nullptr) {
+ // construct native handle from jlong*
+ jlong numFd = data[0];
+ jlong numInt = data[1];
+ if ((numFd + numInt + 2) == len) {
+ native_handle_t *nativeHandle = native_handle_create(numFd, numInt);
+ if (nativeHandle != nullptr) {
+ const jlong *readPointer = data + 2;
+ int *writePointer = nativeHandle->data;
+ size_t n = static_cast<size_t>(numFd + numInt);
+ while (n--) {
+ // native type of data is int, jlong is just to ensure Java does not
+ // truncate data on 64-bit system. The cast here is safe.
+ *writePointer++ = static_cast<int>(*readPointer++);
+ }
+
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ ret = mgr->createDirectChannel(size, channelType, nativeHandle);
+
+ // do not native_handle_close() here as handle is owned by java
+ native_handle_delete(nativeHandle);
+ }
+ }
+ // unidirectional parameter passing, thus JNI_ABORT
+ _env->ReleaseLongArrayElements(channelData, data, JNI_ABORT);
+ }
+ }
+ return ret;
+}
+
+static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
+ jint channelHandle) {
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ mgr->destroyDirectChannel(channelHandle);
+}
+
+static jint nativeConfigDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
+ jint channelHandle, jint sensorHandle, jint rate) {
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
+}
+
//----------------------------------------------------------------------------
class Receiver : public LooperCallback {
@@ -447,7 +496,19 @@ static const JNINativeMethod gSystemSensorManagerMethods[] = {
{"nativeIsDataInjectionEnabled",
"(J)Z",
- (void*)nativeIsDataInjectionEnabled},
+ (void*)nativeIsDataInjectionEnabled },
+
+ {"nativeCreateDirectChannel",
+ "(JJI[J)I",
+ (void*)nativeCreateDirectChannel },
+
+ {"nativeDestroyDirectChannel",
+ "(JI)V",
+ (void*)nativeDestroyDirectChannel },
+
+ {"nativeConfigDirectChannel",
+ "(JIII)I",
+ (void*)nativeConfigDirectChannel },
};
static const JNINativeMethod gBaseEventQueueMethods[] = {
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 793d1325ab6f..0c7f5a116561 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -509,7 +509,7 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
sp<MemoryDealer> memoryDealer;
sp<IMemory> memory;
size_t size;
- sound_model_handle_t handle;
+ sound_model_handle_t handle = 0;
jobject jUuid;
jstring jUuidString;
const char *nUuidString;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 86c4df758811..b2c8168b367a 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -972,6 +972,18 @@ static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject th
}
// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_flags(JNIEnv *env, jobject thiz) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getFlags()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ return (jint)lpTrack->getFlags();
+}
+
+// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
@@ -1212,6 +1224,7 @@ static const JNINativeMethod gMethods[] = {
{"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
{"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
{"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
+ {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
{"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index e65390047c55..d35ffbba3a1e 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -302,6 +302,14 @@ static jobject JHwBinder_native_getService(
return NULL;
}
+ auto manager = hardware::defaultServiceManager();
+
+ if (manager == nullptr) {
+ LOG(ERROR) << "Could not get hwservicemanager.";
+ signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
+ }
+
const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
if (ifaceName == NULL) {
return NULL; // XXX exception already pending?
@@ -312,32 +320,26 @@ static jobject JHwBinder_native_getService(
return NULL; // XXX exception already pending?
}
- LOG(INFO) << "looking for service '"
- << serviceName
- << "'";
-
- auto manager = hardware::defaultServiceManager();
-
- if (manager == nullptr) {
- LOG(ERROR) << "Could not get hwservicemanager.";
- signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
- return NULL;
- }
+ LOG(INFO) << "Looking for service "
+ << ifaceName
+ << "/"
+ << serviceName;
Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
+ env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+ ifaceName = NULL;
+ env->ReleaseStringUTFChars(serviceNameObj, serviceName);
+ serviceName = NULL;
+
if (!ret.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
}
sp<hardware::IBinder> service = hardware::toBinder<
hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
- env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
- ifaceName = NULL;
- env->ReleaseStringUTFChars(serviceNameObj, serviceName);
- serviceName = NULL;
-
if (service == NULL) {
signalExceptionForError(env, NAME_NOT_FOUND);
return NULL;
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index b2dee0689ee0..8590ecf3bb19 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -382,7 +382,7 @@ static void JHwBlob_native_putString(
s = nullptr;
hidl_string tmp;
- tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+ tmp.setToExternal(static_cast<const char *>(subBlob->data()), size - 1);
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
blob->write(offset, &tmp, sizeof(tmp));
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
new file mode 100644
index 000000000000..02c0c625d469
--- /dev/null
+++ b/core/jni/android_os_seccomp.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "core_jni_helpers.h"
+#include "JniConstants.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#if defined __arm__ || defined __aarch64__
+
+#include <vector>
+
+#include <sys/prctl.h>
+
+#include <linux/unistd.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+#include "seccomp_policy.h"
+
+#define syscall_nr (offsetof(struct seccomp_data, nr))
+#define arch_nr (offsetof(struct seccomp_data, arch))
+
+typedef std::vector<sock_filter> filter;
+
+// We want to keep the below inline functions for debugging and future
+// development even though they are not all sed currently.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+
+static inline void Kill(filter& f) {
+ f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL));
+}
+
+static inline void Trap(filter& f) {
+ f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
+}
+
+static inline void Error(filter& f, __u16 retcode) {
+ f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode));
+}
+
+inline static void Trace(filter& f) {
+ f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE));
+}
+
+inline static void Allow(filter& f) {
+ f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
+}
+
+#pragma clang diagnostic pop
+
+inline static void AllowSyscall(filter& f, __u32 num) {
+ f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1));
+ Allow(f);
+}
+
+inline static void ExamineSyscall(filter& f) {
+ f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
+}
+
+inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
+ size_t jump_length = f.size() - offset - 1;
+ auto u8_jump_length = (__u8) jump_length;
+ if (u8_jump_length != jump_length) {
+ ALOGE("Can't set jump greater than 255 - actual jump is %zu",
+ jump_length);
+ return -1;
+ }
+ f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, u8_jump_length, 0);
+ return 0;
+}
+
+inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
+ f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
+
+ f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_AARCH64, 2, 0));
+ f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, 1, 0));
+ Trap(f);
+ return f.size() - 2;
+}
+
+static bool install_filter(filter const& f) {
+ struct sock_fprog prog = {
+ (unsigned short) f.size(),
+ (struct sock_filter*) &f[0],
+ };
+
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
+ ALOGE("SECCOMP: Could not set seccomp filter of size %zu: %s", f.size(), strerror(errno));
+ return false;
+ }
+
+ ALOGI("SECCOMP: Global filter of size %zu installed", f.size());
+ return true;
+}
+
+bool set_seccomp_filter() {
+ filter f;
+
+ // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
+ // jump that must be changed to point to the start of the 32-bit policy
+ // 32 bit syscalls will not hit the policy between here and the call to SetJump
+ auto offset_to_32bit_filter =
+ ValidateArchitectureAndJumpIfNeeded(f);
+
+ // 64-bit filter
+ ExamineSyscall(f);
+
+ // arm64-only filter - autogenerated from bionic syscall usage
+ for (size_t i = 0; i < arm64_filter_size; ++i)
+ f.push_back(arm64_filter[i]);
+
+ // Syscalls needed to boot Android
+ AllowSyscall(f, 41); // __NR_pivot_root
+ AllowSyscall(f, 31); // __NR_ioprio_get
+ AllowSyscall(f, 30); // __NR_ioprio_set
+ AllowSyscall(f, 178); // __NR_gettid
+ AllowSyscall(f, 98); // __NR_futex
+ AllowSyscall(f, 220); // __NR_clone
+ AllowSyscall(f, 139); // __NR_rt_sigreturn
+ AllowSyscall(f, 240); // __NR_rt_tgsigqueueinfo
+ AllowSyscall(f, 128); // __NR_restart_syscall
+ AllowSyscall(f, 278); // __NR_getrandom
+
+ // Needed for performance tools
+ AllowSyscall(f, 241); // __NR_perf_event_open
+
+ // Needed for strace
+ AllowSyscall(f, 130); // __NR_tkill
+
+ // Needed for kernel to restart syscalls
+ AllowSyscall(f, 128); // __NR_restart_syscall
+
+ // b/35034743
+ AllowSyscall(f, 267); // __NR_fstatfs64
+
+ Trap(f);
+
+ if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
+ return -1;
+
+ // 32-bit filter
+ ExamineSyscall(f);
+
+ // arm32 filter - autogenerated from bionic syscall usage
+ for (size_t i = 0; i < arm_filter_size; ++i)
+ f.push_back(arm_filter[i]);
+
+ // Syscalls needed to boot android
+ AllowSyscall(f, 120); // __NR_clone
+ AllowSyscall(f, 240); // __NR_futex
+ AllowSyscall(f, 119); // __NR_sigreturn
+ AllowSyscall(f, 173); // __NR_rt_sigreturn
+ AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo
+ AllowSyscall(f, 224); // __NR_gettid
+
+ // Syscalls needed to run Chrome
+ AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome
+ AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome
+
+ // Syscalls needed to run GFXBenchmark
+ AllowSyscall(f, 190); // __NR_vfork
+
+ // Needed for strace
+ AllowSyscall(f, 238); // __NR_tkill
+
+ // Needed for kernel to restart syscalls
+ AllowSyscall(f, 0); // __NR_restart_syscall
+
+ // Needed for debugging 32-bit Chrome
+ AllowSyscall(f, 42); // __NR_pipe
+
+ // b/34732712
+ AllowSyscall(f, 364); // __NR_perf_event_open
+
+ // b/34651972
+ AllowSyscall(f, 33); // __NR_access
+ AllowSyscall(f, 195); // __NR_stat64
+
+ // b/34813887
+ AllowSyscall(f, 5); // __NR_open
+ AllowSyscall(f, 141); // __NR_getdents
+ AllowSyscall(f, 217); // __NR_getdents64
+
+ // b/34719286
+ AllowSyscall(f, 351); // __NR_eventfd
+
+ // b/34817266
+ AllowSyscall(f, 252); // __NR_epoll_wait
+
+ // Needed by sanitizers (b/34606909)
+ // 5 (__NR_open) and 195 (__NR_stat64) are also required, but they are
+ // already allowed.
+ AllowSyscall(f, 85); // __NR_readlink
+
+ // b/34908783
+ AllowSyscall(f, 250); // __NR_epoll_create
+
+ // b/34979910
+ AllowSyscall(f, 8); // __NR_creat
+ AllowSyscall(f, 10); // __NR_unlink
+
+ Trap(f);
+
+ return install_filter(f);
+}
+
+static void Seccomp_setPolicy(JNIEnv* /*env*/) {
+ if (!set_seccomp_filter()) {
+ ALOGE("Failed to set seccomp policy - killing");
+ exit(1);
+ }
+}
+
+#else // #if defined __arm__ || defined __aarch64__
+
+static void Seccomp_setPolicy(JNIEnv* /*env*/) {
+}
+
+#endif
+
+static const JNINativeMethod method_table[] = {
+ NATIVE_METHOD(Seccomp, setPolicy, "()V"),
+};
+
+namespace android {
+
+int register_android_os_seccomp(JNIEnv* env) {
+ return android::RegisterMethodsOrDie(env, "android/os/Seccomp",
+ method_table, NELEM(method_table));
+}
+
+}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d382f245e0d7..723dce6fcf1e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -681,7 +681,7 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
jint smallestScreenWidthDp,
jint screenWidthDp, jint screenHeightDp,
jint screenLayout, jint uiMode,
- jint sdkVersion)
+ jint colorMode, jint sdkVersion)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
@@ -712,6 +712,7 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
config.screenHeightDp = (uint16_t)screenHeightDp;
config.screenLayout = (uint8_t)screenLayout;
config.uiMode = (uint8_t)uiMode;
+ config.colorMode = (uint8_t)colorMode;
config.sdkVersion = (uint16_t)sdkVersion;
config.minorVersion = 0;
@@ -1691,7 +1692,7 @@ static const JNINativeMethod gAssetManagerMethods[] = {
{ "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
(void*) android_content_AssetManager_getSizeConfigurations },
// @FastNative
- { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
+ { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
(void*) android_content_AssetManager_setConfiguration },
// @FastNative
{ "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index d75d5c179d3c..f221392f16bd 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -43,57 +43,6 @@ using namespace uirenderer;
? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
: false)
-static JNIEnv* getenv(JavaVM* vm) {
- JNIEnv* env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
- }
- return env;
-}
-
-static jfieldID gRenderNode_validFieldID;
-
-class RenderNodeContext : public VirtualLightRefBase {
-public:
- RenderNodeContext(JNIEnv* env, jobject jobjRef) {
- env->GetJavaVM(&mVm);
- // This holds a weak ref because otherwise there's a cyclic global ref
- // with this holding a strong global ref to the view which holds
- // a strong ref to RenderNode which holds a strong ref to this.
- mWeakRef = env->NewWeakGlobalRef(jobjRef);
- }
-
- virtual ~RenderNodeContext() {
- JNIEnv* env = getenv(mVm);
- env->DeleteWeakGlobalRef(mWeakRef);
- }
-
- jobject acquireLocalRef(JNIEnv* env) {
- return env->NewLocalRef(mWeakRef);
- }
-
-private:
- JavaVM* mVm;
- jweak mWeakRef;
-};
-
-// Called by ThreadedRenderer's JNI layer
-void onRenderNodeRemoved(JNIEnv* env, RenderNode* node) {
- auto context = reinterpret_cast<RenderNodeContext*>(node->getUserContext());
- if (!context) return;
- jobject jnode = context->acquireLocalRef(env);
- if (!jnode) {
- // The owning node has been GC'd, release the context
- node->setUserContext(nullptr);
- return;
- }
-
- // Update the valid field, since native has already removed
- // the staging DisplayList
- env->SetBooleanField(jnode, gRenderNode_validFieldID, false);
- env->DeleteLocalRef(jnode);
-}
-
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -108,8 +57,7 @@ static jint android_view_RenderNode_getDebugSize(JNIEnv* env, jobject clazz, jlo
return renderNode->getDebugSize();
}
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
- jstring name) {
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
RenderNode* renderNode = new RenderNode();
renderNode->incStrong(0);
if (name != NULL) {
@@ -117,7 +65,6 @@ static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
renderNode->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
- renderNode->setUserContext(new RenderNodeContext(env, thiz));
return reinterpret_cast<jlong>(renderNode);
}
@@ -132,22 +79,13 @@ static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env,
static void android_view_RenderNode_setDisplayList(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong displayListPtr) {
- class RemovedObserver : public TreeObserver {
- public:
- virtual void onMaybeRemovedFromTree(RenderNode* node) override {
- maybeRemovedNodes.insert(sp<RenderNode>(node));
- }
- std::set< sp<RenderNode> > maybeRemovedNodes;
- };
-
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
DisplayList* newData = reinterpret_cast<DisplayList*>(displayListPtr);
- RemovedObserver observer;
- renderNode->setStagingDisplayList(newData, &observer);
- for (auto& node : observer.maybeRemovedNodes) {
- if (node->hasParents()) continue;
- onRenderNodeRemoved(env, node.get());
- }
+ renderNode->setStagingDisplayList(newData);
+}
+
+static jboolean android_view_RenderNode_isValid(jlong renderNodePtr) {
+ return reinterpret_cast<RenderNode*>(renderNodePtr)->isValid();
}
// ----------------------------------------------------------------------------
@@ -621,6 +559,7 @@ static const JNINativeMethod gMethods[] = {
// ----------------------------------------------------------------------------
// Critical JNI via @CriticalNative annotation in RenderNode.java
// ----------------------------------------------------------------------------
+ { "nIsValid", "(J)Z", (void*) android_view_RenderNode_isValid },
{ "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType },
{ "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint },
{ "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
@@ -691,8 +630,6 @@ int register_android_view_RenderNode(JNIEnv* env) {
"updateWindowPosition_renderWorker", "(JIIII)V");
gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
"windowPositionLost_uiRtSync", "(J)V");
- clazz = FindClassOrDie(env, "android/view/RenderNode");
- gRenderNode_validFieldID = GetFieldIDOrDie(env, clazz, "mValid", "Z");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 96e6f819d592..bc5f847a4aa8 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -532,7 +532,7 @@ static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
UiFrameInfoBuilder(proxy->frameInfo())
.setVsync(vsync, vsync)
.addFlag(FrameInfoFlags::SurfaceCanvas);
- proxy->syncAndDrawFrame(nullptr);
+ proxy->syncAndDrawFrame();
}
static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a3fef27a9c3a..0171562184dc 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -98,15 +98,18 @@ static struct {
// ----------------------------------------------------------------------------
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
- jstring nameStr, jint w, jint h, jint format, jint flags) {
+ jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
+ jint windowType, jint ownerUid) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
+ SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
sp<SurfaceControl> surface = client->createSurface(
- String8(name.c_str()), w, h, format, flags);
+ String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
}
+
surface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(surface.get());
}
@@ -147,8 +150,8 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
}
Rect sourceCrop = rectFromObj(env, sourceCropObj);
if (allLayers) {
- minLayer = 0;
- maxLayer = -1;
+ minLayer = INT32_MIN;
+ maxLayer = INT32_MAX;
}
sp<GraphicBuffer> buffer;
status_t res = ScreenshotClient::captureToBuffer(displayToken,
@@ -181,8 +184,8 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient());
status_t res;
if (allLayers) {
- minLayer = 0;
- maxLayer = -1;
+ minLayer = INT32_MIN;
+ maxLayer = INT32_MAX;
}
res = screenshot->update(displayToken, sourceCrop, width, height,
@@ -254,12 +257,12 @@ static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
Rect sourceCrop(left, top, right, bottom);
if (allLayers) {
- minLayer = 0;
- maxLayer = -1;
+ minLayer = INT32_MIN;
+ maxLayer = INT32_MAX;
}
ScreenshotClient::capture(displayToken,
consumer->getIGraphicBufferProducer(), sourceCrop,
- width, height, uint32_t(minLayer), uint32_t(maxLayer),
+ width, height, minLayer, maxLayer,
useIdentityTransform);
}
}
@@ -741,7 +744,7 @@ static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject token
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
- {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
+ {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
(void*)nativeCreate },
{"nativeRelease", "(J)V",
(void*)nativeRelease },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index c00bcd461181..d37f96aeca30 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -71,31 +71,6 @@ static JNIEnv* getenv(JavaVM* vm) {
return env;
}
-// TODO: Clean this up, it's a bit odd to need to call over to
-// rendernode's jni layer. Probably means RootRenderNode should be pulled
-// into HWUI with appropriate callbacks for the various JNI hooks so
-// that RenderNode's JNI layer can handle its own thing
-void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
-
-class ScopedRemovedRenderNodeObserver : public TreeObserver {
-public:
- explicit ScopedRemovedRenderNodeObserver(JNIEnv* env) : mEnv(env) {}
- ~ScopedRemovedRenderNodeObserver() {
- for (auto& node : mMaybeRemovedNodes) {
- if (node->hasParents()) continue;
- onRenderNodeRemoved(mEnv, node.get());
- }
- }
-
- virtual void onMaybeRemovedFromTree(RenderNode* node) override {
- mMaybeRemovedNodes.insert(sp<RenderNode>(node));
- }
-
-private:
- JNIEnv* mEnv;
- std::set< sp<RenderNode> > mMaybeRemovedNodes;
-};
-
class OnFinishedEvent {
public:
OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
@@ -715,18 +690,16 @@ static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject c
"Mismatched size expectations, given %d expected %d",
frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- ScopedRemovedRenderNodeObserver observer(env);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
- return proxy->syncAndDrawFrame(&observer);
+ return proxy->syncAndDrawFrame();
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong rootNodePtr) {
- ScopedRemovedRenderNodeObserver observer(env);
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
rootRenderNode->destroy();
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->destroy(&observer);
+ proxy->destroy();
}
static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
@@ -758,10 +731,9 @@ static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobje
static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong nodePtr) {
- ScopedRemovedRenderNodeObserver observer(env);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
- proxy->buildLayer(node, &observer);
+ proxy->buildLayer(node);
}
static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
@@ -796,9 +768,8 @@ static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobj
static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
- ScopedRemovedRenderNodeObserver observer(env);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->destroyHardwareResources(&observer);
+ proxy->destroyHardwareResources();
}
static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 070a2d96cd40..e2fc44460dcd 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -253,13 +253,36 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) {
ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
"your kernel is compiled with file capabilities support");
} else {
+ ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
}
}
}
}
-static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ if (capget(&capheader, &capdata[0]) == -1) {
+ ALOGE("capget failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "capget failed");
+ }
+
+ capdata[0].inheritable = inheritable;
+ capdata[1].inheritable = inheritable >> 32;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+ RuntimeAbort(env, __LINE__, "capset failed");
+ }
+}
+
+static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
+ uint64_t inheritable) {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -271,9 +294,12 @@ static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
capdata[1].effective = effective >> 32;
capdata[0].permitted = permitted;
capdata[1].permitted = permitted >> 32;
+ capdata[0].inheritable = inheritable;
+ capdata[1].inheritable = inheritable >> 32;
if (capset(&capheader, &capdata[0]) == -1) {
- ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
+ ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
+ effective, inheritable, strerror(errno));
RuntimeAbort(env, __LINE__, "capset failed");
}
}
@@ -527,6 +553,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
EnableKeepCapabilities(env);
}
+ SetInheritable(env, permittedCapabilities);
DropCapabilitiesBoundingSet(env);
bool use_native_bridge = !is_system_server && (instructionSet != NULL)
@@ -599,7 +626,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
}
}
- SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+ SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
SetSchedulerPolicy(env);
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index bf0e9eddb3e7..eeb92fce2640 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -132,6 +132,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o
pointer = _env->CallStaticLongMethod(nioAccessClass,
getBasePointerID, buffer);
if (pointer != 0L) {
+ *offset = 0;
*array = NULL;
return reinterpret_cast<void *>(pointer);
}
@@ -139,6 +140,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
+ *offset = 0;
return (void*) NULL;
}
*offset = _env->CallStaticIntMethod(nioAccessClass,
diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
index 60e065cbd0e3..a5d0596dd98b 100644
--- a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
+++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
@@ -40,12 +40,13 @@ extern uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(
uint32_t format);
/* Convert from AHARDWAREBUFFER_USAGE* flags to to gralloc usage flags. */
-extern uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- uint64_t usage0, uint64_t usage1);
+extern void android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+ uint64_t usage0, uint64_t usage1, uint64_t* outProducerUsage,
+ uint64_t* outConsumerUsage);
/* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */
extern uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- uint64_t usage0);
+ uint64_t producerUsage, uint64_t consumerUsage);
} // namespace android
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ac9ebe06ae0e..ba1d6646adae 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -20,8 +20,10 @@ option java_multiple_files = true;
option java_outer_classname = "IncidentProtoMetadata";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/fingerprint.proto";
import "frameworks/base/core/proto/android/service/netstats.proto";
+import "frameworks/base/core/proto/android/service/notification.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
package android.os;
@@ -53,4 +55,6 @@ message IncidentProto {
android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000;
android.service.NetworkStatsServiceDumpProto netstats = 3001;
android.providers.settings.SettingsServiceDumpProto settings = 3002;
+ android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
+ android.service.notification.NotificationServiceDumpProto notification = 3004;
}
diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto
new file mode 100644
index 000000000000..1f04f71bb121
--- /dev/null
+++ b/core/proto/android/service/appwidget.proto
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.appwidget;
+
+option java_multiple_files = true;
+option java_outer_classname = "AppWidgetServiceProto";
+
+// represents the object holding the dump info of the app widget service
+message AppWidgetServiceDumpProto {
+ repeated WidgetProto widgets = 1; // the array of bound widgets
+}
+
+// represents a bound widget
+message WidgetProto {
+ bool isCrossProfile = 1; // true if host and provider belong to diff users
+ bool isHostStopped = 2; // true if host has not called startListening yet
+ string hostPackage = 3;
+ string providerPackage = 4;
+ string providerClass = 5;
+ int32 minWidth = 6;
+ int32 minHeight = 7;
+ int32 maxWidth = 8;
+ int32 maxHeight = 9;
+}
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
new file mode 100644
index 000000000000..33ad682ba8b1
--- /dev/null
+++ b/core/proto/android/service/battery.proto
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.battery;
+
+option java_multiple_files = true;
+option java_outer_classname = "BatteryServiceProto";
+
+message BatteryServiceDumpProto {
+ enum BatteryPlugged {
+ BATTERY_PLUGGED_NONE = 0;
+ BATTERY_PLUGGED_AC = 1;
+ BATTERY_PLUGGED_USB = 2;
+ BATTERY_PLUGGED_WIRELESS = 4;
+ }
+ enum BatteryStatus {
+ BATTERY_STATUS_INVALID = 0;
+ BATTERY_STATUS_UNKNOWN = 1;
+ BATTERY_STATUS_CHARGING = 2;
+ BATTERY_STATUS_DISCHARGING = 3;
+ BATTERY_STATUS_NOT_CHARGING = 4;
+ BATTERY_STATUS_FULL = 5;
+ }
+ enum BatteryHealth {
+ BATTERY_HEALTH_INVALID = 0;
+ BATTERY_HEALTH_UNKNOWN = 1;
+ BATTERY_HEALTH_GOOD = 2;
+ BATTERY_HEALTH_OVERHEAT = 3;
+ BATTERY_HEALTH_DEAD = 4;
+ BATTERY_HEALTH_OVER_VOLTAGE = 5;
+ BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
+ BATTERY_HEALTH_COLD = 7;
+ }
+
+ // If true: UPDATES STOPPED -- use 'reset' to restart
+ bool are_updates_stopped = 1;
+ // Plugged status of power sources
+ BatteryPlugged plugged = 2;
+ // Max current in microamperes
+ int32 max_charging_current = 3;
+ // Max voltage
+ int32 max_charging_voltage = 4;
+ // Battery capacity in microampere-hours
+ int32 charge_counter = 5;
+ // Charging status
+ BatteryStatus status = 6;
+ // Battery health
+ BatteryHealth health = 7;
+ // True if the battery is present
+ bool is_present = 8;
+ // Charge level, from 0 through "scale" inclusive
+ int32 level = 9;
+ // The maximum value for the charge level
+ int32 scale = 10;
+ // Battery voltage in millivolts
+ int32 voltage = 11;
+ // Battery temperature in tenths of a degree Centigrade
+ int32 temperature = 12;
+ // The type of battery installed, e.g. "Li-ion"
+ string technology = 13;
+}
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index 5cca6ab07a6d..5a577b1a3236 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -27,12 +27,16 @@ message NetworkStatsServiceDumpProto {
repeated NetworkInterfaceProto active_uid_interfaces = 2;
+ // Device level network stats, which may include non-IP layer traffic.
NetworkStatsRecorderProto dev_stats = 3;
+ // IP-layer traffic stats.
NetworkStatsRecorderProto xt_stats = 4;
+ // Per-UID network stats.
NetworkStatsRecorderProto uid_stats = 5;
+ // Per-UID, per-tag network stats, excluding the default tag (i.e. tag=0).
NetworkStatsRecorderProto uid_tag_stats = 6;
}
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
new file mode 100644
index 000000000000..bc257e04440d
--- /dev/null
+++ b/core/proto/android/service/notification.proto
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.notification;
+
+option java_multiple_files = true;
+option java_outer_classname = "NotificationServiceProto";
+
+message NotificationServiceDumpProto {
+ repeated NotificationRecordProto records = 1;
+}
+
+message NotificationRecordProto {
+ string key = 1;
+ State state = 2;
+ int32 flags = 3;
+ string channelId = 4;
+ string sound = 5;
+ int32 sound_usage = 6;
+ bool can_vibrate = 7;
+ bool can_show_light = 8;
+ string group_key = 9;
+ int32 importance = 10;
+}
+
+enum State {
+ ENQUEUED = 0;
+
+ POSTED = 1;
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6d48862ea132..7b800b363e65 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -82,6 +82,10 @@
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
<protected-broadcast android:name="android.intent.action.USER_INITIALIZE" />
<protected-broadcast android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_ADDED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -443,6 +447,7 @@
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
+ <protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
<protected-broadcast android:name="EventConditionProvider.EVALUATE" />
<protected-broadcast android:name="SnoozeHelper.EVALUATE" />
@@ -514,6 +519,7 @@
<!-- Added in O -->
<!-- TODO: temporary broadcast used by AutoFillManagerServiceImpl; will be removed -->
<protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" />
+ <protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -1607,6 +1613,16 @@
<permission android:name="android.permission.RECEIVE_STK_COMMANDS"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by an ImsService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature|privileged
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_IMS_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
@@ -2095,6 +2111,12 @@
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"/>
+ <!-- Allows an application to enable, disable and change priority of
+ runtime resource overlays.
+ @hide -->
+ <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
@@ -2343,6 +2365,11 @@
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by the CompanionDeviceManager to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
that only the system can bind to it.
@hide -->
@@ -2482,7 +2509,7 @@
<!-- Allows an application to request installing packages. Apps
targeting APIs greater than 25 must hold this permission in
order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
- <p>Protection level: normal
+ <p>Protection level: signature
-->
<permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
android:label="@string/permlab_requestInstallPackages"
@@ -2645,6 +2672,21 @@
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to set the volume key long-press listener.
+ <p>When it's set, the application will receive the volume key long-press event
+ instead of changing volume.</p>
+ <p>Not for use by third-party applications</p> -->
+ <permission android:name="android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi @hide Allows an application to set media key event listener.
+ <p>When it's set, the application will receive the media key event before
+ any other media sessions. If the event is handled by the listener, other sessions
+ cannot get the event.</p>
+ <p>Not for use by third-party applications</p> -->
+ <permission android:name="android.permission.SET_MEDIA_KEY_LISTENER"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- @SystemApi Required to be able to disable the device (very dangerous!).
<p>Not for use by third-party applications.
@hide
@@ -3139,8 +3181,8 @@
<!-- Allows the holder to access the instant applications on the device.
@hide -->
- <permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
- android:protectionLevel="signature" />
+ <permission android:name="android.permission.ACCESS_INSTANT_APPS"
+ android:protectionLevel="signature|installer" />
<!-- Allows receiving the usage of media resource e.g. video/audio codec and
graphic memory.
@@ -3178,6 +3220,11 @@
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by system apps when accessing restricted VR APIs.
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.RESTRICTED_VR_ACCESS"
+ android:protectionLevel="signature|preinstalled" />
+
<!-- Required to make calls to {@link android.service.vr.IVrManager}.
@hide -->
<permission android:name="android.permission.ACCESS_VR_MANAGER"
@@ -3482,11 +3529,15 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
- <service android:name="com.android.server.pm.BackgroundDexOptService"
+ <service android:name="com.android.server.BackgroundDexOptJobService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
+ <service android:name="com.android.server.PruneInstantAppsJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.storage.DiskStatsLoggingService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
diff --git a/core/res/res/color/text_color_secondary.xml b/core/res/res/color/text_color_secondary.xml
new file mode 100644
index 000000000000..60e0af80e04e
--- /dev/null
+++ b/core/res/res/color/text_color_secondary.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?attr/disabledAlpha"
+ android:color="?attr/colorForeground"/>
+ <item android:alpha="?attr/secondaryContentAlpha"
+ android:color="?attr/colorForeground"/>
+</selector>
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 516f25284282..182ba24f2216 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2016 The Android Open Source Project
+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.
@@ -14,24 +14,27 @@ Copyright (C) 2016 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="512dp"
- android:height="512dp"
+ android:width="480dp"
+ android:height="480dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#FFc7d4b6"
- android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
+ android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0"
+ android:fillAlpha="0.066"
+ android:fillColor="#000000"/>
<path
- android:fillColor="#FFfbd3cb"
- android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
+ android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0"
+ android:fillColor="#FFC107"/>
<path
- android:fillColor="#40000000"
- android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
+ android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z"
+ android:fillColor="#FE9F00"/>
<path
- android:fillColor="#40000000"
- android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
+ android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0"
+ android:fillColor="#FED44F"/>
<path
- android:fillColor="#FFe0e0d6"
- android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
+ android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z"
+ android:fillColor="#FFC107"/>
+ <path
+ android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0"
+ android:fillColor="#FFFFFF"/>
</vector>
-
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 5043cba3aa5e..89e42e6a82d5 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2016 The Android Open Source Project
+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.
@@ -16,21 +16,17 @@ Copyright (C) 2016 The Android Open Source Project
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#A0FFFFFF"
- android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12.0,12.0m-10.0,0.0a10.0,10.0,0,1,1,20.0,0.0a10.0,10.0,0,1,1,-20.0,0.0"
+ android:fillAlpha="0.25"/>
<path
- android:fillColor="#A0FFFFFF"
- android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12,22 C6.4771525,22 2,17.5228475 2,12 C2,6.4771525 6.4771525,2 12,2 C17.5228475,2 22,6.4771525 22,12 C22,17.5228475 17.5228475,22 12,22 Z M12,18.5 C15.5898509,18.5 18.5,15.5898509 18.5,12 C18.5,8.41014913 15.5898509,5.5 12,5.5 C8.41014913,5.5 5.5,8.41014913 5.5,12 C5.5,15.5898509 8.41014913,18.5 12,18.5 Z"/>
<path
- android:fillColor="#40000000"
- android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
- <path
- android:fillColor="#40000000"
- android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12,18.5 C8.41014913,18.5 5.5,15.5898509 5.5,12 C5.5,8.41014913 8.41014913,5.5 12,5.5 C15.5898509,5.5 18.5,8.41014913 18.5,12 C18.5,15.5898509 15.5898509,18.5 12,18.5 Z M12,15 C13.6568542,15 15,13.6568542 15,12 C15,10.3431458 13.6568542,9 12,9 C10.3431458,9 9,10.3431458 9,12 C9,13.6568542 10.3431458,15 12,15 Z"
+ android:fillAlpha="0.25"/>
</vector>
diff --git a/core/res/res/drawable/btn_event_material.xml b/core/res/res/drawable/btn_event_material.xml
new file mode 100644
index 000000000000..47c49cf2fa8c
--- /dev/null
+++ b/core/res/res/drawable/btn_event_material.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#90ffffff"
+ android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
+2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
+ <path android:pathData="M0 0h24v24H0z" />
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/btn_keyboard_key_material.xml b/core/res/res/drawable/btn_keyboard_key_material.xml
new file mode 100644
index 000000000000..14a9492f0023
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_material.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#90ffffff"
+ android:pathData="M20 5H4c-1.1 0-1.99 .9 -1.99 2L2 17c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0
+3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9
+7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z" />
+ <path
+ android:pathData="M0 0h24v24H0zm0 0h24v24H0z" />
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_0_bars.xml b/core/res/res/drawable/ic_signal_wifi_badged_0_bars.xml
index bd1eb41bee18..606b686bd59b 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_0_bars.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_0_bars.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_1_bar.xml b/core/res/res/drawable/ic_signal_wifi_badged_1_bar.xml
index aedb12c310e6..a4c5bc290d90 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_1_bar.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_1_bar.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_2_bars.xml b/core/res/res/drawable/ic_signal_wifi_badged_2_bars.xml
index 6f07cb5f5009..9c27833ed4e5 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_2_bars.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_2_bars.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_3_bars.xml b/core/res/res/drawable/ic_signal_wifi_badged_3_bars.xml
index c41a8ca8a47c..6d693f1cc94a 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_3_bars.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_3_bars.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_4_bars.xml b/core/res/res/drawable/ic_signal_wifi_badged_4_bars.xml
index ec0a52f6a43a..c48fa364b1e6 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_4_bars.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_4_bars.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_4k.xml b/core/res/res/drawable/ic_signal_wifi_badged_4k.xml
index 78bd0a060d0e..0868845bee92 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_4k.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_4k.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_hd.xml b/core/res/res/drawable/ic_signal_wifi_badged_hd.xml
index 78085c2f5b4d..657f5edf751c 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_hd.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_hd.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_ld.xml b/core/res/res/drawable/ic_signal_wifi_badged_ld.xml
index f660ab76e83a..e2971aa1cba0 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_ld.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_ld.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_signal_wifi_badged_sd.xml b/core/res/res/drawable/ic_signal_wifi_badged_sd.xml
index 43b865325a7e..b073be36e840 100644
--- a/core/res/res/drawable/ic_signal_wifi_badged_sd.xml
+++ b/core/res/res/drawable/ic_signal_wifi_badged_sd.xml
@@ -13,11 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="18"
android:viewportHeight="18"
- android:width="18dp"
- android:height="18dp">
+ android:width="26dp"
+ android:height="24dp">
<group
android:translateX="386"
android:translateY="-298">
diff --git a/core/res/res/drawable/ic_wifi_signal_0.xml b/core/res/res/drawable/ic_wifi_signal_0.xml
new file mode 100644
index 000000000000..e732a8dbbf20
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_signal_0.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_wifi_signal_1.xml b/core/res/res/drawable/ic_wifi_signal_1.xml
new file mode 100644
index 000000000000..3d006953fcaa
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_signal_1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.1,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.5,6.5L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.1,22.0l5.5,-6.8c-0.2,-0.2 -2.3,-1.9 -5.5,-1.9s-5.3,1.8 -5.5,1.9L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_signal_2.xml b/core/res/res/drawable/ic_wifi_signal_2.xml
new file mode 100644
index 000000000000..2cce9e90c02b
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_signal_2.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0l7.6,-9.4C20.3,12.4 17.4,10.0 13.0,10.0s-7.3,2.4 -7.6,2.7L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_signal_3.xml b/core/res/res/drawable/ic_wifi_signal_3.xml
new file mode 100644
index 000000000000..d3b3d3ad6025
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_signal_3.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0l9.2,-11.4c-0.4,-0.3 -3.9,-3.2 -9.2,-3.2s-8.9,3.0 -9.2,3.2L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_signal_4.xml b/core/res/res/drawable/ic_wifi_signal_4.xml
new file mode 100644
index 000000000000..aca4551044ec
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_signal_4.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/resolver_icon_placeholder.xml b/core/res/res/drawable/resolver_icon_placeholder.xml
new file mode 100644
index 000000000000..049cfeecc4c6
--- /dev/null
+++ b/core/res/res/drawable/resolver_icon_placeholder.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+ <solid android:color="#10000000"/>
+ <size android:width="36dp" android:height="36dp"/>
+</shape> \ No newline at end of file
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 70833d6d757e..8b95f9f814aa 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -15,28 +15,17 @@
limitations under the License.
-->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layoutDirection="ltr">
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <!-- Provides a background for the time layout that extends into the button bar area. -->
- <com.android.internal.widget.DrawingSpace
+ <LinearLayout
android:id="@+id/time_header"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_column="@dimen/time_picker_column_start_material"
- android:layout_row="0"
- android:layout_rowSpan="3"
- android:layout_gravity="center|fill"
- android:layoutDirection="locale" />
-
- <RelativeLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_column="@dimen/time_picker_column_start_material"
- android:layout_row="1"
- android:layout_gravity="center|fill"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingEnd="?attr/dialogPreferredPadding">
@@ -44,10 +33,8 @@
android:id="@+id/time_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_centerInParent="true"
android:paddingTop="@dimen/timepicker_radial_picker_top_margin"
- android:layout_marginBottom="-12dp">
+ android:orientation="horizontal">
<!-- The hour should always be to the left of the separator,
regardless of the current locale's layout direction. -->
@@ -125,38 +112,71 @@
android:includeFontPadding="false"
android:button="@null" />
</RadioGroup>
- </RelativeLayout>
+ </LinearLayout>
- <ViewStub
- android:id="@id/topPanel"
- android:layout="@layout/alert_dialog_title_material"
+ <TextView
+ android:visibility="gone"
+ android:id="@+id/input_header"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_column="@dimen/time_picker_column_end_material"
- android:layout_row="0"
- android:layout_gravity="top|fill_horizontal"
- android:layoutDirection="locale" />
-
- <android.widget.RadialTimePickerView
- android:id="@+id/radial_picker"
- android:layout_width="@dimen/timepicker_radial_picker_dimen"
- android:layout_height="@dimen/timepicker_radial_picker_dimen"
- android:layout_column="@dimen/time_picker_column_end_material"
- android:layout_row="1"
- android:layout_rowWeight="1"
- android:layout_gravity="center|fill"
- android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
- android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
- android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
- android:layoutDirection="locale" />
-
- <ViewStub
- android:id="@id/buttonPanel"
- android:layout="@layout/alert_dialog_button_bar_material"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:paddingStart="@dimen/dialog_padding_material"
+ android:paddingEnd="@dimen/dialog_padding_material"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:includeFontPadding="false"
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputHeader"
+ android:text="@string/time_picker_header_text"/>
+
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_column="@dimen/time_picker_column_end_material"
- android:layout_row="2"
- android:layout_gravity="bottom|fill_horizontal"
- android:layoutDirection="locale" />
-</GridLayout>
+ android:orientation="vertical">
+
+ <android.widget.RadialTimePickerView
+ android:id="@+id/radial_picker"
+ android:layout_width="@dimen/timepicker_radial_picker_dimen"
+ android:layout_height="@dimen/timepicker_radial_picker_dimen"
+ android:layout_gravity="center|fill"
+ android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+ android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+ android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
+ android:layoutDirection="locale" />
+
+ <android.widget.TextInputTimePickerView
+ android:id="@+id/input_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <ImageButton
+ android:id="@+id/toggle_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:padding="12dp"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:tint="?attr/colorControlNormal"
+ android:src="@drawable/btn_keyboard_key_material"
+ android:contentDescription="@string/time_picker_text_input_mode_description" />
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ <ViewStub
+ android:id="@id/buttonPanel"
+ android:layout="@layout/alert_dialog_button_bar_material"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layoutDirection="locale" />
+ </LinearLayout>
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
new file mode 100644
index 000000000000..d55a01235fcf
--- /dev/null
+++ b/core/res/res/layout/autofill_save.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- TODO(b/33197203) remove hardcoded color once color is final -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip"
+ android:background="#FDF8C8">
+
+ <!-- TODO(b/33197203) use.R.string once final wording is done -->
+ <TextView
+ android:id="@+id/autofill_save_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Save for autofill?"
+ android:singleLine="true"/>
+
+ <TextView
+ android:id="@+id/autofill_save_no"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/autofill_save_title"
+ android:layout_toLeftOf="@+id/autofill_save_yes"
+ android:layout_marginRight="16dip"
+ android:text="No thanks"
+ android:textAllCaps="true"
+ android:singleLine="true"/>
+
+ <TextView
+ android:id="@+id/autofill_save_yes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/autofill_save_title"
+ android:layout_alignParentRight="true"
+ android:text="Save"
+ android:textAllCaps="true"
+ android:singleLine="true"/>
+
+</RelativeLayout>
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index d8dd447e6a74..7dee2af3abbd 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -53,8 +53,7 @@
android:visibility="gone"
android:scaleType="fitCenter"
android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"
- />
+ android:layout_alignParentLeft="true"/>
<TextView android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 1f71a180cdf4..0dfeb6286fb3 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -20,10 +20,11 @@
android:id="@+id/notification_header"
android:orientation="horizontal"
android:layout_width="wrap_content"
- android:layout_height="53dp"
+ android:layout_height="48dp"
android:clipChildren="false"
android:paddingTop="10dp"
- android:paddingBottom="16dp"
+ android:paddingBottom="11dp"
+ android:layout_marginBottom="5dp"
android:paddingStart="@dimen/notification_content_margin_start"
android:paddingEnd="16dp">
<com.android.internal.widget.CachingIconView
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index 1ae317c7e6dd..e2c68b51b733 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -52,19 +52,18 @@
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textSize="20sp"
- android:textColor="@android:color/white"
+ android:textColor="#e6fafafa"
/>
<TextView android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:paddingBottom="@dimen/notification_content_margin_bottom"
android:textAppearance="@style/TextAppearance.Material.Notification"
android:singleLine="false"
android:layout_weight="1"
android:gravity="top"
android:visibility="gone"
- android:textSize="18sp"
- android:textColor="@android:color/white"
+ android:textSize="16sp"
+ android:textColor="#ccfafafa"
android:layout_marginTop="4dp"
/>
</LinearLayout>
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 02cd8cdd9b8e..bed80edf0ee7 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -24,6 +24,7 @@
android:layout_width="match_parent">
<LinearLayout
+ android:id="@+id/prefs_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0px"
@@ -61,8 +62,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="@integer/preferences_right_pane_weight"
- android:orientation="vertical"
- android:visibility="gone" >
+ android:orientation="vertical">
<!-- Breadcrumb inserted here, in certain screen sizes. In others, it will be an
empty layout or just padding, and PreferenceActivity will put the breadcrumbs in
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
index 1bc527e26b48..37b411918ef6 100644
--- a/core/res/res/layout/preference_list_content_material.xml
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -24,6 +24,7 @@
android:layout_width="match_parent">
<LinearLayout
+ android:id="@+id/prefs_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0px"
@@ -64,8 +65,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="@integer/preferences_right_pane_weight"
- android:orientation="vertical"
- android:visibility="gone" >
+ android:orientation="vertical">
<!-- Breadcrumb inserted here, in certain screen sizes. In others, it will be an
empty layout or just padding, and PreferenceActivity will put the breadcrumbs in
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 02dc2ede430d..8101183d4e24 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -45,6 +45,7 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="20dp"
+ android:src="@drawable/resolver_icon_placeholder"
android:scaleType="fitCenter" />
<TextView
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 72588c71b7d9..0c462fda9235 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -43,7 +43,8 @@
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:focusable="true"
- android:contentDescription="@string/searchview_description_search" />
+ android:contentDescription="@string/searchview_description_search"
+ android:tooltipText="@string/searchview_description_search" />
<LinearLayout
android:id="@+id/search_edit_frame"
diff --git a/core/res/res/layout/time_picker_material.xml b/core/res/res/layout/time_picker_material.xml
index 37a7384608ce..75973798219e 100644
--- a/core/res/res/layout/time_picker_material.xml
+++ b/core/res/res/layout/time_picker_material.xml
@@ -34,4 +34,53 @@
android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
+ <TextView
+ android:visibility="gone"
+ android:id="@+id/input_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/dialog_padding_material"
+ android:paddingEnd="@dimen/dialog_padding_material"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:includeFontPadding="false"
+ android:fontFamily="sans-serif-medium"
+ android:textSize="34sp"
+ android:textColor="@color/white"
+ android:text="@string/time_picker_header_text"/>
+ <android.widget.TextInputTimePickerView
+ android:id="@+id/input_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <ImageButton
+ android:id="@+id/toggle_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:padding="12dp"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:tint="?attr/colorControlNormal"
+ android:src="@drawable/btn_keyboard_key_material"
+ android:contentDescription="@string/time_picker_text_input_mode_description" />
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ <ViewStub
+ android:id="@id/buttonPanel"
+ android:layout="@layout/alert_dialog_button_bar_material"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layoutDirection="locale" />
+ </LinearLayout>
+
</LinearLayout>
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
new file mode 100644
index 000000000000..f17b80ee2f39
--- /dev/null
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <TextView
+ android:id="@+id/top_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="26dp"
+ android:layout_marginBottom="8dp"
+ android:text="@string/time_picker_prompt_label"
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.PromptLabel" />
+
+ <RelativeLayout
+ android:id="@+id/input_block"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/top_label"
+ android:layoutDirection="ltr">
+ <EditText
+ android:id="@+id/input_hour"
+ android:layout_width="50dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+ <TextView
+ android:id="@+id/label_hour"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/input_hour"
+ android:layout_alignStart="@id/input_hour"
+ android:text="@string/time_picker_hour_label"/>
+
+ <TextView
+ android:id="@+id/input_separator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignEnd="@id/input_hour"
+ android:layout_alignBaseline="@id/input_hour"
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+
+ <EditText
+ android:id="@+id/input_minute"
+ android:layout_width="50dp"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@id/input_hour"
+ android:layout_toEndOf="@id/input_separator"
+ android:inputType="number"
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+ <TextView
+ android:id="@+id/label_minute"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/input_minute"
+ android:layout_alignStart="@id/input_minute"
+ android:text="@string/time_picker_minute_label"/>
+
+ <TextView
+ android:visibility="invisible"
+ android:id="@+id/label_error"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/input_hour"
+ android:layout_alignStart="@id/input_hour"
+ android:textColor="?attr/textColorError"
+ android:text="@string/time_picker_input_error" />
+ </RelativeLayout>
+ <Spinner
+ android:id="@+id/am_pm_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@id/input_block"
+ android:layout_alignParentEnd="true"/>
+
+</merge> \ No newline at end of file
diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin
deleted file mode 100644
index acd79939b105..000000000000
--- a/core/res/res/raw/accessibility_gestures.bin
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values-af-watch/styles_material.xml b/core/res/res/values-af-watch/styles_material.xml
deleted file mode 100644
index 80a5fa631ffe..000000000000
--- a/core/res/res/values-af-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidate"</font></string>
-</resources>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c00424351ce2..46d0745978f7 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Die werkprofiel se administrasieprogram ontbreek of is korrup. Gevolglik is jou werkprofiel en verwante data uitgevee. Kontak jou administrateur vir bystand."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Jou werkprofiel is nie meer op hierdie toestel beskikbaar nie."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Netwerkverkeer word gemonitor"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tik vir meer besonderhede"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tik om meer te wete te kom"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Jou toestel sal uitgevee word"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Die administrasieprogram kort komponente of is korrup en kan nie gebruik word nie. Jou toestel sal nou uitgevee word. Kontak jou administrateur vir bystand."</string>
<string name="me" msgid="6545696007631404292">"Ek"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Beheer die vertoonskerm se zoemvlak en posisionering."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Voer gebare uit"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tik, swiep, knyp en ander gebare uitvoer."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Vingerafdrukgebare"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan gebare wat op die toestel se vingerafdruksensor uitgevoer word, vasvang"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktiveer of verander statusbalk"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Laat die program toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"wees die statusbalk"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Laat die program toe om die kitsboodskapdiens te gebruik om oproepe sonder jou ingryping te maak."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lees foonstatus en identiteit"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"roeteer oproepe deur die stelsel"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Laat die program toe om sy oproepe deur die stelsel te stuur om die oproepervaring te verbeter."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lees foonnommer"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gee die program toegang tot die toestel se foonnommer."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"verhoed dat tablet slaap"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Vee uit"</string>
<string name="inputMethod" msgid="1653630062304567879">"Invoermetode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string>
+ <string name="email" msgid="4560673117055050403">"E-pos"</string>
+ <string name="dial" msgid="2275093056198652749">"Bel"</string>
+ <string name="map" msgid="5441053548030107189">"Kaart"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nie genoeg berging vir die stelsel nie. Maak seker jy het 250 MB spasie beskikbaar en herbegin."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tik vir meer opsies."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-ontfouting te deaktiveer."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Kies om USB-ontfouting te deaktiveer."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Neem tans foutverslag …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deel foutverslag?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deel tans foutverslag …"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Laat \'n program toe om installasiesessies te lees. Dit laat dit toe om besonderhede van aktiewe pakketinstallasies te sien."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"versoek installeerpakkette"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Laat \'n program toe om te versoek dat pakkette geïnstalleer word."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"versoek uitvee van pakkette"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Laat \'n program toe om te versoek dat pakkette uitgevee word."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"vra om batteryoptimerings te ignoreer"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Laat \'n program toe om toestemming te vra om batteryoptimerings vir daardie program ignoreer."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Klop twee keer vir zoembeheer"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou aan met twee vingers inhou om toeganklikheid te aktiveer."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Toeganklikheid geaktiveer."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Toeganklikheidskortpad is AAN"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Skakel <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aan of af deur albei volumeknoppies vir 3 sekondes in te hou.\n\nJy kan die diens in Instellings &gt; Toeganklikheid verander."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Skakel kortpad af"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Los aan"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
<string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Skakel tans oor na <xliff:g id="NAME">%1$s</xliff:g> …"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Meld <xliff:g id="NAME">%1$s</xliff:g> tans af …"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferensie-oproep"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Nutswenk"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Speletjies"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musiek en oudio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Flieks en video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto\'s en prente"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosiaal en kommunikasie"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Nuus en tydskrifte"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kaarte en navigasie"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktiwiteit"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Toestelberging"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-am-watch/styles_material.xml b/core/res/res/values-am-watch/styles_material.xml
deleted file mode 100644
index 5ec383a896da..000000000000
--- a/core/res/res/values-am-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"እጩዎች"</font></string>
-</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 24feab7c1fb2..45206873f752 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"የስራ መገለጫ አስተዳዳሪ መተግበሪያው ወይም ይጎድላል ወይም ተበላሽቷል። በዚህ ምክንያት የስራ መገለጫዎ እና ተዛማጅ ውሂብ ተሰርዘዋል። እርዳታን ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"የስራ መገለጫዎ ከዚህ በኋላ በዚህ መሳሪያ ላይ አይገኝም።"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"የአውታረ መረብ ክትትል እየተደረገበት ነው"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"ተጨማሪ ዝርዝሮችን ለማግኘት መታ ያድርጉ"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"የበለጠ ለመረዳት መታ ያድርጉ"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"የአስተዳዳሪ መተግበሪያው ክፍሎች ይጎድሉታል ወይም ተበላሽቷል፣ እና ስራ ላይ መዋል አይችልም። የእርስዎ መሣሪያ አሁን ይደመሰሳል። እርዳታ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="me" msgid="6545696007631404292">"እኔ"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"የማሳያውን የማጉያ ደረጃ እና አቀማመጥ ይቆጣጠሩ።"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"የጣት ምልክቶችን ያከናውኑ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"መታ ማድረግ፣ ማንሸራተት፣ መቆንጠጥ እና ሌሎች የጣት ምልክቶችን ማከናወን ይችላል።"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"የጣት አሻራ ምልክቶች"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"በመሣሪያዎቹ የጣት አሻራ ዳሳሽ ላይ የተከናወኑ የጣት ምልክቶችን መያዝ ይችላል።"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"የሁኔቴ አሞሌ አቦዝን ወይም ቀይር"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"የስርዓት አዶዎችን ወደ ሁኔታ አሞሌ ላለማስቻል ወይም ለማከል እና ለማስወገድ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"የሁኔታ አሞሌ መሆን"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"መተግበሪያው ያለእርስዎ ጣልቃ ገብነት ጥሪዎችን ለማድረግ የአይኤምኤስ አገልግሎቱን እንዲጠቀም ያስችለዋል።"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"የስልክ ሁኔታና ማንነት አንብብ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"መተግበሪያው የመሳሪያውን የስልክ ባህሪያት ላይ እንዲደርስ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው የስልክ ቁጥሩን እና የመሳሪያውን መታወቂያዎች፣ ጥሪ የነቃ እንደሆነ፣ እና በጥሪ የተገናኘውን የሩቅ ቁጥር እንዲወስን ይፈቅድለታል።"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ጥሪዎችን በስርዓቱ በኩል አዙር"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"መተግበሪያው የጥሪ ተሞክሮን እንዲያሻሽል ጥሪዎቹን በስርዓቱ በኩል እንዲያዞር ያስችለዋል።"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ስልክ ቁጥር አንብብ"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"መተግበሪያው የመሣሪያውን ስልክ ቁጥር እንዲደርስበት ይፈቅድለታል።"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ሰርዝ"</string>
<string name="inputMethod" msgid="1653630062304567879">"ግቤት ስልት"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"የፅሁፍ እርምጃዎች"</string>
+ <string name="email" msgid="4560673117055050403">"ኢሜይል"</string>
+ <string name="dial" msgid="2275093056198652749">"ደውል"</string>
+ <string name="map" msgid="5441053548030107189">"ካርታ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ለስርዓቱ የሚሆን በቂ ቦታ የለም። 250 ሜባ ነጻ ቦታ እንዳለዎት ያረጋግጡና ዳግም ያስጀምሩ።"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"ለተጨማሪ አማራጮች መታ ያድርጉ።"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"የዩኤስቢ ማረሚያን ለማሰናከል መታ ያድርጉ።"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ማረሚያ ላለማንቃት ምረጥ።"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"መተግበሪያው የመጫን ክፍለ ጊዜዎችን እንዲያነብ ይፈቅድለታል። ይህም ስለ ገቢር የጥቅል ጭነቶች ዝርዝር መረጃን እንዲያይ ይፈቅድለታል።"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"የጭነት ጥቅሎችን መጠየቅ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"መተግበሪያ የጥቅሎች መጫንን እንዲጠይቅ ይፈቅዳል።"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"የጥቅሎች ስረዛን ጠይቅ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"አንድ መተግበሪያ የጥቅሎች ስረዛን እንዲጠይቅ ይፈቅዳል።"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"የባትሪ ማትባቶችን ችላ ለማለት መጠየቅ"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"አንድ መተግበሪያ ለዚያ መተግበሪያ የባትሪ ማትባቶችን ችላ ለማለት እንዲጠይቅ ይፈቅድለታል።"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ለአጉላ መቆጣጠሪያ ሁለት ጊዜ ነካ አድርግ"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"አስወግድ"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ተደራሽነትን ለማንቃት ሁለት ጣቶችዎን ባሉበት ያቆዩዋቸው።"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ተደራሽነት ነቅቷል።"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ተደራሽነት ተሰርዟል።"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"የተደራሽነት አቋራጭ በርቷል"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ በመያዝ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ያብሩት ወይም ያጥፉት።\n\nአገልግሎቱን በቅንብሮች &gt; ተደራሽነት ውስጥ መቀየር ይችላሉ።"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"አቋራጩን አጥፋ"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"እንደበራ ተወው"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አብርቶታል"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አጥፍቶታል"</string>
<string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
<string name="user_switching_message" msgid="2871009331809089783">"ወደ <xliff:g id="NAME">%1$s</xliff:g> በመቀየር ላይ…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> በማውጣት ላይ…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ተሰናክሏል"</string>
<string name="conference_call" msgid="3751093130790472426">"የስብሰባ ጥሪ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"የመሣሪያ ጥቆማ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ጨዋታዎች"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"ሙዚቃ እና ኦዲዮ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ፊልሞች እና ቪዲዮ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ፎቶዎች እና ምስሎች"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"ማኅበራዊ እና መልእክት ልውውጥ"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ዜና እና መጽሔቶች"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"ካርታዎች እና ዳሰሳ"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ውጤታማነት"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"የመሣሪያ ማከማቻ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ar-watch/styles_material.xml b/core/res/res/values-ar-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ar-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f28d044c4d2f..95118c261f26 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -191,7 +191,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"تطبيق المشرف للملف الشخصي للعمل مفقود أو تالف لذا تم حذف الملف والبيانات ذات الصلة. اتصل بالمشرف للحصول على المساعدة."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"لم يعد ملفك الشخصي للعمل متاحًا على هذا الجهاز."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"تتم مراقبة حركة بيانات الشبكة"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"انقر للحصول على المزيد من التفاصيل"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"انقر لمعرفة المزيد من المعلومات"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"سيتم محو بيانات جهازك."</string>
<string name="factory_reset_message" msgid="4905025204141900666">"تطبيق المشرف فاقد لمكونات أو تالف ويتعذر استخدامه. سيتم محو بيانات جهازك الآن. اتصل بالمشرف للحصول على المساعدة."</string>
<string name="me" msgid="6545696007631404292">"أنا"</string>
@@ -290,6 +290,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"يمكنك التحكم في مستوى التكبير/التصغير للشاشة وتحديد الموضع."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"تنفيذ إيماءات"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"يمكن النقر والتمرير بسرعة والتصغير وتنفيذ إيماءات أخرى."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"إيماءات بصمات الإصبع"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"يمكن أن تلتقط الإيماءات التي تم تنفيذها على مستشعر بصمات الإصبع في الأجهزة."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"تعطيل شريط الحالة أو تعديله"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"للسماح للتطبيق بتعطيل شريط الحالة أو إضافة رموز نظام وإزالتها."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"العمل كشريط للحالة"</string>
@@ -394,6 +396,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"للسماح للتطبيق باستخدام خدمة الرسائل الفورية لإجراء المكالمات دون تدخل منك."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"قراءة حالة الهاتف والهوية"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"توجيه المكالمات من خلال النظام"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"يسمح للتطبيق بتوجيه المكالمات من خلال النظام لتحسين تجربة الاتصال."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"قراءة رقم الهاتف"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"للسماح للتطبيق بالوصول إلى رقم الهاتف على الجهاز."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
@@ -1027,6 +1031,9 @@
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
<string name="inputMethod" msgid="1653630062304567879">"طريقة الإرسال"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
+ <string name="email" msgid="4560673117055050403">"بريد إلكتروني"</string>
+ <string name="dial" msgid="2275093056198652749">"طلب"</string>
+ <string name="map" msgid="5441053548030107189">"خريطة"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
@@ -1221,6 +1228,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"انقر للحصول على المزيد من الخيارات."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏تم توصيل تصحيح أخطاء USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"‏انقر لتعطيل تصحيح أخطاء USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏اختيار تعطيل تصحيح أخطاء USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"جارٍ الحصول على تقرير الخطأ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"هل تريد مشاركة تقرير الخطأ؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"جارٍ مشاركة تقرير الخطأ…"</string>
@@ -1277,6 +1285,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"للسماح لأحد التطبيقات بقراءة جلسات التثبيت. ويسمح لك هذا بالاطلاع على تفاصيل بشأن عمليات تثبيت الحزم النشطة."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"طلب حزم التثبيت"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"للسماح لتطبيق ما بطلب تثبيت الحزم."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"طلب حذف الحِزم"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"للسماح لتطبيق ما بطلب حذف الحِزم."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"طلب تجاهل تحسينات البطارية"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"للسماح للتطبيق بطلب الإذن لتجاهل تحسينات البطارية في هذا التطبيق."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"اضغط مرتين للتحكم في التكبير/التصغير"</string>
@@ -1507,9 +1517,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"إزالة"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"اضغط بإصبعين لأسفل مع الاستمرار لتمكين تسهيل الدخول."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"تم تمكين إمكانية الدخول."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"تم إلغاء تسهيل الدخول."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"اختصار إمكانية الوصول قيد التشغيل"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"يمكنك تشغيل خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g> أو إيقافها عن طريق الضغط باستمرار على مفتاحي مستوى الصوت على حد سواء لمدة 3 ثوانٍ.\n\nيمكنك تغيير الخدمة في الإعدادات وإمكانية الوصول."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"إيقاف الاختصار"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ترك الاختصار في وضع التشغيل"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"شغَّل اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"أوقف اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"جارٍ التبديل إلى <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"جارٍ الخروج <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1795,20 +1808,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"تم تعطيل <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"مكالمة جماعية"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"تلميح"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"الألعاب"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"الموسيقى والصوت"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"الأفلام والفيديو"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"الصور"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"التواصل الاجتماعي"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"الأخبار والمجلات"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"الخرائط والتنقل"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"الإنتاجية"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"السعة التخزينية للجهاز"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-az-watch/styles_material.xml b/core/res/res/values-az-watch/styles_material.xml
deleted file mode 100644
index b6212666e113..000000000000
--- a/core/res/res/values-az-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"namizədlər"</font></string>
-</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 9b55a5511050..cf377b2d9aa9 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"İnzibatçı proqramın iş profili ya yoxdur, ya da korlanıb. Nəticədə iş profiliniz və onunla bağlı məlumatlar silinib. Yardım üçün inzibatçınızla əlaqə saxlayın."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"İş profiliniz daha bu cihazda əlçatan deyil."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Şəbəkə trafikinə nəzarət edilir"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Ətraflı məlumat üçün klikləyin"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Ətraflı məlumat üçün klikləyin"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Cihazınız təmizlənəcəkdir"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"İnzibatçı proqramında komponentlər yoxdur və ya korlanıb və istifadə oluna bilməz. Cihazınız indi təmizlənəcəkdir. Yardım üçün inzibatçınızla əlaqə saxlayın."</string>
<string name="me" msgid="6545696007631404292">"Mən"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekran yaxınlaşdırma səviyyəsi və yerləşdirməsinə nəzarət edin."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Jestlər ilə əməliyyat aparın"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Digər jestlərə tıklaya, sürüşdürə və əməliyyat apara bilərsiniz."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Barmaq izi işarələri"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Cihazların barmaq izi sensorunda olan işarələri əldə edə bilər"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"status panelini deaktivləşdir və ya dəyişdir"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tətbiqə status panelini deaktiv etməyə və ya sistem ikonalarını əlavə etmək və ya silmək imkanı verir."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"status paneli edin"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tətbiqə müdaxilə olmadan zəng etmək üçün IMS xidmətindən istifadə etməyə imkan verir."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefon statusunu və identifikasiyanı oxuyur"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tətbiqə cihazın telefon funksiyalarına giriş icazəsi verir. Belə icazəli tətbiq bu telefonun nömrəsini və cihaz İD\'ni, zəngin aktiv olub-olmadığını və zəng edilən nömrəni müəyyən edə bilər."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"zəngləri sistem üzərindən yönləndirin"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Tətbiqə, zəng təcrübəsini yaxşılaşdırmaq üçün, zəngləri sistem üzərindən yönləndirməyə icazə verilir."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon nömrəsini oxuyun"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Tətbiqə cihazın telefon nömrəsinə daxil olmağa icazə verir."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"planşetin yuxu rejiminin qarşısını almaq"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Sil"</string>
<string name="inputMethod" msgid="1653630062304567879">"Daxiletmə metodu"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Mətn əməliyyatları"</string>
+ <string name="email" msgid="4560673117055050403">"E-poçt"</string>
+ <string name="dial" msgid="2275093056198652749">"Yığım"</string>
+ <string name="map" msgid="5441053548030107189">"Xəritə"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Yaddaş yeri bitir"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bəzi sistem funksiyaları işləməyə bilər"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem üçün yetərincə yaddaş ehtiyatı yoxdur. 250 MB yaddaş ehtiyatının olmasına əmin olun və yenidən başladın."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Əlavə seçimlər üçün tıklayın."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB debaqı deaktivasiya etmək üçün tıklayın."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USb debaqı deaktivasiya etməyi seçin."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Baq hesabatı verilir..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Baq hesabatı paylaşılsın?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Baq hesabatı paylaşılır..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tətbiqə quraşdırma sessiyalarını oxumağa yardım edir. Bu da aktiv paket quraşdırmaları haqqında məlumatları görməyə imkan verir."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paketləri quraşdırma sorğusu"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tətbiqə paketləri quraşdırma sorğusu göndərməyə icazə verir."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"paketlərin silinmə sorğusu"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Tətbiqə paketlərin silinməsi sorğusunu göndərməyə icazə verir."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"batareya optimallaşdırmasını iqnor etmək üçün soruşun"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Tatareya optimallaşdırılmasını o tətbiq üçün iqnor edilməsinə icazə vermək məqsədilə soruşmağa tətbiqə icazə verilir."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zoom kontrolu üçün iki dəfə toxunun"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Yığışdır"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Əlçatımlığı aktivləşdirmək üçün iki barmağınızı basılı saxlayın."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Əlçatımlılıq aktivləşdirildi"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Giriş imkanı ləğv edilib."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Əlçatımlıq Qısayolu Aktivdir"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Hər iki səs düyməsini 3 saniyə basıb saxlamaqla <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv və ya deaktiv edin.\n\nXidməti Ayarlar &gt; Əlçatımlıq bölməsində dəyişdirə bilərsiniz."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Qısayolu Deaktiv Edin"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Açıq saxlayın"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
<string name="user_switched" msgid="3768006783166984410">"Cari istifadəçi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> adına keçirilir…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> çıxır..."</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
<string name="conference_call" msgid="3751093130790472426">"Konfrans Zəngi"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Oyunlar"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musiqi və Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmlər və Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotolar və Şəkillər"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosial və Kommunikasiya"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Xəbər və Jurnallar"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Xəritə və Naviqasiya"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Məhsuldarlıq"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Cihaz yaddaşı"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn-watch/styles_material.xml b/core/res/res/values-b+sr+Latn-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-b+sr+Latn-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b0c62e92cad3..e56d938e8b33 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Administratorska aplikacija poslovnog profila nedostaje ili je oštećena. Zbog toga su vaš poslovni profil i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profil za Work više nije dostupan na ovom uređaju."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Mrežni saobraćaj se prati"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Dodirnite za više detalja"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Dodirnite da biste saznali više"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Uređaj će biti obrisan"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administratorskoj aplikaciji nedostaju neke komponente ili je oštećena i ne može da se koristi. Uređaj će sada biti obrisan. Obratite se administratoru za pomoć."</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obavljanje pokreta"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može da dodiruje, lista, skuplja prikaz i obavlja druge pokrete."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti za otisak prsta"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Može da registruje pokrete na senzoru za otisak prsta na uređaju."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmena statusne trake"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji da onemogući statusnu traku ili da dodaje i uklanja sistemske ikone."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"funkcionisanje kao statusna traka"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Dozvoljava aplikaciji da koristi uslugu razmene trenutnih poruka da bi upućivala pozive bez vaše intervencije."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Dozvoljava aplikaciji da pristupa funkcijama telefona na uređaju. Ova dozvola omogućava aplikaciji da utvrdi broj telefona i ID-ove uređaja, zatim da li je poziv aktivan, kao i broj daljinskog uređaja sa kojim je uspostavljen poziv."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"preusmeravanje poziva preko sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Dozvoljava aplikaciji da preusmerava pozive preko sistema da bi poboljšala doživljaj pozivanja."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitanje broja telefona"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Dozvoljava aplikaciji da pristupa broju telefona na uređaju."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje prelaska tableta u stanje spavanja"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
+ <string name="email" msgid="4560673117055050403">"Pošalji imejl"</string>
+ <string name="dial" msgid="2275093056198652749">"Pozovi"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
@@ -1161,6 +1168,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za još opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
@@ -1217,6 +1225,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instaliranja. To joj dozvoljava da vidi detalje o aktivnim instalacijama paketa."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketa za instaliranje"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava da aplikacija zahteva instalaciju paketa."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"zahtevanje brisanja paketa"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Omogućava da aplikacija zahteva brisanje paketa."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"traženje dozvole za ignorisanje optimizacija baterije"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Dozvoljava aplikaciji da traži dozvolu za ignorisanje optimizacija baterije za tu aplikaciju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu zumiranja"</string>
@@ -1444,9 +1454,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Držite sa dva prsta da biste omogućili pristupačnost."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pristupačnost je omogućena."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost je otkazana."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Prečica za pristupačnost je UKLJUČENA"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Uključite ili isključite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tako što ćete istovremeno zadržati oba dugmeta za jačinu zvuka 3 sekunde.\n\nMožete da promenite uslugu u odeljku Podešavanja &gt; Pristupačnost."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Isključi prečicu"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ostavi uključeno"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Aktuelni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Prebacivanje na <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Odjavljuje se <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1702,20 +1715,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Objašnjenje"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Igre"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzika i audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmovi i video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Slike"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Društvene mreže i komunikacija"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Novosti i časopisi"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mape i navigacija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memorijski prostor uređaja"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-be-watch/styles_material.xml b/core/res/res/values-be-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-be-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 50cfa824a0c8..6383c39b1939 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Праграма для адміністравання рабочага профілю адсутнічае або пашкоджана. У выніку гэтага ваш рабочы профіль і звязаныя з ім даныя былі выдаленыя. Звярніцеся па дапамогу да адміністратара."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Ваш працоўны профіль больш не даступны на гэтай прыладзе."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Сеткавы трафік адсочваецца"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Дакраніцеся для атрымання больш падрабязнай інфармацыі"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Дакраніцеся, каб даведацца больш"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Даныя вашай прылады будуць сцерты"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Праграма для адміністравання не можа быць выкарыстана, таму што ў яе адсутнічаюць кампаненты або яна пашкоджана. Зараз даныя вашай прылады будуць сцерты. Звярніцеся па дапамогу да адміністратара."</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Кіраваць маштабам дысплэя і пазіцыянаваннем."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Выконваць жэсты"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна кранаць, праводзіць пальцам, маштабаваць шчыпком, а таксама выконваць іншыя жэсты."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жэсты адбіткаў пальцаў"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Можа распазнаваць жэсты на сканеры адбіткаў пальцаў прылады."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"быць панэллю стану"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дазваляе праграмам выкарыстоўваць службу IMS, каб рабіць выклікі без вашага ўмяшання."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"чытанне статусу тэлефона і ідэнтыфікацыя"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дазваляе прыкладанням атрымлiваць доступ да функцый тэлефона на прыладзе. Дзякуючы гэтаму дазволу прыкладанне можа вызначаць iдэнтыфiкатары нумару тэлефона i прылады, незалежна ад таго, цi актыўны выклiк, i аддалены нумар, на якi робiцца выклiк."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"перанакіраванне выклікаў праз сістэму"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Дазваляе праграме перанакіроўваць выклікі праз сістэму ў мэтах паляпшэння выклікаў."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"чытаць нумар тэлефона"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Праграма зможа атрымліваць доступ да тэлефоннага нумара прылады."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Выдалiць"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метад уводу"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Дзеянні з тэкстам"</string>
+ <string name="email" msgid="4560673117055050403">"Электронная пошта"</string>
+ <string name="dial" msgid="2275093056198652749">"Набор нумара"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Дакраніцеся, каб атрымаць іншыя параметры."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Адладка па USB падключана"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Дакраніцеся, каб адключыць адладку па USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Выберыце, каб адключыць адладку USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Стварэнне справаздачы пра памылку…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Падзяліцца справаздачай пра памылку?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Перадача справаздачы пра памылку..."</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дазваляе праграме счытваць сеансы ўсталёўкі. Гэта дазваляе ёй праглядаць інфармацыю аб актыўных усталёўках пакета."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"запытваць усталёўку пакетаў"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Дазваляе праграме запытваць усталёўку пакетаў."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"запытваць выдаленне пакетаў"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Дазваляе праграме запытваць выдаленне пакетаў."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"запытваць дазвол на ігнараванне аптымізацыі акумулятара"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Дазваляе праграме запытваць дазвол на ігнараванне аптымізацыі акумулятара для гэтай праграмы."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Націсніце двойчы, каб кіраваць маштабаваннем"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдалiць"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Даступнасць адменена."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Камбінацыя хуткага доступу для спецыяльных магчымасцей АКТЫВАВАНА"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Уключайце ці адключайце <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утрымліваючы абедзве кнопкі рэгулявання гучнасці націснутымі на працягу 3 секунд.\n\nВы можаце змяніць сэрвіс у меню \"Налады &gt; Спецыяльныя магчымасці\"."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Дэактываваць камбінацыю хуткага доступу"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Пакінуць актываванай"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў уключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў адключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
<string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Пераход да <xliff:g id="NAME">%1$s</xliff:g>..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> выходзіць з сістэмы…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Адключаны <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Канферэнц-выклік"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Падказка"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Гульні"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музыка і аўдыя"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Фільмы і відэа"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Фота і відарысы"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Сацыяльнае і сувязь"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Навіны і часопісы"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карты і навігацыя"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Прадукцыйнасць"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Сховішча на прыладзе"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-bg-watch/styles_material.xml b/core/res/res/values-bg-watch/styles_material.xml
deleted file mode 100644
index 89c3366d183f..000000000000
--- a/core/res/res/values-bg-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"кандидати"</font></string>
-</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4b391296b728..1238e2cef8a7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Администраторското приложение на служебния потребителски профил липсва или е повредено. В резултат на това той и свързаните с него данни са изтрити. За съдействие се свържете с администратора си."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Служебният ви потребителски профил вече не е налице на това устройство."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Трафикът в мрежата се следи"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Докоснете за още подробности"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Докоснете, за да научите повече"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Данните на устройството ви ще бъдат изтрити"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"В администраторското приложение липсват компоненти или то е невалидно и не може да се използва. Сега данните на устройството ви ще бъдат изтрити. Свържете се с администратора си за съдействие."</string>
<string name="me" msgid="6545696007631404292">"Аз"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управление на нивото на мащаба и позиционирането на дисплея."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Извършване на жестове"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можете да докосвате, да прекарвате пръст, да събирате пръсти и да извършвате други жестове."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жестове за отпечатък"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да улавя жестовете, извършени върху сензора за отпечатъци на устройството."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"деактивиране или промяна на лентата на състоянието"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Разрешава на приложението да деактивира лентата на състоянието или да добавя и премахва системни икони."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"изпълняване на ролята на лента на състоянието"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Разрешава на приложението да използва услугата за незабавни съобщения за извършване на обаждания без намеса от ваша страна."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"четене на състоянието и идентификационните данни на телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Разрешава на приложението достъп до телефонните функции на устройството. Това разрешение позволява на приложението да определя телефонния номер и идентификационния номер на устройството, дали се води разговор и отдалечения номер, до който е установена връзка с обаждането."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"маршрутизиране на обажданията чрез системата"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Разрешава на приложението да маршрутизира обажданията си чрез системата с цел подобряване на свързаната с тях практическа работа."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"четене на телефонния номер"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Разрешава на приложението да осъществява достъп до телефонния номер на устройството."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"предотвратяване на спящия режим на таблета"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Изтриване"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метод на въвеждане"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Действия с текста"</string>
+ <string name="email" msgid="4560673117055050403">"Имейл"</string>
+ <string name="dial" msgid="2275093056198652749">"Набиране"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"За системата няма достатъчно място в хранилището. Уверете се, че имате свободни 250 МБ, и рестартирайте."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Докоснете за още опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Докоснете, за да деактивирате отстраняването на грешки през USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изберете, за да деактивирате отстраняването на грешки през USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Сигналът за програмна грешка се извлича…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Разрешава на приложението да чете сесии за инсталиране. Това му позволява да вижда подробности за активните инсталирания на пакети."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"заявка на пакети за инсталиране"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Разрешава на приложението да заявява инсталиране на пакети."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"заявяване на изтриване на пакети"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Разрешава на приложението да заявява изтриване на пакети."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"искане за пренебрегване на оптимизациите на батерията"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Разрешава на дадено приложение да иска разрешение за пренебрегване на свързаните с него оптимизации на батерията."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Докоснете двукратно за управление на промяната на мащаба"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Приемател за виртуална реалност"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Приемател за VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Услуга за класифициране на известията"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Премахване"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Продължете да натискате с два пръста, за да активирате функцията за достъпност."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Достъпността е активирана."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Функцията за достъпност е анулирана."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Прекият път за достъпност е ВКЛЮЧЕН"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Включете или изключете <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, като задържите натиснати за 3 секунди бутоните за силата на звука.\n\nМожете да промените услугата от „Настройки“ &gt; „Достъпност“."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Изключване на прекия път"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Да остане включен"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Прекият път за достъпност включи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Прекият път за достъпност изключи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Превключва се към <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> излиза…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>: Деактивирано"</string>
<string name="conference_call" msgid="3751093130790472426">"Конферентно обаждане"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Игри"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музика и аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Филми и видеоклипове"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Снимки и изображения"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Социални мрежи и комуникация"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Новини и списания"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карти и навигация"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Производителност"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Хранилище на устройството"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-bn-watch/styles_material.xml b/core/res/res/values-bn-watch/styles_material.xml
deleted file mode 100644
index cd5990268bf9..000000000000
--- a/core/res/res/values-bn-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"প্রার্থীরা"</font></string>
-</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b6f7a12a9e6c..9bedf582637f 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -63,8 +63,8 @@
<string name="needPuk2" msgid="4526033371987193070">"সিম কার্ড অবরোধ মুক্ত করতে PUK2 লিখুন৷"</string>
<string name="enablePin" msgid="209412020907207950">"অসফল, সিম/RUIM লক সক্ষম করুন৷"</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
- <item quantity="one">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
- <item quantity="other">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
+ <item quantity="one">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷</item>
+ <item quantity="other">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷</item>
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"কাজের প্রোফাইলের প্রশাসক অ্যাপ্লিকেশান হয় অনুপস্থিত বা ক্ষতিগ্রস্ত হয়েছে৷ এর ফলস্বরূপ আপনার কাজের প্রোফাইল এবং সম্পর্কিত ডেটা মুছে দেওয়া হয়েছে৷ সহায়তার জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"আপনার কাজের প্রোফাইল এই ডিভাইসে আর উপলব্ধ নেই।"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"নেটওয়ার্ক ট্রাফিক মনিটর করা হচ্ছে"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"আরো বিশদ বিবরণের জন্য আলতো চাপ দিন"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"আরো জানতে আলতো চাপুন"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"প্রশাসক অ্যাপকেশানটিতে উপাদান অনুপস্থিত বা ক্ষতিগ্রস্ত হয়েছে এবং ব্যবহার করা যাবে না৷ আপনার ডিভাইস এখন মুছে ফেলা হবে৷ সহায়তার জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
<string name="me" msgid="6545696007631404292">"আমাকে"</string>
@@ -255,7 +255,7 @@
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ক্যালেন্ডার"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS বার্তাগুলি পাঠাতে এবং দেখতে"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"এসএমএসগুলি পাঠাতে এবং দেখতে"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"সঞ্চয়স্থান"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"আপনার ডিভাইসে ফটো, মিডিয়া এবং ফাইলগুলিতে অ্যাক্সেস"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"মাইক্রোফোন"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"প্রদর্শনের জুমের স্তর এবং অবস্থান নির্ধারন নিয়ন্ত্রণ করুন৷"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"অঙ্গভঙ্গির কাজগুলি সম্পাদন করুন"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"আলতো চাপ দেওয়া, সোয়াইপ, পিঞ্চ করা এবং অন্যান্য অঙ্গভঙ্গির কাজগুলি সম্পাদন করতে পারবেন৷"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ফিঙ্গারপ্রিন্ট সেন্সরের উপর করা অঙ্গভঙ্গিগুলি"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সরের উপর আঙ্গুলের অঙ্গভঙ্গি ক্যাপচার করতে পারে।"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"স্থিতি দন্ড নিষ্ক্রিয় অথবা সংশোধন করে"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"অ্যাপ্লিকেশানকে স্থিতি দন্ড অক্ষম করতে এবং সিস্টেম আইকনগুলি সরাতে দেয়৷"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"স্থিতি দন্ডে থাকুন"</string>
@@ -291,7 +293,7 @@
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"আউটগোয়িং কলগুলি পুনঃচালিত করুন"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"অ্যাপ্লিকেশানকে কল চলাকালীন অন্য একটি নম্বরে কল পুনঃনির্দেশ বা কলটি একসথে বন্ধ করার সাথে ডায়াল করা নম্বরটি দেখতে দেয়৷"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"পাঠ্য বার্তা পান (SMS)"</string>
- <string name="permdesc_receiveSms" msgid="6424387754228766939">"অ্যাপ্লিকেশানটিকে SMS বার্তা প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"অ্যাপ্লিকেশানটিকে এসএমএস প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"পাঠ্য বার্তা পান (MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"অ্যাপ্লিকেশানটিকে MMS বার্তা প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"সেল সম্প্রচার বার্তা পড়ুন"</string>
@@ -299,7 +301,7 @@
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"গ্রাহক হিসাবে নেওয়া ফিডগুলি পড়ে"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"অ্যাপ্লিকেশানকে বর্তমানে সিঙ্ক করা ফিডগুলির সম্পর্কে বিবরণ পেতে দেয়৷"</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"SMS পাঠানো ও দেখা,আপনি কি পরিচিতি কে এগুলি করার অনুমতি দেবেন?"</string>
- <string name="permdesc_sendSms" msgid="7094729298204937667">"অ্যাপ্লিকেশানটিকে SMS বার্তাগুলি পাঠাতে অনুমতি দেয়৷ এর জন্য অপ্রত্যাশিত চার্জ কাটা হতে পারে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার নিশ্চিতকরণ ছাড়া বার্তা পাঠানোর মাধ্যমে আপনাকে অর্থ চার্জ করতে পারে৷"</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"অ্যাপ্লিকেশানটিকে এসএমএসগুলি পাঠাতে অনুমতি দেয়৷ এর জন্য অপ্রত্যাশিত চার্জ কাটা হতে পারে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার নিশ্চিতকরণ ছাড়া বার্তা পাঠানোর মাধ্যমে আপনাকে অর্থ চার্জ করতে পারে৷"</string>
<string name="permlab_readSms" msgid="8745086572213270480">"আপনার পাঠ্য বার্তা পড়ুন (SMS বা MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"এই অ্যাপটি আপনার ট্যাবলেটে সংরক্ষিত সমস্ত SMS (পাঠ্য) বার্তা পড়তে পারে৷"</string>
<string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"এই অ্যাপটি আপনার টিভিতে সংরক্ষিত সমস্ত SMS (পাঠ্য) বার্তা পড়তে পারে৷"</string>
@@ -370,7 +372,7 @@
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ভলিউম এবং যেখানে স্পিকার আউটপুট সামগ্রী হিসাবে ব্যবহৃত হয় সেই সব ক্ষেত্রে গ্লোবাল অডিও সেটিংসের সংশোধন করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"অডিও রেকর্ড"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যে কোনো সময় অডিও রেকর্ড করতে পারে৷"</string>
- <string name="permlab_sim_communication" msgid="2935852302216852065">"SIM এ আদেশগুলি পাঠান"</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"সিম এ আদেশগুলি পাঠান"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"অ্যাপ্লিকেশানটিকে সিম কার্ডে কমান্ডগুলি পাঠানোর অনুমতি দেয়৷ এটি খুবই বিপজ্জনক৷"</string>
<string name="permlab_camera" msgid="3616391919559751192">"ছবি এবং ভিডিও তোলে"</string>
<string name="permdesc_camera" msgid="5392231870049240670">"এই অ্যাপটি যে কোনো সময় ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারে৷"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"আপনার হস্তক্ষেপ ছাড়াই কল করতে অ্যাপ্লিকেশানটিকে IMS পরিষেবা ব্যবহারের অনুমতি দিন৷"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ফোনের স্থিতি এবং পরিচয় পড়ুন"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"অ্যাপ্লিকেশানটিকে ডিভাইসের ফোন বৈশিষ্ট্যগুলিকে অ্যাক্সেস করার অনুমতি দেয়৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে একটি কল সক্রিয় থাকা অবস্থায় এবং দূরবর্তী নম্বর একটি কল দ্বারা সংযুক্ত থাকাকালীনও ফোন নম্বর এবং ডিভাইসের IDগুলি নির্ধারণ করার অনুমতি দেয়৷"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"সিস্টেমের মাধ্যমে কলগুলি রুট করতে দিন"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"কল করার অভিজ্ঞতা উন্নত করার জন্য অ্যাপকে সিস্টেমের মাধ্যমে তার কলগুলি রুট করতে দেয়।"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"অ্যাপটিকে ফোন নম্বর পড়ার অনুমতি দিন"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"অ্যাপটিকে এই ডিভাইসের ফোন নম্বর অ্যাক্সেস করার মঞ্জুরি দেয়"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ঘুমানো থেকে ট্যাবলেটকে প্রতিরোধ করে"</string>
@@ -477,8 +481,8 @@
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"অ্যাপ্লিকেশানকে SD কার্ডে লেখার অনুমতি দেয়৷"</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"SIP কল করুন/গ্রহণ করুন"</string>
<string name="permdesc_use_sip" msgid="2297804849860225257">"অ্যাপ্লিকেশানকে SIP কল করতে ও গ্রহণ করতে অনুমতি দেয়।"</string>
- <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"নতুন টেলিকম SIM সংযোগগুলির নিবন্ধন"</string>
- <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"অ্যাপ্লিকেশানটিকে নতুন টেলিকম SIM সংযোগগুলি নিবন্ধিত করতে অনুমোদিত করে৷"</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"নতুন টেলিকম সিম সংযোগগুলির নিবন্ধন"</string>
+ <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"অ্যাপ্লিকেশানটিকে নতুন টেলিকম সিম সংযোগগুলি নিবন্ধিত করতে অনুমোদিত করে৷"</string>
<string name="permlab_register_call_provider" msgid="108102120289029841">"নতুন টেলিকম সংযোগগুলির নিবন্ধন"</string>
<string name="permdesc_register_call_provider" msgid="7034310263521081388">"নতুন টেলিকম সংযোগ নিবন্ধিত করতে অ্যাপ্লিকেশানটিকে অনুমোদিত করে৷"</string>
<string name="permlab_connection_manager" msgid="1116193254522105375">"টেলিকম সংযোগগুলি পরিচালনা করুন"</string>
@@ -690,7 +694,7 @@
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"মুখের সাহায্যে আনলক করার প্রচেষ্টা যতবার করা যায় তার সীমা পেরিয়ে গেছে"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"কোনো সিম কার্ড নেই"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই৷"</string>
- <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"টিভির মধ্যে কোনো SIM কার্ড নেই৷"</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"টিভির মধ্যে কোনো সিম কার্ড নেই৷"</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ফোনের মধ্যে কোনো সিম কার্ড নেই৷"</string>
<string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"একটি সিম কার্ড ঢোকান৷"</string>
<string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"সিম কার্ডটি অনুপস্থিত বা পাঠযোগ্য নয়৷ একটি সিম কার্ড ঢোকান৷"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"মুছুন"</string>
<string name="inputMethod" msgid="1653630062304567879">"ইনপুট পদ্ধতি"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"পাঠ্য ক্রিয়াগুলি"</string>
+ <string name="email" msgid="4560673117055050403">"ইমেল"</string>
+ <string name="dial" msgid="2275093056198652749">"ডায়াল করুন"</string>
+ <string name="map" msgid="5441053548030107189">"মানচিত্র"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"সঞ্চয়স্থান পূর্ণ হতে চলেছে"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"কিছু কিছু সিস্টেম ক্রিয়াকলাপ কাজ নাও করতে পারে"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"সিস্টেমের জন্য যথেষ্ট সঞ্চয়স্থান নেই৷ আপনার কাছে ২৫০MB ফাঁকা স্থান রয়েছে কিনা সে বিষয়ে নিশ্চিত হওয়ার পর পুনরায় চালু করুন৷"</string>
@@ -1099,8 +1106,8 @@
<string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"আপনার টিভি <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত থাকার সময় ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে৷"</string>
<string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ফোনটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string>
<string name="select_character" msgid="3365550120617701745">"অক্ষর ঢোকান"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS বার্তা পাঠানো হচ্ছে"</string>
- <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অনেকগুলি SMS বার্তা পাঠাচ্ছে৷ আপনি কি এই অ্যাপ্লিকেশানটিকে বার্তা পাঠানো চালিয়ে যাওয়ার অনুমতি দিতে চান?"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"এসএমএস পাঠানো হচ্ছে"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অনেকগুলি এসএমএস পাঠাচ্ছে৷ আপনি কি এই অ্যাপ্লিকেশানটিকে বার্তা পাঠানো চালিয়ে যাওয়ার অনুমতি দিতে চান?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"অনুমতি দিন"</string>
<string name="sms_control_no" msgid="625438561395534982">"আস্বীকার করুন"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; এ একটি বার্তা পাঠাতে চায়৷"</string>
@@ -1118,10 +1125,10 @@
<string name="sim_added_title" msgid="3719670512889674693">"সিম কার্ড যোগ করা হয়েছে"</string>
<string name="sim_added_message" msgid="7797975656153714319">"সেলুলার নেটওয়ার্ক অ্যাক্সেস করতে আপনার ডিভাইস পুনর্সূচনা করুন"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"পুনর্সূচনা"</string>
- <string name="carrier_app_dialog_message" msgid="7066156088266319533">"যাতে আপনার নতুন SIM সঠিকভাবে কাজ করে, তার জন্য আপনাকে আপনার পরিষেবা প্রদানকারীর থেকে একটি অ্যাপ্লিকেশান ইনস্টল করতে এবং খুলতে হবে৷"</string>
+ <string name="carrier_app_dialog_message" msgid="7066156088266319533">"যাতে আপনার নতুন সিম সঠিকভাবে কাজ করে, তার জন্য আপনাকে আপনার পরিষেবা প্রদানকারীর থেকে একটি অ্যাপ্লিকেশান ইনস্টল করতে এবং খুলতে হবে৷"</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"অ্যাপ্লিকেশানটি পান"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"এখনই নয়"</string>
- <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন SIM ঢোকানো হয়েছে"</string>
+ <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন সিম ঢোকানো হয়েছে"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"এটিকে সেট আপ করতে আলতো চাপুন"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"সময় সেট করুন"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"তারিখ সেট করুন"</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"আরো বিকল্পের জন্য আলতো চাপুন৷"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ডিবাগিং অক্ষম করতে আলতো চাপুন৷"</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"কোনো অ্যাপ্লিকেশানকে সেশনগুলি পড়ার অনুমতি দেয়। এটি সক্রিয় প্যাকেজ ইনস্টলেশনের বিশদ বিবরণ দেখতে দেয়।"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"প্যাকেজগুলি ইনস্টল করার অনুরোধ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"একটি অ্যাপ্লিকেশানকে প্যাকেজগুলির ইনস্টল করার অনুরোধ জানাতে অনুমতি দেয়৷"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"প্যাকেজ মোছার অনুরোধ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"একটি অ্যাপ্লিকেশানকে প্যাকেজগুলি মুছে দেওয়ার অনুরোধ জানাতে দেয়৷"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করার জন্য অনুমতি চাওয়া"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"কোনো অ্যাপের জন্য ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করতে সেটিকে অনুমতির চাওয়ার মঞ্জুরি দেয়৷"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"জুম নিয়ন্ত্রণের জন্য দুবার আলতো চাপুন"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"সরান"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"অ্যাক্সেসযোগ্যতা সক্রিয় করতে দুইটি আঙ্গুলকে চেপে নিচে ধরে রাখুন৷"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"অ্যাক্সেসযোগ্যতা সক্ষম করা হয়েছে৷"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"অ্যাক্সেসযোগ্যতা বাতিল করা হয়েছে৷"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"অ্যাক্সেসযোগ্যতা শর্টকাট চালু রয়েছে"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"উভয় ভলিউম বোতামকে ৩ সেকেন্ড পর্যন্ত চেপে ধরে <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু বা বন্ধ করতে পারেন।\n\nআপনি সেটিংস &gt; অ্যাক্সেসযোগ্যতা এ গিয়ে পরিষেবা পরিবর্তন করতে পারবেন।"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"অ্যাক্সেসযোগ্যতা শর্টকাট বন্ধ রয়েছে"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"চালু থাক"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
<string name="user_switched" msgid="3768006783166984410">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> নামের ব্যবহারকারীতে যাচ্ছে…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>কে লগ আউট করা হচ্ছে..."</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"কনফারেন্স কল"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"টুলটিপ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"গেম্স"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"সঙ্গীত ও অডিও"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"চলচ্চিত্র ও ভিডিওগুলি"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ফটো ও চিত্রগুলি"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"সামাজিক ও যোগাযোগ"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"খবর ও পত্রিকাগুলি"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"মানচিত্র ও নেভিগেশান"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"উৎপাদনশীলতা"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ডিভাইসের সঞ্চয়স্থান"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-bs-watch/styles_material.xml b/core/res/res/values-bs-watch/styles_material.xml
deleted file mode 100644
index 88e5751c04ce..000000000000
--- a/core/res/res/values-bs-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidati"</font></string>
-</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 71c9f7d83611..66ef19a33143 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Aplikacija administratora za poslovni profil nedostaje ili je neispravna. Zbog toga su vaš poslovni profil i vezani podaci obrisani. Za pomoć se obratite administratoru."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profil za posao više nije dostupan na ovom uređaju."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Mrežni saobraćaj se nadgleda"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Dodirnite za više detalja"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Dodirnite da saznate više"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Uređaj će biti izbrisan"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Aplikaciji administratora nedostaju komponente ili je neispravna, i ne može se koristiti. Vaš uređaj će sada biti izbrisan. Za pomoć se obratite administratoru."</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira stepen uvećanja prikaza na ekranu i podešavanje položaja."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Praviti pokrete"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirivati, prevlačiti, hvatati prstima i praviti druge pokrete."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti otiska prsta"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Moguće je zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili mijenjanje statusne trake"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji onemogućavanje statusne trake ili dodavanje i uklanjanje sistemskih ikona."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"funkcioniranje u vidu statusne trake"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Omogućava aplikaciji da koristi IMS uslugu za pozivanje bez vaše intervencije."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Omogućava aplikaciji pristup telefonskim funkcijama uređaja. Ova dozvola omogućava aplikaciji određivanje telefonskog i identifikacionog broja uređaja, bez obzira da li je poziv aktivan i da li je uspostavljena veza sa pozivanim brojem."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"usmjeravanje poziva preko sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Dopušta aplikaciji da pozive usmjeri preko sistema radi poboljšanja iskustva pozivanja."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitanje telefonskog broja"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Dopušta aplikaciji pristup telefonskom broju telefona."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje tableta da uđe u režim mirovanja"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
<string name="inputMethod" msgid="1653630062304567879">"Način unosa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Akcije za tekst"</string>
+ <string name="email" msgid="4560673117055050403">"E-pošta"</string>
+ <string name="dial" msgid="2275093056198652749">"Biraj"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke funkcije sistema možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno prostora za sistem. Obezbijedite 250MB slobodnog prostora i ponovo pokrenite uređaj."</string>
@@ -1163,6 +1170,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka putem uređaja spojenog na USB je uspostavljeno"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da onemogućite otklanjanje grešaka putem uređaja spojenog na USB."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Prijem izvještaja o grešci..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
@@ -1219,6 +1228,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instalacija. Ovim se aplikaciji omogućava da vidi detalje o aktivnim instalacijama paketa."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtijevanje paketa za instaliranje"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava aplikaciji da zahtijeva instalaciju paket ā."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"zatraži brisanje paketanja"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Omogućava aplikaciji da zatraži brisanje paketa."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"traži zanemarivanje optimizacije baterije"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Omogućava aplikaciji da traži dozvolu za zanemarivanje optimizacije baterije za tu aplikaciju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu uvećanja"</string>
@@ -1446,9 +1457,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati pritisnuta dva prsta da aktivirate način rada za pristupačnost."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Način rada za pristupačnost je omogućen."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Način rada za pristupačnost je poništen."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Prečica za pristupačnost je UKLJUČENA"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Držite oba dugmeta za podešavanje jačine zvuka 3 sekunde da uključite ili isključite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>.\n\nUslugu možete promijeniti ako odete u Postavke &gt; Pristupačnost."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Isključi prečicu"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ostavi uključeno"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Trenutni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Odjava korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1704,20 +1718,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Savjet za alat"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Igre"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzika i zvuk"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmovi i videozapisi"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotografije i slike"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Društvene mreže i komunikacija"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Vijesti i časopisi"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mape i navigacija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memorija uređaja"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ca-watch/styles_material.xml b/core/res/res/values-ca-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ca-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4db3b710e27c..b01f3824ac1d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"L\'aplicació d\'administració del perfil professional està malmesa o no es detecta. Com a conseqüència, el perfil professional i les dades relacionades s\'han suprimit. Contacta amb l\'administrador per obtenir ajuda."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"El perfil professional ja no està disponible en aquest dispositiu."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"El trànsit de xarxa s\'està supervisant"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toca per obtenir més informació"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toca per obtenir més informació"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"El contingut del dispositiu s\'esborrarà"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"L\'aplicació d\'administració està malmesa o hi falten components, i no es pot fer servir. El contingut del dispositiu s\'esborrarà. Contacta amb l\'administrador per obtenir ajuda."</string>
<string name="me" msgid="6545696007631404292">"Mi"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el nivell i el posicionament del zoom de la pantalla."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Utilitza gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Pot tocar, lliscar, pessigar i utilitzar altres gestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos amb les empremtes digitals"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Captura gestos realitzats en el sensor d\'empremtes digitals del dispositiu."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra d\'estat"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet que l\'aplicació desactivi la barra d\'estat o afegeixi i elimini icones del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparèixer a la barra d\'estat"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet que l\'aplicació utilitzi el servei IMS per fer trucades sense la teva intervenció."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"encaminar trucades a través del sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permet que l\'aplicació encamini les trucades a través del sistema per millorar-ne l\'experiència."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"llegeix el número de telèfon"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet que l\'aplicació accedeixi al número de telèfon del dispositiu."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode de repòs"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Suprimeix"</string>
<string name="inputMethod" msgid="1653630062304567879">"Mètode d\'introducció de text"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
+ <string name="email" msgid="4560673117055050403">"Correu electrònic"</string>
+ <string name="dial" msgid="2275093056198652749">"Telèfon"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hi ha prou espai d\'emmagatzematge per al sistema. Comprova que tinguis 250 MB d\'espai lliure i reinicia."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toca per veure més opcions."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toca per desactivar la depuració USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecciona per desactivar la depuració USB"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"S\'està creant l\'informe d\'errors…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vols compartir l\'informe d\'errors?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"S\'està compartint l\'informe d\'errors…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet que una aplicació llegeixi les sessions d\'instal·lació i això permet veure detalls sobre les instal·lacions de paquet actives."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"sol·licitar la instal·lació de paquets"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet que una aplicació sol·liciti la instal·lació de paquets."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"sol·licitar la supressió de paquets"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permet que una aplicació sol·liciti la supressió de paquets."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Demanar permís per ignorar les optimitzacions de bateria"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet que una aplicació demani permís per ignorar les optimitzacions de bateria per a l\'aplicació."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Piqueu dos cops per controlar el zoom"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador de realitat virtual"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Servei de classificació de notificacions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén premuts els dos dits per activar l\'accessibilitat."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"S\'ha activat l\'accessibilitat."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilitat cancel·lada."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"La drecera d\'accessibilitat està ACTIVADA"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Per activar o desactivar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén premuts els dos botons de volum durant tres segons.\n\nPots canviar el servei a Configuració &gt; Accessibilitat."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desactiva la drecera"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Mantén-la activada"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"S\'està canviant a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"S\'està tancant la sessió de l\'usuari <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferència"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Descripció emergent"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jocs"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música i àudio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Pel·lícules i vídeos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos i imatges"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Xarxes socials i comunicació"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Notícies i revistes"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapes i navegació"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivitat"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Emmagatzematge del dispositiu"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-cs-watch/styles_material.xml b/core/res/res/values-cs-watch/styles_material.xml
deleted file mode 100644
index 5b604e837551..000000000000
--- a/core/res/res/values-cs-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidáti"</font></string>
-</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b72ef8b0476f..b8717d5e3b22 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Aplikace pro správu pracovního profilu chybí nebo je poškozena. Váš pracovní profil a související data proto byla smazána. Kontaktujte svého administrátora a požádejte jej o pomoc."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Váš pracovní profil v tomto zařízení již není k dispozici."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Síťový provoz je monitorován"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Klepnutím zobrazíte další podrobnosti"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Klepnutím zobrazíte další informace"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Zařízení bude vymazáno"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"V aplikaci pro správu chybí některé součásti nebo je poškozená, a proto ji nelze použít. Zařízení nyní bude vymazáno. Kontaktujte svého administrátora a požádejte jej o pomoc."</string>
<string name="me" msgid="6545696007631404292">"Já"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Určuje umístění a úroveň přiblížení displeje."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Provádění gest"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Může provádět gesta klepnutí, přejetí, stažení prstů a další."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesta otiskem prstu"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dokáže rozpoznat gesta zadaná na snímači otisků prstů."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zakázání či změny stavového řádku"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vydávání se za stavový řádek"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Umožňuje aplikaci používat službu zasílání rychlých zpráv k uskutečňování hovorů bez vašeho zásahu."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čtení stavu a identity telefonu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Toto oprávnění umožňuje aplikaci zjistit telefonní číslo telefonu, identifikační čísla zařízení, zda zrovna probíhá hovor, a vzdálené číslo, ke kterému je hovor připojen."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"směrování volání prostřednictvím systému"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Umožňuje aplikaci směrovat volání prostřednictvím systému za účelem vylepšení funkcí volání."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"přístup k telefonnímu číslu"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Umožňuje aplikaci zobrazit telefonní číslo zařízení."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"bránění přechodu tabletu do režimu spánku"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Smazat"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metoda zadávání dat"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Operace s textem"</string>
+ <string name="email" msgid="4560673117055050403">"Poslat e-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Vytočit"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Pro systém není dostatek místa v úložišti. Uvolněte alespoň 250 MB místa a restartujte zařízení."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte další možnosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladění USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, chcete-li zakázat ladění USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Vytváření zprávy o chybě…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Sdílet zprávu o chybě?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sdílení zprávy o chybě…"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Povoluje aplikaci číst instalační relace. Díky tomu můžete zobrazit podrobnosti o aktivních instalacích balíčku."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"odesílání žádostí o přístup k instalačním balíčkům"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Umožňuje aplikaci požádat o instalaci balíčků."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"požádat o smazání balíčků"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Umožňuje aplikaci požádat o smazání balíčků."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"požádat o ignorování optimalizace využití baterie"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Povoluje aplikaci požádat o oprávnění ignorovat optimalizaci využití baterie, která pro ni je nastavena."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Poklepáním můžete ovládat přiblížení"</string>
@@ -1265,7 +1275,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Přijímač virtuální reality"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR přijímač"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovatel podmínky"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Služba na hodnocení důležitosti oznámení"</string>
<string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Usnadnění zapnete dlouhým stisknutím dvěma prsty."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Usnadnění přístupu je aktivováno."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Usnadnění zrušeno."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Zkratka přístupnosti je ZAPNUTÁ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zapnete či vypnete, když po dobu tří sekund podržíte obě tlačítka hlasitosti.\n\nVybranou službu lze změnit v Nastavení &gt; Přístupnost."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Vypnout zkratku"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ponechat zapnutou"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Přepínání na účet <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Odhlašování uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenční hovor"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Popisek"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Hry"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Hudba a zvuk"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmy a video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotky a obrázky"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociální sítě a komunikace"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Zprávy a časopisy"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapy a navigace"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivita"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Úložiště zařízení"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-da-watch/styles_material.xml b/core/res/res/values-da-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-da-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ad01840a8e3d..ebcd48e3d1ce 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Administrationsappen til arbejdsprofilen mangler eller er beskadiget. Derfor er din arbejdsprofil og dine relaterede data blevet slettet. Kontakt din administrator for at få hjælp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Netværkstrafikken overvåges"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tryk for at få flere oplysninger"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tryk for at få flere oplysninger"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Enheden slettes"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administrationsappen mangler komponenter eller er beskadiget og kan ikke bruges. Enheden vil nu blive slettet. Kontakt din administrator for at få hjælp."</string>
<string name="me" msgid="6545696007631404292">"Mig"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér skærmens zoomniveau og position."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Udfør bevægelser"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingeraftryksbevægelser"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan registrere bevægelser, der foretages på enhedernes fingeraftrykslæser."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tillader, at appen kan deaktivere statusbjælken eller tilføje og fjerne systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vær statusbjælken"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tillader, at appen kan bruge chat-tjenesten til at foretage opkald, uden du gør noget."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"læse telefonens status og identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"dirigere opkald gennem systemet"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Tillader appen at dirigere sine opkald gennem systemet for at forbedre opkaldsoplevelsen."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"læs telefonnummer"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Tillader, at appen har adgang til enhedens telefonnummer."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Slet"</string>
<string name="inputMethod" msgid="1653630062304567879">"Inputmetode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Ring op"</string>
+ <string name="map" msgid="5441053548030107189">"Kort"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tryk for at se flere muligheder."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tryk for at deaktivere fejlretning via USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vælg for at deaktivere USB-fejlretning."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Opretter fejlrapport…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele fejlrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler fejlrapport…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillader, at en applikation læser installationssessioner. Dermed kan applikationen se oplysninger om aktive pakkeinstallationer."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"anmod om installation af pakker"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tillader, at en app anmoder om installation af pakker."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"anmod om sletning af pakker"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Tillader, at en app anmoder om sletning af pakker."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"bede om at ignorere batterioptimeringer"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gør det muligt for en app at bede om tilladelse til at ignorere batterioptimeringer for den pågældende app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tryk to gange for zoomkontrol"</string>
@@ -1388,7 +1398,7 @@
<string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%1$d</xliff:g> sekunder."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM-kort"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
<string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Kontakt mobiloperatøren for at få flere oplysninger."</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget højt musik over længere tid."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Bliv ved med at holde to fingre nede for at aktivere hjælpefunktioner."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Hjælpefunktioner er aktiveret."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hjælpefunktioner er annulleret."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Genvej til hjælpefunktioner er slået TIL"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Slå <xliff:g id="SERVICE_NAME">%1$s</xliff:g> til eller fra ved at holde begge lydstyrkeknapper nede i tre sekunder.\n\nDu kan skifte tjeneste under Indstillinger &gt; Hjælpefunktioner."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Deaktiver genvej"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Lad den være aktiveret"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Skifter til <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> logges ud…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonmøde"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Værktøjstip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Spil"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musik og lyd"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Film og video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Billeder"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociale medier og kommunikation"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Aviser og blade"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kort og navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Lagerplads på enheden"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-de-watch/styles_material.xml b/core/res/res/values-de-watch/styles_material.xml
deleted file mode 100644
index 891a647b3c33..000000000000
--- a/core/res/res/values-de-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"Kandidaten"</font></string>
-</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index db19e193261b..7e3174836d5e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Die Admin-App für das Arbeitsprofil fehlt oder ist beschädigt. Daher wurden dein Arbeitsprofil und alle zugehörigen Daten gelöscht. Wende dich für weitere Hilfe an deinen Administrator."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Dein Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Der Netzwerkverkehr wird protokolliert"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Für weitere Details antippen"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Für weitere Informationen tippen"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Die Daten auf deinem Gerät werden gelöscht."</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Die Admin-App kann nicht verwendet werden, da sie beschädigt wurde oder Komponenten fehlen. Die Daten auf deinem Gerät werden nun gelöscht. Wende dich für weitere Hilfe an deinen Administrator."</string>
<string name="me" msgid="6545696007631404292">"Eigene"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe des Displays und die Zoom-Position auf dem Display fest."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Bewegungen möglich"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Bewegungen möglich."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bewegungen auf dem Fingerabdrucksensor"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Erfasst Bewegungen auf dem Fingerabdrucksensor des Geräts."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ermöglicht der App die Verwendung des IMS-Dienstes zum Tätigen von Anrufen ohne Nutzereingriffe"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"Anrufe über das System durchführen"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Ermöglicht der App, Anrufe über das System durchzuführen, um die Anrufqualität zu verbessern."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Telefonnummer lesen"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Der App den Zugriff auf die Telefonnummer des Geräts erlauben."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Löschen"</string>
<string name="inputMethod" msgid="1653630062304567879">"Eingabemethode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
+ <string name="email" msgid="4560673117055050403">"E-Mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Wählen"</string>
+ <string name="map" msgid="5441053548030107189">"Karte"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Für weitere Optionen tippen."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging aktiviert"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Zum Deaktivieren von USB-Debugging tippen."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Fehlerbericht wird abgerufen…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Fehlerbericht wird geteilt…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ermöglicht der App, Installationssitzungen zu lesen. Dadurch kann sie Details aktiver Paketinstallationen abrufen."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Installation von Paketen anfordern"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ermöglicht der App, die Installation von Paketen anzufordern"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"Löschen von Paketen anfordern"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Ermöglicht der App, das Löschen von Paketen anzufordern."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"fragen, ob Akku-Leistungsoptimierungen ignoriert werden können"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Erlaubt einer App, nach der Berechtigung zum Ignorieren der Akku-Leistungsoptimierungen zu fragen."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücke mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Verknüpfung für Bedienungshilfen ist AKTIVIERT"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Schalte <xliff:g id="SERVICE_NAME">%1$s</xliff:g> durch dreisekündiges Drücken beider Lautstärketasten ein oder aus.\n\nDu kannst den Dienst unter \"Einstellungen\" &gt; \"Bedienungshilfen\" ändern."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Verknüpfung deaktivieren"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Aktiviert lassen"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
<string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Wechseln zu <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> wird abgemeldet…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonkonferenz"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Kurzinfo"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Spiele"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musik &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filme &amp; Videos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos &amp; Bilder"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Soziale Netzwerke &amp; Kommunikation"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Nachrichten &amp; Zeitschriften"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Karten &amp; Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Effizienz"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Gerätespeicher"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-el-watch/styles_material.xml b/core/res/res/values-el-watch/styles_material.xml
deleted file mode 100644
index a02b85e9b0a4..000000000000
--- a/core/res/res/values-el-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"υποψήφιοι"</font></string>
-</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 333adaa07e4b..7458e0461a8f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Η εφαρμογή διαχείρισης προφίλ εργασίας είτε λείπει είτε είναι κατεστραμμένη. Ως αποτέλεσμα, το προφίλ εργασίας και σχετικά δεδομένα διαγράφηκαν. Επικοινωνήστε με το διαχειριστή για βοήθεια."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Το προφίλ σας εργασίας δεν είναι πια διαθέσιμο σε αυτήν τη συσκευή."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Η επισκεψιμότητα δικτύου παρακολουθείται"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Πατήστε για να δείτε περισσότερες λεπτομέρειες"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Πατήστε για να μάθετε περισσότερα"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Η συσκευή σας θα διαγραφεί"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Λείπουν στοιχεία από την εφαρμογή διαχείρισης ή είναι κατεστραμμένη, και δεν μπορεί να χρησιμοποιηθεί. Η συσκευή σας θα διαγραφεί. Επικοινωνήστε με το διαχειριστή για βοήθεια."</string>
<string name="me" msgid="6545696007631404292">"Για εμένα"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ελέγξτε το επίπεδο ζουμ και τη θέση της οθόνης."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Εκτέλεση κινήσεων"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Επιτρέπει το πάτημα, την ολίσθηση, το πλησίασμα και άλλες κινήσεις."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Κινήσεις δακτυλικών αποτυπωμάτων"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Μπορεί να αναγνωρίσει κινήσεις που εκτελούνται στον αισθητήρα δακτυλικών αποτυπωμάτων των συσκευών."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποιεί ή να τροποποιεί την γραμμή κατάστασης"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ορίζεται ως γραμμή κατάστασης"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Επιτρέπει στην εφαρμογή τη χρήση της υπηρεσίας IMS για την πραγματοποίηση κλήσεων χωρίς τη δική σας παρέμβαση."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"διαβάζει την κατάσταση και ταυτότητα τηλεφώνου"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"δρομολόγηση κλήσεων μέσω του συστήματος"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Επιτρέπει στην εφαρμογή να δρομολογεί τις κλήσεις της μέσω του συστήματος για να βελτιώσει την εμπειρία κλήσης."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ανάγνωση αριθμού τηλεφώνου"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Επιτρέπει στην εφαρμογή να έχει πρόσβαση στον αριθμό τηλεφώνου της συσκευής."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Διαγραφή"</string>
<string name="inputMethod" msgid="1653630062304567879">"Μέθοδος εισόδου"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Ενέργειες κειμένου"</string>
+ <string name="email" msgid="4560673117055050403">"Ηλεκτρονικό ταχυδρομείο"</string>
+ <string name="dial" msgid="2275093056198652749">"Κλήση"</string>
+ <string name="map" msgid="5441053548030107189">"Χάρτης"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο αποθηκευτικός χώρος εξαντλείται"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Πατήστε για περισσότερες επιλογές."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Πατήστε για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Λήψη αναφοράς σφάλματος…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των περιόδων σύνδεσης εγκατάστασης. Αυτό της επιτρέπει να βλέπει λεπτομέρειες σχετικά με τις εγκαταστάσεις του ενεργού πακέτου."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ζητά πακέτα εγκατάστασης"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Επιτρέπει σε μια εφαρμογή να ζητά εγκατάσταση πακέτων."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"αίτημα διαγραφής πακέτων"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Επιτρέπει σε μια εφαρμογή να ζητά διαγραφή πακέτων."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"αίτημα αγνόησης βελτιστοποιήσεων μπαταρίας"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Επιτρέπει σε μια εφαρμογή να ζητήσει άδεια για την αγνόηση βελτιστοποιήσεων της μπαταρίας για τη συγκεκριμένη εφαρμογή."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Λειτουργία ακρόασης Εικονικής Πραγματικότητας"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Λειτουργία ακρόασης VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Υπηρεσία κατάταξης ειδοποιήσεων"</string>
<string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Κατάργηση"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Αγγίξτε παρατεταμένα με δύο δάχτυλα για να ενεργοποιήσετε τη λειτουργία προσβασιμότητας."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Ενεργοποιήθηκε η προσβασιμότητα."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Η λειτουργία προσβασιμότητας ακυρώθηκε."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Η συντόμευση προσβασιμότητας είναι ΕΝΕΡΓΗ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ενεργοποιήστε ή απενεργοποιήστε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g> πατώντας παρατεταμένα τα κουμπιά έντασης ήχου για 3 δευτερόλεπτα.\n\nΜπορείτε να αλλάξετε την υπηρεσία στις Ρυθμίσεις &gt; Προσβασιμότητα."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Απενεργοποίηση συντόμευσης"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Διατήρηση ενεργοποίησης"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Η συντόμευση προσβασιμότητας ενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Η συντόμευση προσβασιμότητας απενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Εναλλαγή σε <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Αποσύνδεση <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Απενεργοποιημένο <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Κλήση συνδιάσκεψης"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Επεξήγηση εργαλείου"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Παιχνίδια"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Μουσική και ήχος"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Ταινίες και βίντεο"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Φωτογραφίες και εικόνες"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Κοινωνικά και επικοινωνία"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Ειδήσεις και περιοδικά"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Χάρτες και πλοήγηση"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Παραγωγικότητα"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Αποθηκευτικός χώρος συσκευής"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-en-rAU-watch/styles_material.xml b/core/res/res/values-en-rAU-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-en-rAU-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 91b1620129cd..107f2478cce6 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your administrator for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Your work profile is no longer available on this device."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Network traffic is being monitored"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tap for more details"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tap to find out more"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"The admin app is missing components or corrupted, and can\'t be used. Your device will now be erased. Contact your administrator for assistance."</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"route calls through the system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Allows the app to route its calls through the system in order to improve the calling experience."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Dial"</string>
+ <string name="map" msgid="5441053548030107189">"Map"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"request delete packages"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Allows an application to request deletion of packages."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Keep holding down two fingers to enable accessibility."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibility enabled."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibility cancelled."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Accessibility Shortcut is ON"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Turn <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on or off by holding down both volume buttons for 3 seconds.\n\nYou can change the service in Settings &gt; Accessibility."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Turn Off Shortcut"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Leave on"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
<string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Games"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Music &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Movies &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos &amp; Images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social &amp; Communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-en-rGB-watch/styles_material.xml b/core/res/res/values-en-rGB-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-en-rGB-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 91b1620129cd..107f2478cce6 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your administrator for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Your work profile is no longer available on this device."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Network traffic is being monitored"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tap for more details"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tap to find out more"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"The admin app is missing components or corrupted, and can\'t be used. Your device will now be erased. Contact your administrator for assistance."</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"route calls through the system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Allows the app to route its calls through the system in order to improve the calling experience."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Dial"</string>
+ <string name="map" msgid="5441053548030107189">"Map"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"request delete packages"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Allows an application to request deletion of packages."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Keep holding down two fingers to enable accessibility."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibility enabled."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibility cancelled."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Accessibility Shortcut is ON"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Turn <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on or off by holding down both volume buttons for 3 seconds.\n\nYou can change the service in Settings &gt; Accessibility."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Turn Off Shortcut"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Leave on"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
<string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Games"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Music &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Movies &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos &amp; Images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social &amp; Communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-en-rIN-watch/styles_material.xml b/core/res/res/values-en-rIN-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-en-rIN-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 91b1620129cd..107f2478cce6 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your administrator for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Your work profile is no longer available on this device."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Network traffic is being monitored"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tap for more details"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tap to find out more"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"The admin app is missing components or corrupted, and can\'t be used. Your device will now be erased. Contact your administrator for assistance."</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Allows the app to use the IMS service to make calls without your intervention."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"route calls through the system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Allows the app to route its calls through the system in order to improve the calling experience."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Dial"</string>
+ <string name="map" msgid="5441053548030107189">"Map"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Allows an application to read install sessions. This allows it to see details about active package installations."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"request install packages"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Allows an application to request installation of packages."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"request delete packages"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Allows an application to request deletion of packages."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ask to ignore battery optimisations"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tap twice for zoom control"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Keep holding down two fingers to enable accessibility."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibility enabled."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibility cancelled."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Accessibility Shortcut is ON"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Turn <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on or off by holding down both volume buttons for 3 seconds.\n\nYou can change the service in Settings &gt; Accessibility."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Turn Off Shortcut"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Leave on"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
<string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Games"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Music &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Movies &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos &amp; Images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social &amp; Communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-es-rUS-watch/styles_material.xml b/core/res/res/values-es-rUS-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-es-rUS-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7db3b4cc7d46..2749b350d15d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"La aplicación de administración de perfil de trabajo no se encuentra o está dañada. Por lo tanto, se eliminaron tu perfil de trabajo y los datos relacionados. Para obtener asistencia, comunícate con el administrador."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Tu perfil de trabajo ya no está disponible en este dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Se está controlando el tráfico de red"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Presiona para ver más detalles"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Presiona para obtener más información"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Se borrarán los datos del dispositivo"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"La aplicación de administración no cuenta con algunos componentes o está dañada, de modo que no puede usarse. Se borrarán los datos del dispositivo. Para obtener asistencia, comunícate con el administrador."</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Usar gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permite presionar, deslizar, pellizcar y usar otros gestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos del sensor de huellas digitales"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Captura los gestos que se hacen en el sensor de huellas digitales de los dispositivos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o que agregue y elimine íconos del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que la aplicación utilice el servicio IMS para hacer llamadas sin tu intervención."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"leer la identidad y el estado del dispositivo"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"Transmite llamadas a través del sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite que la app transmita las llamadas a través del sistema para mejorar la experiencia de llamadas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leer el número de teléfono"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que la app acceda al número de teléfono del dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
+ <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
+ <string name="dial" msgid="2275093056198652749">"Marcar"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Asegúrate de que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Presiona para ver más opciones."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Presiona para inhabilitar la depuración por USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para desactivar la depuración por USB"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Realizando un informe de errores…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que una aplicación lea sesiones de instalación. Esto le permite ver detalles acerca de instalaciones de paquetes activas."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar la instalación de paquetes"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que una aplicación solicite la instalación de paquetes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar la eliminación de paquetes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite que una aplicación solicite que se borren paquetes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar permiso para ignorar las optimizaciones de la batería"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que una app solicite permiso para ignorar las optimizaciones de la batería."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Presiona dos veces para obtener el control del zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén presionado con dos dedos para activar la accesibilidad."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Se activó la accesibilidad."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"El acceso directo de accesibilidad está ACTIVADO"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Activa o desactiva <xliff:g id="SERVICE_NAME">%1$s</xliff:g>. Para ello, presiona ambos botones de volumen durante 3 segundos.\n\nPuedes cambiar el servicio en Configuración &gt; Accesibilidad."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desactivar acceso directo"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Dejar habilitado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Saliendo de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Información sobre la herramienta"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Juegos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música y audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Películas y videos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Imágenes y fotos"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociales y comunicación"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Noticias y revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas y navegación"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productividad"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamiento del dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-es-watch/styles_material.xml b/core/res/res/values-es-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-es-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 39ca2ef4db75..bdb138134a11 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"La aplicación de administración del perfil de trabajo falta o está dañada. Como consecuencia, se han eliminado tu perfil de trabajo y todos los datos asociados. Si necesitas ayuda, ponte en contacto con tu administrador."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Tu perfil de trabajo ya no está disponible en este dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Se está controlando el tráfico de la red"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toca la notificación para ver más detalles"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toca la notificación para obtener más información"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Tu dispositivo se borrará"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"La aplicación de administración no se puede usar porque está dañada o le faltan componentes. Tu dispositivo se borrará. Si necesitas ayuda, ponte en contacto con tu administrador."</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de huellas digitales"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Puede capturar los gestos realizados en el sensor de huellas digitales del dispositivo."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o añada y elimine iconos del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que la aplicación utilice el servicio IMS para realizar llamadas sin tu intervención."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"consultar la identidad y el estado del teléfono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"direccionar llamadas a través del sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite a la aplicación direccionar sus llamadas hacia el sistema para mejorar la calidad de estas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leer el número de teléfono"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que la aplicación acceda al número de teléfono del dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de introducción de texto"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
+ <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
+ <string name="dial" msgid="2275093056198652749">"Marcar"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Comprueba que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver más opciones."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para inhabilitar la depuración USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de errores…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que una aplicación consulte sesiones de instalación para ver detalles sobre instalaciones de paquetes activos."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar instalación de paquetes"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite a una aplicación solicitar la instalación de paquetes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar eliminación de paquetes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite a una aplicación solicitar la eliminación de paquetes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar permiso para ignorar las optimizaciones de la batería"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que una aplicación solicite permiso para ignorar las optimizaciones de la batería."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Da dos toques para acceder al control de zoom."</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Quitar"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar tus oídos."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén la pantalla pulsada con dos dedos para habilitar las funciones de accesibilidad."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accesibilidad habilitada"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidad cancelada"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Acceso directo a accesibilidad activado"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Para activar o desactivar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsados los dos botones de volumen durante tres segundos.\n\nPuedes cambiar el servicio en Configuración &gt; Accesibilidad."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desactivar acceso directo"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Mantener activado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Cerrando la sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Descripción emergente"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Juegos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música y audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Películas y vídeos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos e imágenes"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social y comunicación"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Noticias y revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas y navegación"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productividad"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamiento del dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-et-watch/styles_material.xml b/core/res/res/values-et-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-et-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2ccc3ebd79a4..5b532b4ec757 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Tööprofiili administraatori rakendus puudub või on rikutud. Seetõttu on teie tööprofiil ja seotud andmed kustutatud. Abi saamiseks võtke ühendust administraatoriga."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Teie tööprofiil pole selles seadmes enam saadaval."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Võrguliiklust jälgitakse"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Puudutage üksikasjade vaatamiseks"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Puudutage lisateabe saamiseks"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Seade kustutatakse"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administraatori rakendusel on puuduvaid osi või on see rikutud ja seda ei saa kasutada. Seade kustutatakse. Abi saamiseks võtke ühendust administraatoriga."</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Saate juhtida ekraani suumitaset ja asendit."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Liigutuste tegemine"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Saate puudutada, pühkida, sõrmi kokku-lahku liigutada ja teisi liigutusi teha."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Sõrmejälje liigutused"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Teil on võimalik jäädvustada liigutused, mis on tehtud seadmete sõrmejäljeanduri abil."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"keela või muuda olekuriba"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Võimaldab rakendusel keelata olekuriba või lisada ja eemaldada süsteemiikoone."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"olekuribana kuvamine"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Võimaldab rakendusel kasutada IMS-teenust kõnede tegemiseks ilma, et peaksite sekkuma."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lugege telefoni olekut ja identiteeti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Annab rakendusele juurdepääsu seadme telefonifunktsioonidele. See luba võimaldab rakendusel määrata telefoninumbri ja seadme ID-d ning kontrollida, kas kõne on aktiivne ja kaugnumber on kõne kaudu telefoniga ühendatud."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"kõnede marsruutimine süsteemi kaudu"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Võimaldab rakendusel kõnesid süsteemi kaudu marsruutida, et helistamiskogemust täiustada."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lugeda telefoninumbrit"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Lubab rakendusel juurde pääseda seadme telefoninumbrile."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tahvelarvuti uinumise vältimine"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Kustuta"</string>
<string name="inputMethod" msgid="1653630062304567879">"Sisestusmeetod"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoimingud"</string>
+ <string name="email" msgid="4560673117055050403">"E-post"</string>
+ <string name="dial" msgid="2275093056198652749">"Helistamine"</string>
+ <string name="map" msgid="5441053548030107189">"Kaart"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Süsteemis pole piisavalt talletusruumi. Veenduge, et seadmes oleks 250 MB vaba ruumi, ja käivitage seade uuesti."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Puudutage lisavalikute nägemiseks."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Puudutage USB-silumise keelamiseks."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Valige USB silumise keelamiseks"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Veaaruande võtmine …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kas jagada veaaruannet?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Veaaruande jagamine …"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Lubab rakendusel lugeda installiseansse. See võimaldab näha aktiivse paketi installimise üksikasju."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"installipakettide taotlemine"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Võimaldab rakendusel pakettide installimist taotleda."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"pakettide kustutamise taotlemine"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Võimaldab rakendusel taotleda pakettide kustutamist."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"küsida luba aku optimeerimise eiramiseks"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Lubab rakendusel küsida luba rakenduse aku optimeerimise eiramiseks."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Suumi kasutamiseks koputage kaks korda"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hõlbustuse lubamiseks hoidke kaht sõrme all."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Hõlbustus on lubatud."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hõlbustus on tühistatud."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Juurdepääsetavuse otsetee on SEES"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Lülitage teenus <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse või välja, hoides mõlemat helitugevuse nuppu kolm sekundit all.\n\nTeenust saate muuta menüüs Seaded &gt; Juurdepääsetavus."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Lülita otsetee välja"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Jäta sisselülitatuks"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
<string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Üleminek kasutajale <xliff:g id="NAME">%1$s</xliff:g> ..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Kasutaja <xliff:g id="NAME">%1$s</xliff:g> väljalogimine …"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konverentskõne"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tööriistavihje"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Mängud"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muusika ja heli"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmid ja video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotod ja kujutised"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Suhtlus ja side"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Uudised ja ajakirjad"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kaardid ja navigeerimine"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktiivsus"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Seadme salvestusruum"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-eu-watch/styles_material.xml b/core/res/res/values-eu-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-eu-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index c131c42c0c90..afb0a9cb006a 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Laneko profila administratzeko aplikazioa falta da edo hondatuta dago. Ondorioz, laneko profila eta horrekin erlazionatutako datuak ezabatu egin dira. Laguntza lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Work profila ez dago erabilgarri gailu honetan."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Sareko trafikoa gainbegiratzen da"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Xehetasun gehiago lortzeko, sakatu hau"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Sakatu informazio gehiago lortzeko"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Gailuko datuak ezabatu egingo dira"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administrazio-aplikazioaren osagai batzuk falta dira edo aplikazioa hondatuta dago eta ezin da erabili. Gailuko datuak ezabatu egingo dira. Laguntza lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="me" msgid="6545696007631404292">"Ni"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta kokapena."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Keinuak egin"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Hatz-marken keinuak"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Gailuaren hatz-marken sentsorean egindako keinuak antzeman ditzake."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Desgaitu edo aldatu egoera-barra"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Bihurtu egoera-barra"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zuk ezer egin beharrik gabe deiak egiteko IMS zerbitzua erabiltzea baimentzen die aplikazioei."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonoaren egoera eta identitatea irakurtzea"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"Bideratu deiak sistemaren bidez"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Deiak sistemaren bidez bideratzea baimentzen dio aplikazioari, deien zerbitzua ahal bezain ona izan dadin."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Irakurri telefono-zenbakia"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gailuaren telefono-zenbakia atzitzea baimentzen dio aplikazioari."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Eragotzi tableta inaktibo ezartzea"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Ezabatu"</string>
<string name="inputMethod" msgid="1653630062304567879">"Idazketa-metodoa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Testu-ekintzak"</string>
+ <string name="email" msgid="4560673117055050403">"Posta"</string>
+ <string name="dial" msgid="2275093056198652749">"Telefonoa"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -1064,7 +1071,7 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi eginbidea ezin da Internetera konektatu"</string>
+ <string name="wifi_no_internet" msgid="8451173622563841546">"Ezin da konektatu Internetera Wi-Fi bidez"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
<string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Sakatu aukera gehiago ikusteko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Sakatu USB arazketa desgaitzeko."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Akatsen txostena sortzen…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Akatsen txostena partekatu nahi duzu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Akatsen txostena partekatzen…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Instalazio-saioak irakurtzea baimentzen die aplikazioei. Horrela, pakete-instalazio aktiboei buruzko xehetasunak ikus ditzakete."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Eskatu instalazio-paketeak"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Paketeak instalatzeko eskatzea baimentzen die aplikazioei."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"Eskatu paketeak ezabatzeko"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Paketeak ezabatzeko eskatzea baimentzen die aplikazioei."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Eskatu bateriaren optimizazioei ez ikusi egitea"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Bateriaren optimizazioei ez ikusi egiteko baimena eskatzea baimentzen die aplikazioei."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Sakatu birritan zooma kontrolatzeko"</string>
@@ -1225,7 +1236,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Horma-papera"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Errealitate birtualeko hautemailea"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"EB hautemailea"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Baldintza-hornitzailea"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Jakinarazpenen sailkapen-zerbitzua"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN eginbidea aktibatuta"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kendu"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Erabilerraztasuna gaitzeko eduki pantaila bi hatzekin sakatuta."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Erabilerraztasuna gaitu da."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erabilerraztasuna bertan behera utzi da."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Erabilerraztasun-lasterbidea AKTIBATUTA dago"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatzeko edo desaktibatzeko eduki sakatuta bi bolumen-teklak batera hiru segundoz.\n\nZerbitzua aldatzeko, joan Ezarpenak &gt; Erabilerraztasuna atalera."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desaktibatu lasterbidea"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Utzi aktibatuta"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
<string name="user_switched" msgid="3768006783166984410">"Uneko erabiltzailea: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailera aldatzen…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen saioa amaitzen…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferentzia-deia"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Aholkua"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jokoak"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musika eta audioa"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmak eta bideoak"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Argazkiak eta irudiak"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sare sozialak eta komunikazioa"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Albisteak eta aldizkariak"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapak eta nabigazioa"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktibitatea"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Gailuaren memoria"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-fa-watch/styles_material.xml b/core/res/res/values-fa-watch/styles_material.xml
deleted file mode 100644
index 23b9a7eed18c..000000000000
--- a/core/res/res/values-fa-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"کاندیدها"</font></string>
-</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d6ef85acfe27..1e1c8fa44db8 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"برنامه سرپرست نمایه کار وجود ندارد یا خراب است. در نتیجه، نمایه کاریتان و اطلاعات مرتبط حذف شده است. برای دریافت راهنمایی با سرپرستتان تماس بگیرید."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"نمایه کاری شما دیگر در این دستگاه در دسترس نیست."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ترافیک شبکه، تحت نظارت است"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"برای جزئیات بیشتر ضربه بزنید"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"برای اطلاعات بیشتر ضربه بزنید"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"دستگاهتان پاک خواهد شد"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"برنامه سرپرست بخش‌هایی را ندارد یا خراب است، و نمی‌تواند استفاده شود. دستگاهتان اکنون پاک می‌شود. برای این که راهنمایی شوید، با سرپرستتان تماس بگیرید."</string>
<string name="me" msgid="6545696007631404292">"من"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"سطح و موقعیت بزرگ‌نمایی نمایشگر را کنترل کنید."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اجرای اشاره‌ها"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"می‌توانید ضربه بزنید، انگشتتان را تند بکشید، انگشتانتان را به هم نزدیک یا از هم دور کنید و اشاره‌های دیگری اجرا کنید."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"اشاره‌های اثر انگشت"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"می‌تواند اشاره‌های انجام‌شده روی حسگر اثرانگشت دستگاه‌ها را ثبت کند."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"غیرفعال کردن یا تغییر نوار وضعیت"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"‏به برنامه اجازه می‎دهد تا نوار وضعیت را غیرفعال کند یا نمادهای سیستم را اضافه یا حذف کند."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"نوار وضعیت باشد"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏به برنامه اجازه می‌دهد از سرویس IMS برای برقراری تماس‌ها بدون دخالت شما استفاده کند."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"خواندن وضعیت تلفن و شناسه"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"به برنامه اجازه می‌دهد به ویژگی‌های تلفن دستگاه شما دسترسی پیدا کند. این مجوز به برنامه اجازه می‌دهد شماره تلفن و شناسه‌های دستگاه، فعال بودن یک تماس و شماره راه دوری که با یک تماس متصل شده است را مشخص کند."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"برقرار کردن تماس‌ها ازطریق سیستم"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"به برنامه امکان می‌دهد برای بهبود تجربه تماس، تماس‌هایش را ازطریق سیستم برقرار کند."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"خواندن شماره تلفن"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"به برنامه اجازه می‌دهد به شماره تلفن دستگاه دسترسی پیدا کند."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
<string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
+ <string name="email" msgid="4560673117055050403">"رایانامه"</string>
+ <string name="dial" msgid="2275093056198652749">"شماره‌گیری"</string>
+ <string name="map" msgid="5441053548030107189">"نقشه"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"حافظه درحال پر شدن است"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"فضای ذخیره‌سازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راه‌اندازی مجدد کنید."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"برای گزینه‌های بیشتر ضربه بزنید."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏اشکال‌زدایی USB متصل شد"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"‏برای غیرفعال کردن اشکال‌زدایی USB ضربه بزنید."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏انتخاب کنید تا رفع عیب USB غیرفعال شود."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"درحال گرفتن گزارش اشکال…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراک‌گذاری گزارش اشکال…‏"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"به برنامه اجازه می‌دهد جلسات نصب را بخواند. این کار به برنامه اجازه می‌دهد جزئیات نصب‌های بسته فعال را ببیند."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"درخواست نصب بسته"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"به برنامه اجازه می‌دهد درخواست نصب بسته‌بندی کند."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"درخواست حذف بسته‌ها"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"به برنامه اجازه می‌دهد حذف بسته‌ها را درخواست کند."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"درخواست نادیده‌گرفتن بهینه‌سازی باتری"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"به یک برنامه اجازه می‌دهد جهت نادیده گرفتن بهینه‌سازی باتری برای خود مجوز درخواست کند."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"برای کنترل بزرگ‌نمایی، دو بار ضربه بزنید"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"حذف"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"میزان صدا را به بالاتر از حد توصیه شده افزایش می‌دهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی می‌تواند به شنوایی‌تان آسیب وارد کند."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"برای فعال کردن دسترس‌پذیری، با دو انگشت خود همچنان به طرف پایین فشار دهید."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"قابلیت دسترسی فعال شد."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"دسترس‌پذیری لغو شد."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"«میان‌بر دسترس‌پذیری» روشن است"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"با هم‌زمان پایین نگه‌داشتن دکمه‌های صدا به مدت ۳ ثانیه، <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن یا خاموش کنید.\n\nمی‌توانید در «تنظیمات &gt; دسترس‌پذیری» سرویس را تغییر دهید."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"خاموش کردن میان‌بر"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"روشن بماند"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
<string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"در حالت تغییر به <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"در حال خروج از سیستم <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> غیرفعال شد"</string>
<string name="conference_call" msgid="3751093130790472426">"تماس کنفرانسی"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"نکته‌ابزار"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"بازی"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"موسیقی و صوت"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"فیلم و ویدیو"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"عکس و تصویر"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"اجتماعی و ارتباطات"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"اخبار و مجله"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"نقشه و پیمایش"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"بهره‌وری"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"حافظه دستگاه"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-fi-watch/styles_material.xml b/core/res/res/values-fi-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-fi-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 943b8e7927d2..c3c2c65567f0 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Työprofiilin järjestelmänvalvojasovellus puuttuu tai se on vioittunut. Tästä syystä työprofiilisi ja siihen liittyvät tiedot on poistettu. Pyydä ohjeita järjestelmänvalvojaltasi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Työprofiilisi ei ole enää käytettävissä tällä laitteella."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Verkkoliikennettä seurataan"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Katso lisätietoja napauttamalla."</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Lue lisää napauttamalla."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Laitteen tiedot poistetaan"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Järjestelmänvalvojasovelluksesta puuttuu osia tai se on vioittunut, eikä sitä voi käyttää. Laitteen tiedot poistetaan. Pyydä ohjeita järjestelmänvalvojaltasi."</string>
<string name="me" msgid="6545696007631404292">"Minä"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Hallinnoi näytön zoomaustasoa ja asettelua."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Eleiden käyttäminen"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Lupa napauttaa, pyyhkäistä, nipistää ja käyttää muita eleitä."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Sormenjälkieleet"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Voi tallentaa laitteen sormenjälkitunnistimella tehtyjä eleitä."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"poista tilapalkki käytöstä tai muokkaa tilapalkkia"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Antaa sovelluksen poistaa tilapalkin käytöstä ja lisätä tai poistaa järjestelmäkuvakkeita."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"sijaita tilapalkissa"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Antaa sovelluksen soittaa puheluita pikaviestipalvelun avulla ilman käyttäjän toimia."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lue puhelimen tila ja identiteetti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Antaa sovelluksen käyttää laitteen puhelinominaisuuksia. Sovellus voi määrittää puhelinnumeron ja laitteen tunnuksen, puhelun tilan sekä soitetun numeron."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ohjata puhelut järjestelmän kautta"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Tämä sallii sovelluksen ohjata puhelut järjestelmän kautta, mikä auttaa parantamaan puhelujen laatua."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lukea puhelinnumeron"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Anna sovelluksen käyttää laitteen puhelinnumeroa."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"estä tablet-laitetta menemästä virransäästötilaan"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Poista"</string>
<string name="inputMethod" msgid="1653630062304567879">"Syöttötapa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoiminnot"</string>
+ <string name="email" msgid="4560673117055050403">"Sähköposti"</string>
+ <string name="dial" msgid="2275093056198652749">"Puhelu"</string>
+ <string name="map" msgid="5441053548030107189">"Kartta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tallennustila ei riitä. Varmista, että vapaata tilaa on 250 Mt, ja käynnistä uudelleen."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Näet lisää vaihtoehtoja napauttamalla."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Poista USB-vianetsintä käytöstä napauttamalla."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Luodaan virheraporttia…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Jaetaanko virheraportti?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Jaetaan virheraporttia…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Sallii sovelluksen lukea asennusistuntoja. Toiminto sallii sovelluksen lukea aktiivisten asennuspakettien tietoja."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"pyytää asennuspaketteja"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Antaa sovelluksen pyytää pakettien asennusta."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"pyydä pakettien poistamista"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Antaa sovelluksen pyytää pakettien poistamista."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Lupa ohittaa akun optimoinnit"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Sallii sovelluksen pyytää lupaa ohittaa tietyn sovelluksen akun optimoinnit."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Hallitse zoomausta napauttamalla kahdesti"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuaalitodellisuuden kuuntelija"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-kuuntelija"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ehtojen toimituspalvelu"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Ilmoitusten sijoituspalvelu"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Ota esteettömyystila käyttöön koskettamalla pitkään kahdella sormella."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Esteettömyystila käytössä."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Esteettömyystila peruutettu."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Esteettömyystilan pikanäppäin on KÄYTÖSSÄ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ota <xliff:g id="SERVICE_NAME">%1$s</xliff:g> käyttöön tai poista se käytöstä pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan.\n\nVoit vaihtaa palvelun kohdassa Asetukset &gt; Esteettömyys."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Poista pikanäppäin käytöstä"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Pidä käytössä"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
<string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Vaihdetaan käyttäjään <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> kirjautuu ulos…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
<string name="conference_call" msgid="3751093130790472426">"Puhelinneuvottelu"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Työkaluvinkki"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Pelit"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musiikki ja audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Elokuvat ja videot"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Kuvat ja valokuvat"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Some ja viestintä"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Uutiset ja lehdet"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kartat ja navigointi"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Tuottavuus"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Laitteen tallennustila"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-fr-rCA-watch/styles_material.xml b/core/res/res/values-fr-rCA-watch/styles_material.xml
deleted file mode 100644
index f692d5c781e8..000000000000
--- a/core/res/res/values-fr-rCA-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidats"</font></string>
-</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 3deefd3182c8..7e051c9c2b06 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Le profil professionnel de l\'application d\'administration est manquant ou corrompu. Votre profil professionnel et ses données connexes ont donc été supprimés. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Votre profil professionnel n\'est plus accessible sur cet appareil."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Le trafic réseau est surveillé"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Touchez ici pour obtenir plus de détails"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Touchez ici pour en savoir plus"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Le contenu de votre appareil sera effacé"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Des éléments de l\'application d\'administration sont manquants ou celle-ci est corrompue, ce qui la rend inutilisable. Le contenu de votre appareil sera maintenant effacé. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
<string name="me" msgid="6545696007631404292">"Moi"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Peut toucher, balayer, pincer et effectuer d\'autres gestes."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestes sur le capteur d\'empreintes digitales"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Peut capturer des gestes effectués sur le capteur d\'empreintes digitales des appareils."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"désactiver ou modifier la barre d\'état"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"servir de barre d\'état"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet à l\'application d\'utiliser le service IMS pour faire des appels sans votre intervention."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"acheminer les appels dans le système"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permet à l\'application d\'acheminer ses appels dans le système afin d\'améliorer l\'expérience d\'appel."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lire le numéro de téléphone"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet à l\'application d\'accéder au numéro de téléphone de l\'appareil."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
<string name="inputMethod" msgid="1653630062304567879">"Mode de saisie"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
+ <string name="email" msgid="4560673117055050403">"Courriel"</string>
+ <string name="dial" msgid="2275093056198652749">"Composer"</string>
+ <string name="map" msgid="5441053548030107189">"Carte"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Touchez pour désactiver le débogage USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création d\'un rapport de bogue en cours..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bogue?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bogue en cours..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet à une application d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des paquets actifs."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"demander l\'installation de paquets"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet à une application de demander l\'installation de paquets."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"demander la suppression de paquets"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permet à une application de demander la suppression de paquets."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"demander d\'ignorer les optimisations de la pile"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet à une application de demander la permission d\'ignorer les optimisations de la pile."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Pour activer l\'accessibilité, appuyez de manière prolongée avec deux doigts."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Le raccourci d\'accessibilité est activé"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Activez ou désactivez la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g> en maintenant enfoncées les deux touches de volume pendant trois secondes.\n\nVous pouvez modifier le service sous Paramètres &gt; Accessibilité."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Désactiver le raccourci"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Laisser activé"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Changement d\'utilisateur (<xliff:g id="NAME">%1$s</xliff:g>) en cours…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g> en cours..."</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Infobulle"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jeux"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musique et audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Films et vidéos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos et images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Réseaux sociaux et communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Actualités et magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Cartes et navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivité"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Mémoire de l\'appareil"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-fr-watch/styles_material.xml b/core/res/res/values-fr-watch/styles_material.xml
deleted file mode 100644
index f692d5c781e8..000000000000
--- a/core/res/res/values-fr-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidats"</font></string>
-</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7abb6546a819..b8fcf283d852 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"L\'application d\'administration du profil professionnel est manquante ou endommagée. Par conséquent, votre profil professionnel et toutes les données associées ont été supprimés. Pour obtenir de l\'aide, contactez l\'administrateur."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Votre profil professionnel n\'est plus disponible sur cet appareil."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Le trafic réseau est surveillé"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Appuyez ici pour en savoir plus"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Appuyez sur cette notification pour en savoir plus"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Les données de votre appareil vont être effacées"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Certains composants de l\'application d\'administration sont manquants ou endommagés, et l\'application est donc inutilisable. Les données de votre appareil vont maintenant être effacées. Pour obtenir de l\'aide, contactez l\'administrateur."</string>
<string name="me" msgid="6545696007631404292">"Moi"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestes avec l\'empreinte digitale"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Peut enregistrer des gestes effectués sur le lecteur d\'empreinte digitale de l\'appareil."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"remplacer la barre d\'état"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permet à l\'application d\'utiliser le service IMS pour passer des appels sans votre intervention."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"acheminer les appels via le système"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Autorise l\'application à acheminer les appels via le système afin d\'optimiser le confort d\'utilisation."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lire le numéro de téléphone"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permet à l\'application d\'accéder au numéro de téléphone de l\'appareil."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
<string name="inputMethod" msgid="1653630062304567879">"Mode de saisie"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Composer"</string>
+ <string name="map" msgid="5441053548030107189">"Carte"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Appuyez ici pour plus d\'options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Appuyez ici pour désactiver le débogage USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création du rapport de bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bug ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bug…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permet à une application d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des packages actifs."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"demander l\'installation de packages"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permet à une application de demander l\'installation de packages."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"demander la suppression de packages"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permet à une application de demander la suppression de packages."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"demander à ignorer les optimisations de batterie"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Autorise une application à demander l\'autorisation d\'ignorer les optimisations de batterie pour cette application."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Pour activer l\'accessibilité, appuyez de manière prolongée avec deux doigts."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Le raccourci d\'accessibilité est activé"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Pour activer ou désactiver <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, appuyez sur les deux boutons de volume pendant trois secondes.\n\nVous pouvez modifier le service dans Paramètres &gt; Accessibilité."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Désactiver le raccourci"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Laisser activé"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Chargement du profil de <xliff:g id="NAME">%1$s</xliff:g>..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
<string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Info-bulle"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jeux"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musique et audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Films et vidéos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos et images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Réseaux sociaux et communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Actualités et magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Plans et navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivité"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Mémoire de l\'appareil"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-gl-watch/styles_material.xml b/core/res/res/values-gl-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-gl-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9b0f66635410..5d316f67ea79 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Falta a aplicación de administración no perfil de traballo ou ben está danada. Como resultado, eliminouse o teu perfil de traballo e os datos relacionados. Ponte en contacto co teu administrador para obter asistencia."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"O teu perfil de traballo xa non está dispoñible neste dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Estase controlando o tráfico da rede"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toca para obter máis información"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toca para obter máis información"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Borrarase o teu dispositivo"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Non se pode utilizar a aplicación de administración porque lle faltan compoñentes ou están danados. Agora borrarase o teu dispositivo. Ponte en contacto co teu administrador para obter asistencia."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nivel do zoom e o posicionamento da pantalla"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar xestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Podes tocar, pasar o dedo, beliscar e realizar outros xestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Xestos de impresión dixital"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode rexistrar os xestos realizados no sensor de impresión dixital dos dispositivos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar a barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite á aplicación desactivar a barra de estado ou engadir e eliminar as iconas do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"actuar como a barra de estado"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que a aplicación use o servizo de IMS para facer chamadas sen a túa intervención."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do teléfono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite á aplicación acceder ás funcións de teléfono do dispositivo. Con este permiso a aplicación pode determinar o número de teléfono e os ID do dispositivo, se unha chamada está activa e o número remoto conectado mediante unha chamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"dirixir as chamadas a través do sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite á aplicación dirixir as súas chamadas a través do sistema para mellorar a túa experiencia durante as chamadas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de teléfono"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que a aplicación acceda ao número de teléfono do dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que a tableta entre en modo de inactividade"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Accións de texto"</string>
+ <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
+ <string name="dial" msgid="2275093056198652749">"Marcador"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Estase esgotando o espazo de almacenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"É posible que algunhas funcións do sistema non funcionen"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Non hai almacenamento suficiente para o sistema. Asegúrate de ter un espazo libre de 250 MB e reinicia o dispositivo."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver máis opcións."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para desactivar a depuración de erros de USB."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de erros…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Queres compartir o informe de erros?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartindo informe de erros..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que unha aplicación consulte as sesións de instalación. Desta forma, pode ver os detalles acerca das instalacións de paquetes activas."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar instalación de paquetes"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite a unha aplicación solicitar a instalación dos paquetes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar a eliminación dos paquetes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite a unha aplicación solicitar a eliminación dos paquetes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pedir que se ignore a optimización da batería"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Fai que unha aplicación poida solicitar permiso para ignorar as optimizacións da batería."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toca dúas veces para controlar o zoom"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Continúa premendo con dous dedos para activar a accesibilidade."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accesibilidade activada"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidade cancelada"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"O atallo de accesibilidade está ACTIVADO"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Mantén premidos os botóns de subir e baixar volume para activar ou desactivar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>.\n\nPodes cambiar o servizo en Configuración &gt; Accesibilidade."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desactivar atallo"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Deixar activado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuario actual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Pechando sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia telefónica"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Cadro de información"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Xogos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música e audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Películas e vídeo"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos e imaxes"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Redes sociais e comunicación"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Noticias e revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegación"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamento do dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-gu-watch/styles_material.xml b/core/res/res/values-gu-watch/styles_material.xml
deleted file mode 100644
index 21c687108c08..000000000000
--- a/core/res/res/values-gu-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ઉમેદવારો"</font></string>
-</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index db022861b531..b5c243b8cd3d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"કાર્ય પ્રોફાઇલ વ્યવસ્થાપક ઍપ્લિકેશન કાં તો ખૂટે છે અથવા દૂષિત છે. પરિણામે, તમારી કાર્ય પ્રોફાઇલ અને સંબંધિત ડેટા કાઢી નાખવામાં આવ્યો છે. સહાયતા માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"આ ઉપકરણ પર તમારી કાર્ય પ્રોફાઇલ હવે ઉપલબ્ધ નથી."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"નેટવર્ક ટ્રાફિક મૉનિટર કરવામાં આવી રહ્યું છે"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"વધુ વિગતો માટે ટૅપ કરો"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"વધુ જાણવા માટે ટૅપ કરો"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"એડમિન એપ્લિકેશનમાં ઘટકો ખૂટે છે અથવા દૂષિત છે અને વાપરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે. સહાયતા માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="me" msgid="6545696007631404292">"હું"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"પ્રદર્શનનું ઝૂમ સ્તર અને સ્થિતિનિર્ધારણ નિયંત્રિત કરો."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"હાવભાવ કરો"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ટૅપ, સ્વાઇપ, પિંચ કરી અને અન્ય હાવભાવ કરી શકે છે."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ફિંગરપ્રિન્ટ હાવભાવો"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ઉપકરણોનાં ફિંગરપ્રિન્ટ સેન્સર પર ભજવેલા હાવભાવ કૅપ્ચર કરી શકે છે."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"સ્થિતિ બાર અક્ષમ કરો અથવા સંશોધિત કરો"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"એપ્લિકેશનને સ્થિતિ બાર અક્ષમ કરવાની અથવા સિસ્ટમ આયકન્સ ઉમેરવા અને દૂર કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"સ્થિતિ બાર થાઓ"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"તમારા હસ્તક્ષેપ વગર કૉલ્સ કરવા માટે IMS સેવાનો ઉપયોગ કરવાની એપ્લિકેશનને મંજૂરી આપે છે."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ફોન સ્થિતિ અને ઓળખ વાંચો"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"એપ્લિકેશનને ફોન સુવિધાઓને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને ફોન નંબર અને ઉપકરણ ID, કૉલ સક્રિય છે અને કોઈ કૉલ દ્વારા કનેક્ટ થયેલ રિમોટ નંબર નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"સિસ્ટમ મારફતે કૉલ બીજે વાળો"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"કૉલિંગ અનુભવ સુધારવા માટે ઍપ્લિકેશનને સિસ્ટમ મારફતે કૉલ બીજે વાળવાની મંજૂરી આપે છે."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ફોન નંબર વાંચવા"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ઍપ્લિકેશનને ઉપકરણના ફોન નંબરને ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ટેબ્લેટને નિષ્ક્રિય થતું અટકાવો"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"કાઢી નાખો"</string>
<string name="inputMethod" msgid="1653630062304567879">"ઇનપુટ પદ્ધતિ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ટેક્સ્ટ ક્રિયાઓ"</string>
+ <string name="email" msgid="4560673117055050403">"ઇમેઇલ"</string>
+ <string name="dial" msgid="2275093056198652749">"ડાયલ કરો"</string>
+ <string name="map" msgid="5441053548030107189">"નકશો"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"સ્ટોરેજ સ્થાન સમાપ્ત થયું"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"કેટલાક સિસ્ટમ કાર્યો કામ કરી શકશે નહીં"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"સિસ્ટમ માટે પર્યાપ્ત સ્ટોરેજ નથી. ખાતરી કરો કે તમારી પાસે 250MB ખાલી સ્થાન છે અને ફરીથી પ્રારંભ કરો."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"વધુ વિકલ્પો માટે ટૅપ કરો."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ડીબગિંગ અક્ષમ કરવા માટે ટૅપ કરો."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"એપ્લિકેશનને ઇન્સ્ટોલ સત્રોને વાંચવાની મંજૂરી આપે છે. આ તેને સક્રિય પૅકેજ ઇન્સ્ટોલેશન્સ વિશે વિગતો જોવાની મંજૂરી આપે છે."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"પૅકેજેસ ઇન્સ્ટૉલ કરવાની વિનંતી કરો"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"એપ્લિકેશનને પૅકેજેસના ઇન્સ્ટોલેશનની વિનંતી કરવાની મંજૂરી આપો."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"પૅકેજો કાઢી નાખવાની વિનંતી કરો"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ઍપ્લિકેશનને પૅકેજો કાઢી નાખવાની વિનંતી કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવા માટે પૂછો"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ઍપ્લિકેશનને તે ઍપ્લિકેશન માટે બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવાની પરવાનગી આપવા માટે પૂછવાની મંજૂરી આપે છે."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ઝૂમ નિયંત્રણ માટે બેવાર ટૅપ કરો"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"દૂર કરો"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ઍક્સેસિબિલિટી સક્ષમ કરવા માટે બે આંગળીઓ પકડી રાખો."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ઍક્સેસિબિલિટી સક્ષમ કરી."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ઍક્સેસિબિલિટી રદ કરી."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ઍક્સેસિબિલિટી શૉર્ટકટ ચાલુ છે"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખીને <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ અથવા બંધ કરો. \n\nસેટિંગ્સ અને ઍક્સેસિબિલિટીમાં જઈને તમે સેવાઓ બદલી શકો છે."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"શૉર્ટકટ બંધ કરો"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ચાલુ છોડો"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી"</string>
<string name="user_switched" msgid="3768006783166984410">"વર્તમાન વપરાશકર્તા <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> પર સ્વિચ કરી રહ્યાં છે…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> લોગ આઉટ થઈ રહ્યાં છે…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> અક્ષમ કર્યું"</string>
<string name="conference_call" msgid="3751093130790472426">"કોન્ફરન્સ કૉલ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ટૂલટિપ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"રમતો"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"સંગીત અને ઑડિઓ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"મૂવી અને વિડિઓ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ફોટા અને છબીઓ"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"સામાજિક અને સંચાર"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"સમાચાર અને સામાયિકો"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"નકશા અને નેવિગેશન"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ઉત્પાદકતા"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ઉપકરણ સ્ટૉરેજ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-hi-watch/styles_material.xml b/core/res/res/values-hi-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-hi-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 29ead1da701f..f2c3d4384dd9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -156,10 +156,10 @@
<string name="httpErrorConnect" msgid="8714273236364640549">"सर्वर से कनेक्ट नहीं किया जा सका."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"सर्वर से संचार नहीं किया जा सका. बाद में पुन: प्रयास करें."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"सर्वर से कनेक्‍शन का समय समाप्त हुआ."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पृष्ठ में कई सर्वर रीडायरेक्‍ट हैं."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पेज में कई सर्वर रीडायरेक्‍ट हैं."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"प्रोटोकॉल समर्थित नहीं है."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"सुरक्षित कनेक्शन स्थापित नहीं किया जा सका."</string>
- <string name="httpErrorBadUrl" msgid="3636929722728881972">"URL अमान्‍य होने के कारण पृष्ठ नहीं खोला जा सका."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"URL अमान्‍य होने के कारण पेज नहीं खोला जा सका."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"फ़ाइल पर नहीं पहुंचा जा सका."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"अनुरोधित फ़ाइल नहीं मिल सकी."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"बहुत सारे अनुरोधों का संसाधन हो रहा है. बाद में पुन: प्रयास करें."</string>
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"कार्य प्रोफ़ाइल व्‍यवस्‍थापक ऐप या तो अनुपलब्‍ध है या दूषित है. परिणाम स्‍वरूप, आपकी कार्य प्रोफ़ाइल और संबंधित डेटा हटा दिया गया है. सहायता के लिए अपने नियंत्रक से संपर्क करें."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"आपकी कार्य प्रोफ़ाइल इस डिवाइस पर उपलब्‍ध नहीं है."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"नेटवर्क ट्रैफ़िक मॉनीटर किया जा रहा है"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"अधिक विवरण के लिए टैप करें"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"अधिक जानने के लिए टैप करें"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"आपके डिवाइस को मिटा दिया जाएगा"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"व्‍यवस्‍थापक ऐप में घटक अनुपलब्‍ध हैं या वह दूषित है और उसका उपयोग नहीं किया जा सकता. आपके डिवाइस को अब मिटा दिया जाएगा. सहायता के लिए अपने नियंत्रक से संपर्क करें."</string>
<string name="me" msgid="6545696007631404292">"मैं"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शन का ज़ूम स्‍तर और स्‍थिति निर्धारण नियंत्रित करें."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"हावभाव निष्पादित करें"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"इस सेवा के द्वारा टैप किया जा सकता है, स्वाइप किया जा सकता है, पिंच किया जा सकता है और अन्य हावभाव निष्पादित किए जा सकते हैं."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फ़िंगरप्रिंट हावभाव"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"डिवाइस फ़िंगरप्रिंट सेंसर पर किए गए हावभाव कैप्चर किए जा सकते हैं."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्‍थिति बार अक्षम या बदलें"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ऐप्स को स्थिति बार अक्षम करने या सिस्‍टम आइकन को जोड़ने या निकालने देता है."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"स्‍थिति बार होने दें"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"आपके हस्‍तक्षेप के बिना कॉल करने के लिए, ऐप को IMS सेवा का उपयोग करने देती है."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्‍थिति और पहचान पढ़ें"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ऐप्स को डिवाइस की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति ऐप्स को फ़ोन नंबर और डिवाइस आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्‍थ नंबर निर्धारित करने देती है."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"सिस्टम के माध्यम से कॉल रूट करें"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"कॉल करने के अनुभव को बेहतर बनाने के लिए ऐप्लिकेशन को सिस्टम के माध्यम से उसके कॉल रूट करने देती है."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फ़ोन नंबर पढ़ें"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ऐप्लिकेशन को डिवाइस का फ़ोन नंबर एक्सेस करने देती है."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्‍क्रिय होने से रोकें"</string>
@@ -773,12 +777,12 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST क्रिया केवल /system/app में इंस्‍टॉल किए गए पैकेज के लिए समर्थित है."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"ऐसा कोई पैकेज नहीं मिला था जो FACTORY_TEST कार्रवाई प्रदान करता हो."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
- <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पेज दर्शाता है:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"मार्गदर्शक की दुबारा पूछें"</string>
- <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"इस पृष्ठ से आगे बढ़ें"</string>
- <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"इस पृष्ठ पर बने रहें"</string>
- <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nक्या आप वाकई इस पृष्ठ से दूर नेविगेट करना चाहते हैं?"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"इस पेज से आगे बढ़ें"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"इस पेज पर बने रहें"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nक्या आप वाकई इस पेज से दूर नेविगेट करना चाहते हैं?"</string>
<string name="save_password_label" msgid="6860261758665825069">"दुबारा पूछें"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"युक्ति: ज़ूम इन और आउट करने के लिए डबल-टैप करें."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"स्‍वत: भरण"</string>
@@ -815,7 +819,7 @@
<string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
<string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
<string name="save_password_never" msgid="8274330296785855105">"कभी नहीं"</string>
- <string name="open_permission_deny" msgid="7374036708316629800">"आपके पास इस पृष्ठ को खोलने की अनुमति नहीं है."</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"आपके पास इस पेज को खोलने की अनुमति नहीं है."</string>
<string name="text_copied" msgid="4985729524670131385">"लेख की क्‍लिपबोर्ड पर प्रतिलिपि बनाई गई."</string>
<string name="more_item_label" msgid="4650918923083320495">"अधिक"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"मेनू+"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"हटाएं"</string>
<string name="inputMethod" msgid="1653630062304567879">"इनपुट विधि"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"लेख क्रियाएं"</string>
+ <string name="email" msgid="4560673117055050403">"ईमेल करें"</string>
+ <string name="dial" msgid="2275093056198652749">"डायल करें"</string>
+ <string name="map" msgid="5441053548030107189">"मानचित्र"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी स्‍थान समाप्‍त हो रहा है"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए पर्याप्त मेमोरी नहीं है. सुनिश्चित करें कि आपके पास 250MB का खाली स्थान है और फिर से प्रारंभ करें."</string>
@@ -1005,7 +1012,7 @@
<string name="force_close" msgid="8346072094521265605">"ठीक है"</string>
<string name="report" msgid="4060218260984795706">"रिपोर्ट करें"</string>
<string name="wait" msgid="7147118217226317732">"प्रतीक्षा करें"</string>
- <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ प्रतिसाद नहीं दे रहा है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"पेज प्रतिसाद नहीं दे रहा है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"एप्‍लि. रीडायरेक्‍ट किया गया"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> को वास्‍तविक रूप से लॉन्‍च किया गया था."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"अधिक विकल्पों के लिए टैप करें."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करना अक्षम करने के लिए टैप करें."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबग करना अक्षम करने के लिए चुनें."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ऐप्लिकेशन को इंस्टॉल सत्रों को पढ़ने देती है. इससे उसे सक्रिय पैकेज इंस्टॉलेशन के बारे में विवरण देखने की अनुमति मिल जाती है."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"पैकेज इंस्टॉल करने का अनुरोध करें"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"किसी ऐप्लिकेशन को पैकेज इंस्टॉल करने के अनुरोध की अनुमति देता है."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"पैकेज हटाने का अनुरोध करें"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"किसी ऐप्लिकेशन को पैकेज हटाने का अनुरोध करने देती है."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"बैटरी ऑप्टिमाइज़ेशन पर ध्यान ना देने के लिए पूछें"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"किसी ऐप्लिकेशन को उस ऐप्लिकेशन के लिए बैटरी ऑप्टिमाइज़ेशन पर ध्यान ना देने की अनुमति के लिए पूछने देता है."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ज़ूम नियंत्रण के लिए दो बार टैप करें"</string>
@@ -1249,7 +1259,7 @@
<string name="next_button_label" msgid="1080555104677992408">"आगे"</string>
<string name="skip_button_label" msgid="1275362299471631819">"अभी नहीं"</string>
<string name="no_matches" msgid="8129421908915840737">"कोई मिलान नहीं"</string>
- <string name="find_on_page" msgid="1946799233822820384">"पृष्ठ पर ढूंढें"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"पेज पर ढूंढें"</string>
<plurals name="matches_found" formatted="false" msgid="1210884353962081884">
<item quantity="one"><xliff:g id="TOTAL">%d</xliff:g> में से <xliff:g id="INDEX">%d</xliff:g></item>
<item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> में से <xliff:g id="INDEX">%d</xliff:g></item>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर अधिक समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"आसान तरीका को सक्षम करने के लिए दो अंगुलियों से नीचे दबाए रखें."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"आसान तरीका सक्षम कर दी है."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"आसान तरीका रद्द की गई."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"एक्सेस-योग्यता शॉर्टकट चालू है"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"दोनों वॉल्‍यूम बटन 3 सेकंड तक दबाए रखकर <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू या बंद करें.\n\nआप सेटिंग &gt; एक्सेस-योग्यता में सेवा बदल सकते हैं."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"शॉर्टकट बंद करें"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"चालू रखें"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"एक्सेस-योग्यता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू किया"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"एक्सेस-योग्यता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद किया"</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> पर स्विच किया जा रहा है…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्‍थान किया जा रहा है…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"कॉन्फ़्रेंस कॉल"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"गेम"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"संगीत और ऑडियो"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"फ़िल्में और वीडियो"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"फ़ोटो और तस्वीरें"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"सामाजिक और संचार"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"समाचार और पत्रिकाएं"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"मानचित्र और मार्गदर्शक"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादकता"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"डिवाइस में जगह"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-hr-watch/styles_material.xml b/core/res/res/values-hr-watch/styles_material.xml
deleted file mode 100644
index 88e5751c04ce..000000000000
--- a/core/res/res/values-hr-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidati"</font></string>
-</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 8e3ed1ce36da..11864c6a0eb5 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Administratorska aplikacija radnog profila nedostaje ili je oštećena. Zbog toga su radni profil i povezani podaci izbrisani. Za pomoć se obratite svom administratoru."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Vaš poslovni profil više nije dostupan na ovom uređaju."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Mrežni se promet prati"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Dodirnite za više pojedinosti"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Dodirnite da biste saznali više"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Uređaj će se izbrisati"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Nije moguće upotrijebiti administratorsku aplikaciju jer joj nedostaju komponente ili je oštećena. Vaš će se uređaj sada izbrisati. Za pomoć se obratite svom administratoru."</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira razinu zumiranja i položaj zaslona."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvođenje pokreta"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirnuti, prijeći prstom, spojiti prste i izvoditi druge pokrete."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti za otisak prsta"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Može snimati pokrete izvršene na senzoru otiska prsta na uređaju."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmjena trake statusa"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikaciji omogućuje onemogućavanje trake statusa ili dodavanje i uklanjanje sistemskih ikona."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"biti traka statusa"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Omogućuje aplikaciji upotrebu usluge izravnih poruka za uspostavljanje poziva bez vaše intervencije."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogućuje pristup telefonskim značajkama uređaja. Ta dozvola aplikaciji omogućuje utvrđivanje telefonskog broja i ID-ova uređaja, je li poziv aktivan te udaljeni broj koji je povezan pozivom."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"preusmjeravati pozive putem sustava"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Omogućuje aplikaciji da preusmjerava pozive putem sustava radi poboljšanja doživljaja."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čitati telefonski broj"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Omogućuje aplikaciji da pristupi telefonskom broju uređaja."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"spriječi mirovanje tabletnog uređaja"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
<string name="inputMethod" msgid="1653630062304567879">"Način unosa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje s tekstom"</string>
+ <string name="email" msgid="4560673117055050403">"E-pošta"</string>
+ <string name="dial" msgid="2275093056198652749">"Biraj"</string>
+ <string name="map" msgid="5441053548030107189">"Karta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno pohrane za sustav. Oslobodite 250 MB prostora i pokrenite uređaj ponovo."</string>
@@ -1161,6 +1168,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za otklanjanje pogrešaka USB-om"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje pogrešaka putem USB-a."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izrada izvješća o programskoj pogrešci…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li podijeliti izvješće o programskoj pogrešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvješća o programskoj pogrešci…"</string>
@@ -1217,6 +1225,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Omogućuje aplikaciji čitanje sesija instaliranja. Aplikacija može vidjeti pojedinosti o aktivnim instaliranjima paketa."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtijevati instaliranje paketa"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Aplikaciji omogućuje zahtijevanje instaliranja paketa."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"zahtijevaj brisanje paketa"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Aplikaciji omogućuje zahtijevanje brisanja paketa."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"tražiti zanemarivanje optimizacija baterije"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Aplikaciji omogućuje da traži dopuštenje za zanemarivanje optimizacija baterije za tu aplikaciju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dvaput dotaknite za upravljanje zumiranjem"</string>
@@ -1444,9 +1454,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pristupačnost je omogućena."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Prečac pristupačnosti UKLJUČEN"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uključite ili isključite tako što ćete obje tipke za glasnoću pritisnuti 3 sekunde.\n\nUslugu možete promijeniti u Postavkama &gt; Pristupačnost."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Isključi prečac"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ostavi uključeno"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Odjavljivanje korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1702,20 +1715,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Opis"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Igre"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Glazba i zvuk"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmovi i videozapisi"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotografije i slike"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Društvene mreže i komunikacija"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Vijesti i časopisi"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Karte i navigacija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Pohrana na uređaju"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-hu-watch/styles_material.xml b/core/res/res/values-hu-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-hu-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f58f365a58bb..4c6d44023793 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"A munkahelyi profil rendszergazda alkalmazása hiányzik vagy sérült. A rendszer ezért törölte munkahelyi profilját, és az ahhoz kapcsolódó adatokat. Ha segítségre van szüksége, vegye fel a kapcsolatot rendszergazdájával."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Munkaprofilja már nem érhető el ezen az eszközön."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"A hálózati forgalmat figyelik"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Koppintson, ha további információt szeretne"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Koppintson, ha további információt szeretne kapni"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"A rendszer törölni fogja eszközét"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"A rendszergazda alkalmazás egyes részei hiányoznak, vagy az alkalmazás sérült, ezért nem használható. A rendszer most törölni fogja eszközét. Ha segítségre van szüksége, vegye fel a kapcsolatot rendszergazdájával."</string>
<string name="me" msgid="6545696007631404292">"Saját"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"A kijelző nagyítási/kicsinyítési szintjének és pozíciójának vezérlése"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kézmozdulatok végrehajtása"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Koppintás, ujjak gyors csúsztatása és összehúzása, illetve egyéb kézmozdulatok végrehajtása."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Kézmozdulatok az ujjlenyomat-érzékelőn"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Érzékeli az ujjlenyomat-érzékelőn végzett kézmozdulatokat."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"állapotsor kikapcsolása vagy módosítása"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lehetővé teszi az alkalmazás számára az állapotsor kikapcsolását, illetve rendszerikonok hozzáadását és eltávolítását."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"az állapotsor szerepének átvétele"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Az alkalmazás az IMS-szolgáltatást használhatja híváskezdeményezéshez az Ön közbeavatkozása nélkül."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonállapot és azonosító olvasása"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az eszköz telefonálási funkcióihoz. Az engedéllyel rendelkező alkalmazás meghatározhatja a telefonszámot és eszközazonosítókat, hogy egy hívás aktív-e, valamint híváskor a másik fél telefonszámát."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"rendszeren keresztüli hívásirányítás"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"A telefonálási élmény javítása érdekében lehetővé teszi az alkalmazás számára a rendszeren keresztüli hívásirányítást."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefonszám beolvasása"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Engedélyezi az alkalmazás számára, hogy hozzáférjen az eszköz telefonszámához."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"táblagép alvás üzemmódjának megakadályozása"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Törlés"</string>
<string name="inputMethod" msgid="1653630062304567879">"Beviteli mód"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Műveletek szöveggel"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Tárcsázás"</string>
+ <string name="map" msgid="5441053548030107189">"Térkép"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nincs elegendő tárhely a rendszerhez. Győződjön meg arról, hogy rendelkezik 250 MB szabad területtel, majd kezdje elölről."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Koppintson a további beállítások megjelenítéséhez."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Koppintson az USB fejlesztő mód kikapcsolásához."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Válassza ezt az USB hibakeresés kikapcsolásához."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hibajelentés készítése…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Megosztja a hibajelentést?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hibajelentés megosztása…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Engedélyezi az alkalmazásnak a telepítési munkamenetek olvasását. Ezáltal részleteket kaphat az egyes csomagok éppen folyamatban lévő telepítéséről."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"telepítőcsomagok kérése"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lehetővé teszi az alkalmazás számára csomagok telepítésének kérését."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"csomagok törlésének kérése"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Lehetővé teszi az alkalmazás számára, hogy csomagok törlését kérje."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Akkumulátoroptimalizálási beállítások mellőzésének kérése"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Az alkalmazás engedélyt kérhet az akkumulátoroptimalizálási beállítások mellőzésére."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Érintse meg kétszer a nagyítás beállításához"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Továbbra is tartsa lenyomva két ujját a hozzáférés engedélyezéséhez."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Hozzáférés engedélyezve"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hozzáférés megszakítva."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"A Kisegítő lehetőségek gyorsparancsa BE van kapcsolva"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> be- vagy kikapcsolásához tartsa 3 másodpercig lenyomva mindkét hangerőgombot.\n\nA szolgáltatást a Beállítások &gt; Kisegítő lehetőségek elemnél módosíthatja."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Gyorsparancs kikapcsolása"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Maradjon bekapcsolva"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Átváltás erre: <xliff:g id="NAME">%1$s</xliff:g>..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> kijelentkeztetése folyamatban van…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenciahívás"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Elemleírás"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Játékok"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Zene és hang"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmek és videó"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotók és képek"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Közösségi és kommunikációs"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Hírlapok és folyóiratok"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Térképek és navigáció"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Irodai alkalmazások"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Eszköztárhely"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-hy-watch/styles_material.xml b/core/res/res/values-hy-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-hy-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index c1702c002297..276a3264b663 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Աշխատանքային պրոֆիլի ադմինիստրատորի հավելվածը բացակայում է կամ վնասված է: Արդյունքում ձեր աշխատանքային պրոֆիլը և առնչվող տվյալները ջնջվել են: Օգնության համար դիմեք ձեր ադմինիստրատորին:"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Ձեր աշխատանքային պրոֆիլն այս սարքում այլևս հասանելի չէ:"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Ցանցային թրաֆիկը վերահսկվում է"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Հպեք՝ լրացուցիչ տեղեկություններ ստանալու համար"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Հպեք՝ ավելին իմանալու համար"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Ձեր սարքը ջնջվելու է"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Ադմինիստրատորի հավելվածում բացակայում են բաղադրիչներ կամ այն վնասված է և չի կարող օգտագործվել: Ձեր սարքն այժմ ջնջվելու է: Օգնություն համար դիմեք ձեր ադմինիստրատորին:"</string>
<string name="me" msgid="6545696007631404292">"Իմ"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ցուցասարքի մասշտաբավորման և դիրքավորման կառավարում:"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Կատարել ժեստեր"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Կարող է հպել, թերթել, պտղունցել և կատարել այլ ժեստեր:"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Մատնահետքերի սկաների ժեստեր"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Կարող է նկարահանել մատնահետքերի սկաների վրա կատարվող ժեստերը"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"անջատել կամ փոփոխել կարգավիճակի գոտին"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Թույլ է տալիս հավելվածին անջատել կարգավիճակի գոտին կամ ավելացնել ու հեռացնել համակարգի պատկերակները:"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"լինել կարգավիճակի գոտի"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Թույլ է տալիս հավելվածին IMS ծառայության միջոցով կատարել զանգեր՝ առանց ձեր միջամտության:"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"կարդալ հեռախոսի կարգավիճակը և ինքնությունը"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"զանգերն ուղարկել համակարգի միջոցով"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Հավելվածին թույլ է տալիս իր զանգերն ուղարկել համակարգի միջոցով՝ կապի որակը բարձրացնելու նպատակով։"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"կարդալ հեռախոսահամարը"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարը:"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել պլանշետը քնելուց"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Ջնջել"</string>
<string name="inputMethod" msgid="1653630062304567879">"Մուտքագրման եղանակը"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Տեքստի գործողությունները"</string>
+ <string name="email" msgid="4560673117055050403">"Էլփոստ"</string>
+ <string name="dial" msgid="2275093056198652749">"Համարհավաքել"</string>
+ <string name="map" msgid="5441053548030107189">"Քարտեզ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Պահոցային տարածքը սպառվում է"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Համակարգի որոշ գործառույթներ հնարավոր է չաշխատեն"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Հպեք՝ USB վրիպազերծումն անջատելու համար:"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Ընտրել` USB կարգաբերումը կասեցնելու համար:"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Վրիպակի զեկույցի ստեղծում…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ծրագրին թույլ է տալիս կարդալ տեղադրման աշխատաշրջանները: Սա թույլ է տալիս տեղեկանալ փաթեթների ակտիվ տեղադրումների մանրամասներին:"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"պահանջել տեղադրման փաթեթներ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Թույլ է տալիս հավելվածին պահանջել փաթեթների տեղադրումը:"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"պահանջել փաթեթների ջնջում"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Թույլ է տալիս հավելվածին պահանջել փաթեթների ջնջում:"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"հայցել մարտկոցի օպտիմալացումն անտեսելու թույլտվություն"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Հավելվածին հնարավորություն է տալիս հայցելու թույլտվություն՝ տվյալ հավելվածի համար մարտկոցի օպտիմալացումն անտեսելու համար:"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Հպեք երկու անգամ` խոշորացման վերահսկման համար"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Հեռացնել"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Սեղմած պահեք երկու մատները` մատչելիությունը միացնելու համար:"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Մատչելիությունը միացված է:"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Մուտքի հնարավորությունը չեղարկված է:"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Մատչելիության դյուրանցումը ՄԻԱՑՎԱԾ Է"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Միացրեք կամ անջատեք <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը՝ ձայնի երկու կոճակները 3 վայրկյանի ընթացքում միաժամանակ սեղմած պահելու միջոցով։\n\nԿարող եք փոխել ծառայությունը՝ անցնելով Կարգավորումներ &gt; Մատչելիություն։"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Անջատել դյուրանցումը"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Միացված թողնել"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Մատչելիության դյուրանցումն միացրել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Մատչելիության դյուրանցումն անջատել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
<string name="user_switched" msgid="3768006783166984410">"Ներկայիս օգտատերը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Փոխարկվում է <xliff:g id="NAME">%1$s</xliff:g>-ին..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Ելք <xliff:g id="NAME">%1$s</xliff:g>-ից…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Անջատած <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Կոնֆերանս զանգ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Հուշակ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Խաղեր"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Երաժշտություն և աուդիո"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Ֆիլմեր և տեսանյութեր"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Լուսանկարներ և պատկերներ"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Սոցցանցեր և հաղորդակցություն"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Նորություններ և ամսագրեր"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Քարտեզներ և նավարկում"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Աշխատանք"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Սարքի հիշողություն"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-in-watch/styles_material.xml b/core/res/res/values-in-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-in-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 05560d30efb3..839fc0406102 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Aplikasi admin profil kerja tidak ada atau rusak. Akibatnya, profil kerja dan data terkait telah dihapus. Hubungi administrator untuk meminta bantuan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profil kerja tidak tersedia lagi di perangkat ini."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Traffic jaringan sedang dipantau"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tap untuk detail selengkapnya"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tap untuk mempelajari lebih lanjut"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Perangkat akan dihapus"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Aplikasi admin kehilangan komponen atau rusak, dan tidak dapat digunakan. Perangkat sekarang akan dihapus. Hubungi administrator untuk meminta bantuan."</string>
<string name="me" msgid="6545696007631404292">"Saya"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestur sidik jari"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dapat merekam gestur yang dilakukan di sensor sidik jari perangkat."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Mengizinkan apl menonaktifkan bilah status atau menambah dan menghapus ikon sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"jadikan bilah status"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Memungkinkan aplikasi menggunakan layanan IMS untuk melakukan panggilan tanpa campur tangan Anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca identitas dan status ponsel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"sambungkan panggilan telepon melalui sistem"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Mengizinkan aplikasi menyambungkan panggilan telepon melalui sistem untuk menyempurnakan pengalaman menelepon."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"baca nomor telepon"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Mengizinkan aplikasi mengakses nomor telepon perangkat ini."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"cegah tablet dari tidur"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Hapus"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metode masukan"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Telepon"</string>
+ <string name="map" msgid="5441053548030107189">"Peta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Penyimpanan tidak cukup untuk sistem. Pastikan Anda memiliki 250 MB ruang kosong, lalu mulai ulang."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Ketuk untuk opsi lainnya."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Ketuk untuk menonaktifkan debug USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk menonaktifkan debugging USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bagikan laporan bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Membagikan laporan bug..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Memungkinkan aplikasi membaca sesi pemasangan. Tindakan ini memungkinkannya melihat detail tentang pemasangan paket aktif."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"minta pasang paket"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Mengizinkan aplikasi meminta pemasangan paket."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"meminta menghapus paket"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Mengizinkan aplikasi meminta penghapusan paket."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"meminta mengabaikan pengoptimalan baterai"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Mengizinkan aplikasi meminta izin untuk mengabaikan pengoptimalan baterai bagi aplikasi tersebut."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ketuk dua kali untuk kontrol perbesar/perkecil"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Pemroses Realitas Maya"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Pemroses VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Penyedia ketentuan"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Layanan penentu peringkat notifikasi"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tahan terus dua jari untuk mengaktifkan aksesibilitas."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Aksesibilitas diaktifkan."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Aksesibilitas dibatalkan."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Pintasan Aksesibilitas AKTIF"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Aktifkan atau nonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dengan menekan kedua tombol volume selama 3 detik.\n\nAnda dapat mengubah layanan di Setelan &gt; Aksesibilitas."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Nonaktifkan Pintasan"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Biarkan aktif"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Beralih ke <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Mengeluarkan <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferensi Telepon"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan alat"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Game"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musik &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Film &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto &amp; Gambar"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosial &amp; Komunikasi"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Berita &amp; Majalah"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Peta &amp; Navigasi"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitas"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Penyimpanan perangkat"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-is-watch/styles_material.xml b/core/res/res/values-is-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-is-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 573d014ec2c9..1e2beb01c892 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Stjórnunarforrit vinnusniðsins vantar eða er skemmt. Vinnusniðinu og gögnum því tengdu hefur því verið eytt. Hafðu samband við kerfisstjórann til að fá frekari aðstoð."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Vinnusniðið þitt er ekki lengur í boði á þessu tæki."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Verið er að fylgjast með netumferð"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Ýttu til að fá frekari upplýsingar"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Ýttu til að fá frekari upplýsingar"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Tækið verður hreinsað"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Stjórnunarforritið vantar íhluti eða er skemmt og ekki er hægt að nota það. Þurrkað verður út af tækinu. Hafðu samband við kerfisstjórann til að fá aðstoð."</string>
<string name="me" msgid="6545696007631404292">"Ég"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Stjórnaðu aðdrætti og afstöðu skjásins."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Nota bendingar"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Getur ýtt, strokið, fært fingur saman og gert ýmsar aðrar bendingar."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingrafarabendingar"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Getur fangað bendingar sem eru gerðar á fingrafaraskynjara tækisins."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"slökkva á eða breyta stöðustiku"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Leyfir forriti að slökkva á stöðustikunni eða bæta við og fjarlægja kerfistákn."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vera stöðustikan"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Leyfir forriti að nota IMS-þjónustu til að hringja án inngrips frá þér."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lesa stöðu símans og auðkenni"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leyfir forriti að fá aðgang að símaeiginleikum tækisins. Þessi heimild gerir forritinu kleift að komast að símanúmeri og auðkennum tækisins, hvort símtal er í gangi og símanúmeri viðmælanda í símtali."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"senda símtöl gegnum kerfið"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Heimilar forritinu að senda símtöl sín gegnum kerfið til að bæta gæði símtalsins."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lesa símanúmer"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Veitir forritinu aðgang að símanúmeri tækisins."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"koma í veg fyrir að spjaldtölvan fari í biðstöðu"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Eyða"</string>
<string name="inputMethod" msgid="1653630062304567879">"Innsláttaraðferð"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Textaaðgerðir"</string>
+ <string name="email" msgid="4560673117055050403">"Tölvupóstur"</string>
+ <string name="dial" msgid="2275093056198652749">"Hringja"</string>
+ <string name="map" msgid="5441053548030107189">"Kort"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Geymslurýmið er senn á þrotum"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sumir kerfiseiginleikar kunna að vera óvirkir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Ekki nægt geymslurými fyrir kerfið. Gakktu úr skugga um að 250 MB séu laus og endurræstu."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Ýttu til að sjá fleiri valkosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Ýttu til að slökkva á USB-villuleit."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Tekur við villutilkynningu…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deila villutilkynningu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deilir villutilkynningu..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Leyfir forriti að lesa uppsetningarlotur. Þetta gerir því kleift að sjá upplýsingar um virkar pakkauppsetningar."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"fara fram á uppsetningu pakka"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Leyfir forriti að fara fram á uppsetningu pakka."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"biðja um eyðingu á pökkum"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Leyfir forriti að biðja um eyðingu pakka."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"biðja um að hunsa rafhlöðusparnað"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gerir forriti kleift að biðja um heimild til að hunsa rafhlöðusparnað fyrir forritið."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ýttu tvisvar til að opna aðdráttarstýringar"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjarlægja"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Haltu tveimur fingrum áfram á skjánum til að kveikja á auknu aðgengi."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Kveikt á auknu aðgengi."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hætt við aukið aðgengi."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"KVEIKT er á flýtileið aðgengisstillingar"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Kveiktu eða slökktu á <xliff:g id="SERVICE_NAME">%1$s</xliff:g> með því að halda inni báðum tökkunum fyrir hljóðstyrk í þrjár sekúndur.\n\nÞú getur breytt þjónustunni í „Stillingar &gt; Aðgengi“."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Slökkva á flýtileið"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Hafa kveikt"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Núverandi notandi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Skiptir yfir á <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Skráir <xliff:g id="NAME">%1$s</xliff:g> út…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Símafundur"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Ábending"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Leikir"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Tónlist og hljóð"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Kvikmyndir og myndskeið"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Myndir"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Samfélag og samskipti"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Fréttir og tímarit"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kort og leiðsögn"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Aðstoð"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Geymslurými tækis"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-it-watch/styles_material.xml b/core/res/res/values-it-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-it-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 74adcca47cb5..0b7820e708c2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"L\'app di amministrazione dei profili di lavoro manca o è danneggiata. Di conseguenza, il tuo profilo di lavoro e i relativi dati sono stati eliminati. Contatta l\'amministratore per ricevere assistenza."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Il tuo profilo di lavoro non è più disponibile sul dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Il traffico di rete è monitorato"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tocca per ulteriori dettagli"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tocca per ulteriori informazioni"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Il dispositivo verrà resettato"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"L\'app di amministrazione è danneggiata o mancano componenti, pertanto non è possibile utilizzarla. Il dispositivo verrà resettato. Contatta l\'amministratore per ricevere assistenza."</string>
<string name="me" msgid="6545696007631404292">"Io"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlla il livello di zoom e la posizione del display."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Esegui gesti"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesti con sensore di impronte digitali"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"È in grado di rilevare i gesti compiuti con il sensore di impronte digitali dei dispositivi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Consente all\'app di utilizzare il servizio IMS per fare chiamate senza il tuo intervento."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"indirizzamento delle chiamate tramite il sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Consente all\'app di indirizzare le proprie chiamate tramite il sistema al fine di migliorare l\'esperienza di chiamata."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"leggi il numero di telefono"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Consente all\'app di accedere al numero di telefono del dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Elimina"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metodo inserimento"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Azioni testo"</string>
+ <string name="email" msgid="4560673117055050403">"Invia una email"</string>
+ <string name="dial" msgid="2275093056198652749">"Componi"</string>
+ <string name="map" msgid="5441053548030107189">"Mappa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Memoria insufficiente per il sistema. Assicurati di avere 250 MB di spazio libero e riavvia."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tocca per altre opzioni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tocca per disattivare il debug USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleziona per disattivare il debug USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Recupero della segnalazione di bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Condividere la segnalazione di bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Condivisione della segnalazione di bug…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Consente a un\'applicazione di leggere le sessioni di installazione. L\'app può conoscere i dettagli sulle installazioni di pacchetti attive."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"richiesta di pacchetti di installazione"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Consente a un\'applicazione di richiedere l\'installazione di pacchetti."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"richiesta di eliminazione dei pacchetti"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Consente a un\'applicazione di richiedere l\'eliminazione di pacchetti."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"chiedi di ignorare le ottimizzazioni della batteria"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Consente a un\'app di chiedere l\'autorizzazione a ignorare le ottimizzazioni della batteria per quell\'app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener realtà virtuale"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider condizioni"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Servizio di classificazione delle notifiche"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Continua a tenere premuto con due dita per attivare l\'accessibilità."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibilità attivata."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilità annullata."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Scorciatoia Accessibilità attiva"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Attiva o disattiva <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tenendo premuti entrambi i pulsanti del volume per tre secondi.\n\nPuoi cambiare il servizio in Impostazioni &gt; Accessibilità."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Disattiva scorciatoia"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Lascia attiva"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Passaggio a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Disconnessione di <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
<string name="conference_call" msgid="3751093130790472426">"Audioconferenza"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Descrizione comando"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Giochi"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musica e audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Film e video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto e immagini"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social e comunicazione"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Notizie e riviste"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps e Navigatore"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produttività"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memoria dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-iw-watch/styles_material.xml b/core/res/res/values-iw-watch/styles_material.xml
deleted file mode 100644
index f44b272d8315..000000000000
--- a/core/res/res/values-iw-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"מועמדים"</font></string>
-</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 54c370292b58..4361ff253072 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"אפליקציית הניהול של פרופיל העבודה חסרה או פגומה. כתוצאה מכך פרופיל העבודה שלך נמחק, כולל כל הנתונים הקשורים אליו. לקבלת סיוע, פנה למנהל המערכת שלך."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"פרופיל העבודה שלך אינו זמין עוד במכשיר הזה."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"התנועה ברשת מנוטרת"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"הקש לקבלת פרטים נוספים"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"למידע נוסף, הקש"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"תתבצע מחיקה של המכשיר"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"באפליקציית הניהול חסרים מרכיבים או שהיא פגומה ולא ניתן להשתמש בה. תתבצע כעת מחיקה של המכשיר. לקבלת סיוע, פנה למנהל המערכת שלך."</string>
<string name="me" msgid="6545696007631404292">"אני"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"קבע את המרחק מהתצוגה ואת מיקום התצוגה."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ביצוע תנועות"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"יכול להקיש, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"תנועות"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"אפשרות לזהות תנועות בזמן נגיעה בחיישן טביעות האצבע של המכשיר"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"השבת או שנה את שורת המצב"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"מאפשר לאפליקציה להשבית את שורת המצב או להוסיף ולהסיר סמלי מערכת."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"להיות שורת הסטטוס"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏מאפשר לאפליקציה להשתמש בשירות ה-IMS לביצוע שיחות ללא התערבותך."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"קריאת הסטטוס והזהות של הטלפון"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"מאפשר לאפליקציה לגשת לתכונות הטלפון של המכשיר. אישור זה מתיר לאפליקציה לגלות את מספר הטלפון ואת זיהויי המכשיר, האם שיחה פעילה ואת המספר המרוחק המחובר באמצעות שיחה."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ניתוב שיחות דרך המערכת"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"מאפשרת לאפליקציה לנתב את השיחות דרך המערכת כדי לשפר את חוויית השיחה."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"קריאת מספר טלפון"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"מאפשרת לאפליקציה לגשת למספר הטלפון של המכשיר."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"מנע מהטאבלט לעבור למצב שינה"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"מחק"</string>
<string name="inputMethod" msgid="1653630062304567879">"שיטת קלט"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"פעולות טקסט"</string>
+ <string name="email" msgid="4560673117055050403">"אימייל"</string>
+ <string name="dial" msgid="2275093056198652749">"חייג"</string>
+ <string name="map" msgid="5441053548030107189">"מפה"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"‏אין מספיק שטח אחסון עבור המערכת. ודא שיש לך שטח פנוי בגודל 250MB התחל שוב."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"הקש לקבלת אפשרויות נוספות."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"‏הקש כדי להשבית ניפוי באגים של USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏בחר להשבית ניפוי באגים ב-USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"עיבוד דוח על באג..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"האם לשתף דוח על באג?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"מאפשר לאפליקציה לקרוא הפעלות התקנה. הרשאה זו מאפשרת לה לראות פרטים על התקנות פעילות של חבילות."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"בקשה להתקנת חבילות"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"מתיר לאפליקציה לבקש התקנה של חבילות."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"בקשה למחוק חבילות"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"מתיר לאפליקציה לבקש מחיקה של חבילות."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"בקשה להתעלם מאופטימיזציות של הסוללה"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"מאפשר לאפליקציה לבקש רשות להתעלם מאופטימיזציות של הסוללה לאפליקציה הזו."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"הקש פעמיים לבקרת מרחק מתצוגה"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"הסר"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"המשך לגעת בשתי אצבעות כדי להפעיל נגישות."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"נגישות הופעלה."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"נגישות בוטלה."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"קיצור הדרך לנגישות מופעל"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"לחץ על שני לחצני עוצמת הקול בו-זמנית והחזק למשך שלוש שניות כדי להפעיל ולכבות את <xliff:g id="SERVICE_NAME">%1$s</xliff:g>. \n\nכדי לשנות את השירות, עבור אל \'הגדרות\' &gt; \'נגישות\'."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"כבה את קיצור הדרך"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"אל תכבה"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל על-ידי קיצור הדרך לנגישות"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת על-ידי קיצור הדרך לנגישות"</string>
<string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"עובר אל <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"מתבצע ניתוק של <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> הושבת"</string>
<string name="conference_call" msgid="3751093130790472426">"שיחת ועידה"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"הסבר קצר"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"משחקים"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"מוזיקה ואודיו"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"סרטים וסרטונים"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"תמונות"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"תקשורת ורשתות חברתיות"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"חדשות וכתבי עת"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"מפות וניווט"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"פרודוקטיביות"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"שטח האחסון במכשיר"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ja-watch/styles_material.xml b/core/res/res/values-ja-watch/styles_material.xml
deleted file mode 100644
index 7712090be233..000000000000
--- a/core/res/res/values-ja-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"候補"</font></string>
-</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 47b03254bc8c..f3a22cec8719 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"仕事用プロファイルの管理アプリがないか、破損しています。そのため仕事用プロファイルと関連データが削除されました。管理者にサポートをご依頼ください。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"お使いの仕事用プロファイルはこの端末で使用できなくなりました"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ネットワーク トラフィックの監視中"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"タップして詳細を表示します"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"詳細を確認するにはタップします"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"端末のデータが消去されます"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"管理アプリの構成要素が不足しているか、アプリが破損しているため、ご利用になれません。端末のデータはこれから消去されます。管理者にサポートをご依頼ください。"</string>
<string name="me" msgid="6545696007631404292">"自分"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"画面のズームレベルと位置を制御します。"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"操作の実行"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"タップ、スワイプ、ピンチ、その他の操作を行えます。"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋認証センサーでの操作"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"端末の指紋認証センサーで行われた操作をキャプチャできます。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ステータスバーの無効化や変更"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ステータスバーの無効化、システムアイコンの追加や削除をアプリに許可します。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ステータスバーへの表示"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"IMSサービスがユーザー操作なしで電話をかけることをアプリに許可します。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"端末情報と ID の読み取り"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"システム経由での通話転送"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"通話環境の改善のために、システム経由での通話転送をアプリに許可します。"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"電話番号の読み取り"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"端末の電話番号へのアクセスをアプリに許可します。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"削除"</string>
<string name="inputMethod" msgid="1653630062304567879">"入力方法"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"テキスト操作"</string>
+ <string name="email" msgid="4560673117055050403">"メール"</string>
+ <string name="dial" msgid="2275093056198652749">"発信"</string>
+ <string name="map" msgid="5441053548030107189">"地図"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"システムに十分な容量がありません。250MBの空き容量を確保して再起動してください。"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"タップしてその他のオプションを表示します。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"タップして USB デバッグを無効にします。"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USBデバッグを無効にする場合に選択します。"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"バグレポートを取得しています…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"インストールセッションの読み取りをアプリに許可します。これにより、アプリはアクティブパッケージのインストールに関する詳細情報を参照できるようになります。"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"インストールパッケージのリクエスト"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"パッケージのインストールをリクエストすることをアプリケーションに許可します。"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"パッケージの削除のリクエスト"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"パッケージの削除をリクエストすることをアプリに許可します。"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"電池の最適化を無視するかどうかの確認"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"電池の最適化の無視についてアプリが確認することを許可します。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ダブルタップでズームします"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"削除"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ユーザー補助機能を有効にするには2本の指で押し続けてください。"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ユーザー補助が有効になりました。"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ユーザー補助をキャンセルしました。"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ユーザー補助機能のショートカット ON"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を ON または OFF にするには、両方の音量ボタンを 3 秒ほど押し続けます。\n\nこのサービスは [設定] &gt; [ユーザー補助機能] で変更できます。"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"ショートカットを OFF にする"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ON のままにする"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
<string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>に切り替えています…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> をログアウトしています…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"停止済みの「<xliff:g id="LABEL">%1$s</xliff:g>」"</string>
<string name="conference_call" msgid="3751093130790472426">"グループ通話"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ツールチップ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ゲーム"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"音楽&オーディオ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"映画&動画"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"写真&画像"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"ソーシャル&コミュニケーション"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ニュース&雑誌"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"地図&ナビ"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"仕事効率化"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"端末のストレージ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ka-watch/styles_material.xml b/core/res/res/values-ka-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ka-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index fb901364d5fe..9d3b288bb55d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"სამუშაო პროფილის ადმინისტრატორის აპლიკაცია გამოტოვებული ან დაზიანებულია. შედეგად, თქვენი სამუშაო პროფილი და მასთან დაკავშირებული მონაცემები წაიშალა. დახმარებისათვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"თქვენი სამუშაო პროფილი აღარ არის ხელმისაწვდომი ამ მოწყობილობაზე."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ქსელის ტრაფიკი მონიტორინგს გადის"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"შეეხეთ დამატებითი დეტალების სანახავად"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"შეეხეთ, რათა შეიტყოთ მეტი"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"თქვენი მოწყობილობა წაიშლება"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"ადმინისტრატორის აპლიკაციას კომპონენტები აკლია ან დაზიანებულია, შესაბამისად, მისი გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა წაიშლება. დახმარებისათვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
<string name="me" msgid="6545696007631404292">"მე"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ეკრანის მასშტაბირების დონისა და პოზიციის მართვა."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ჟესტების შესრულება"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"შეუძლია შეხება, გადაფურცვლა, მასშტაბირება და სხვა ჟესტების შესრულება."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"თითის ანაბეჭდის ჟესტები"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"შეუძლია აღბეჭდოს მოწყობილობის თითის ანაბეჭდის სენსორზე განხორციელებული ჟესტები."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"სტატუსის ზოლის გათიშვა ან ცვლილება"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"აპს შეეძლება სტატუსების ზოლის გათიშვა და სისტემის ხატულების დამატება/წაშლა."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"სტატუსის ზოლის ჩანაცვლება"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"აპს შეეძლება, გამოიყენოს IMS სერვისი ზარების თქვენი ჩარევის გარეშე განსახორციელებლად."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ტელეფონის სტატუსისა და იდენტობის წაკითხვა"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"აპს შეეძლება ჰქონდეს წვდომა მოწყობილობის სატელეფონო ფუნქციებზე. აპმა მსგავსი უფლებით შეძლებს დაადგინოს ტელეფონის ნომერი, მისი სერიული გამოცემა, აქტიური ზარი, დაკავშირებული ნომერი და მსგავსი."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ზარების სისტემის მეშვეობით მარშრუტიზაცია"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"დარეკვის ხარისხის გაუმჯობესების მიზნით, აპს ზარების სისტემის მეშვეობით მარშრუტიზაციის საშუალებას აძლევს."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ტელეფონის ნომრის წაკითხვა"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"აპს მოწყობილობის ტელეფონის ნომერზე წვდომის საშუალებას მისცემს."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"დაიცავით ტაბლეტი დაძინებისგან"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"წაშლა"</string>
<string name="inputMethod" msgid="1653630062304567879">"შეყვანის მეთოდი"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ქმედებები ტექსტზე"</string>
+ <string name="email" msgid="4560673117055050403">"ელფოსტა"</string>
+ <string name="dial" msgid="2275093056198652749">"დარეკვა"</string>
+ <string name="map" msgid="5441053548030107189">"რუკა"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"თავისუფალი ადგილი იწურება"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"სისტემის ზოგიერთმა ფუნქციამ შესაძლოა არ იმუშავოს"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"სისტემისათვის საკმარისი საცავი არ არის. დარწმუნდით, რომ იქონიოთ სულ მცირე 250 მბაიტი თავისუფალი სივრცე და დაიწყეთ ხელახლა."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"შეეხეთ დამატებითი ვარიანტების სანახავად."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"შეეხეთ USB-გამართვის გასათიშად."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"მონიშნეთ რათა შეწყვიტოთ USB-ის გამართვა"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"საშუალებას აძლევს აპლიკაციას წაიკითხოს ინსტალაციის სესიები. ამით მას საშუალება აქვს იხილოს პაკეტის აქტიური ინსტალაციები."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"პაკეტების ინსტალაციის მოთხოვნა"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"აპლიკაციას შეეძლება მოითხოვოს პაკეტების ინსტალაცია."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"პაკეტების წაშლის მოთხოვნა"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"აპლიკაციას შეეძლება პაკეტების წაშლის მოთხოვნა."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ბატარეის ოპტიმიზაციის იგნორირების მოთხოვნა"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"საშუალებას მისცემს აპს, მოითხოვოს მასთან დაკავშირებული ბატარეის ოპტიმიზაციის იგნორირების ნებართვა."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"მასშტაბის ცვლილებისთვის შეეხეთ ორჯერ"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ამოშლა"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"გეჭიროთ ორი თითი მარტივი წვდომის ჩასართავად."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"მარტივი წვდომა ჩართულია."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"მარტივი წვდომა გაუქმდა."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"მარტივი წვდომის მალსახმობი ჩართულია"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"ჩართეთ ან გამორთეთ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით.\n\nსერვისის შეცვლა შეგიძლიათ აქ: პარამეტრები &gt; მარტივი წვდომა."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"მალსახმობის გამორთვა"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ჩართულად დატოვება"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"ამჟამინდელი მომხმარებელი <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>-ზე გადართვა…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>-ის ანგარიშიდან გასვლა…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"გათიშული <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"საკონფერენციო ზარი"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"მინიშნება"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"თამაშები"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"მუსიკა და აუდიო"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ფილმები და ვიდეო"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ფოტოები და სურათები"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"სოციალური და კომუნიკაცია"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ახალი ამბები და ჟურნალები"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"რუკები და ნავიგაცია"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"პროდუქტიულობა"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"მოწყობილობის მეხსიერება"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-kk-watch/styles_material.xml b/core/res/res/values-kk-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-kk-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 377f0c984520..b168b6fcb677 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Жұмыс профилінің басқару қолданбасы жоқ немесе бүлінген. Нәтижесінде жұмыс профиліңіз және қатысты деректер жойылды. Көмек алу үшін әкімшіге хабарласыңыз."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Жұмыс профиліңіз осы құрылғыда енді қолжетімді емес."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Желі трафигі бақылануда"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Қосымша мәліметтерді көру үшін түртіңіз"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Толығырақ мәліметтер үшін түртіңіз"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Құрылғыңыздағы деректер өшіріледі"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Басқару қолданбасында құрамдастар жетіспейді немесе ол бүлінген және оны пайдалану мүмкін емес. Құрылғыңыздағы деректер қазір өшіріледі. Көмек алу үшін әкімшіге хабарласыңыз."</string>
<string name="me" msgid="6545696007631404292">"Мен"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дисплейдің масштабтау деңгейін және орналастыруды басқару."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Қимылдарды орындау"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Түртуге, сырғытуға, қысуға және басқа қимылдарды орындауға болады."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Саусақ ізі датчигіндегі қимылдар"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Құрылғының саусақ ізі датчигінде орындалған қимылдарды сақтайды"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"күйін көрсету тақтасын өшіру немесе өзгерту"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Қолданбаға күй жолағын өшіруге немесе жүйелік белгішелерді қосуға және жоюға рұқсат береді."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"күй жолағы болу"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Сіздің қатысуыңызсыз қоңыраулар соғу үшін қолданбаға IMS қызметін пайдалануға рұқсат етеді."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"телефон күйін оқу немесе анықтау"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Қолданбаға құрылғыдағы телефон функцияларына кіру мүмкіндігін береді. Бұл рұқсат қолданбаға телефон нөмірі, құрылғы жеке анықтағышы, қоңырау белсенділігі және сол қоңырауға байланысты қашықтағы нөмірді анықтау мүмкіндігін береді."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"қоңырауларды жүйе арқылы бағыттау"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Қоңырау шалу тәжірибесін жақсарту үшін қолданба қоңырауларды жүйе арқылы бағыттай алады."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"телефон нөмірін оқу"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Қолданбаға құрылғының телефон нөмірін алуға рұқсат береді."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"планшетті ұйқыдан бөгеу"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Жою"</string>
<string name="inputMethod" msgid="1653630062304567879">"Енгізу әдісі"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Мәтін әрекеттері"</string>
+ <string name="email" msgid="4560673117055050403">"Электрондық пошта"</string>
+ <string name="dial" msgid="2275093056198652749">"Теру"</string>
+ <string name="map" msgid="5441053548030107189">"Map"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Жадта орын азайып барады"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Жүйенің кейбір функциялары жұмыс істемеуі мүмкін"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Жүйе үшін жад жеткіліксіз. 250 МБ бос орын бар екенін тексеріп, қайта іске қосыңыз."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Қосымша опциялар үшін түртіңіз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB түзетуін өшіру үшін түртіңіз."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Қате туралы есеп алынуда…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Қате туралы есепті бөлісу керек пе?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Қате туралы есеп бөлісілуде…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Қолданбаға орнату сеанстарын оқуға рұқсат етеді. Бұл оған белсенді бума орнатулары туралы мәліметтерді көруге рұқсат етеді."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнату бумаларын сұрау"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Қолданбаның бумаларды орнатуға рұқсат сұрауына мүмкіндік береді."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"пакеттерді жоюға рұқсат сұрау"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Қолданбаның пакеттерді жоюға рұқсат сұрауына мүмкіндік береді."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батареяны оңтайландыру әрекетін елемеуді сұрау"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Қолданба батареяны оңтайландыру әрекетін елемеуді сұрай алады."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабтау параметрін басқару үшін екі рет түртіңіз"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Алып тастау"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Қол жетімділікті қосу үшін екі саусағыңызды төмен басып тұрыңыз."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Қол жетімділік қосылды."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Қол жетімділік өшірілді."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Арнайы мүмкіндіктер таңбашасы ҚОСУЛЫ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Дыбыс деңгейі түймелерін 3 секунд басып тұрып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосыңыз не өшіріңіз.\n\nҚызметті \"Параметрлер &gt; Арнайы мүмкіндіктер\" тармағынан өзгерте аласыз."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Таңбашаны өшіру"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Қосулы қалдыру"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосты"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін өшірді"</string>
<string name="user_switched" msgid="3768006783166984410">"Ағымдағы пайдаланушы <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> ауысу орындалуда…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> ішінен шығу…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өшірулі"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференциялық қоңырау"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Қалқыма сөзкөмек"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Ойындар"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музыка және аудиомазмұн"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Фильм және бейне"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Суреттер және кескіндер"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Әлеуметтік қолданба мен байланыс"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Газеттер және журналдар"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карта және навигация"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Өнімділік"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Құрылғы жады"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-km-watch/styles_material.xml b/core/res/res/values-km-watch/styles_material.xml
deleted file mode 100644
index e54cb0081fa5..000000000000
--- a/core/res/res/values-km-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"បេក្ខជន"</font></string>
-</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 756465c78280..0a57834c7840 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"ប្រវត្តិរូបការងាររបស់អ្នកអាចបាត់បង់ ឬមានបញ្ហា។ ជាលទ្ធផល ប្រវត្តិរូបការងាររបស់អ្នក និងទិន្នន័យដែលពាក់ព័ន្ធត្រូវបានលុប។ ទំនាក់ទំនងអ្នកគ្រប់គ្រងរបស់អ្នកសម្រាប់ជំនួយ។"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ប្រវត្តិរូបការងាររបស់អ្នកមិនមាននៅលើឧបករណ៍នេះទៀតទេ។"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"កំពុង​តាមដាន​ចរាចរណ៍​បណ្តាញ"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"ចុច​ដើម្បី​ទទួលបាន​ព័ត៌មាន​លម្អិត​បន្ថែម"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"ចុច​ដើម្បី​ស្វែងយល់​បន្ថែម"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"កម្មវិធីគ្រប់គ្រងបាត់បង់សមាសធាតុ ឬមានបញ្ហា ហើយមិនអាចប្រើបានទេ។ ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុបឥឡូវនេះ។ ទំនាក់ទំនងអ្នកគ្រប់គ្រងរបស់អ្នកសម្រាប់ជំនួយ។"</string>
<string name="me" msgid="6545696007631404292">"ខ្ញុំ"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"គ្រប់គ្រងការកំណត់ទីតាំង និងកម្រិតពង្រីករបស់អេក្រង់"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ធ្វើកាយវិការ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"អាចប៉ះ អូស ច្បិច និងធ្វើកាយវិការផ្សេងទៀត"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ចលនា​ស្នាមម្រាមដៃ"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"អាចថត​ចលនា​ដែលមាន​សកម្មភាព​នៅលើ​ឧបករណ៍​ចាប់​ស្នាម​ម្រាមដៃ​របស់ឧបករណ៍។"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"បិទ ឬ​កែ​របារ​ស្ថានភាព"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ឲ្យ​កម្មវិធី​បិទ​របារ​ស្ថានភាព ឬ​បន្ថែម និង​លុប​រូប​តំណាង​ប្រព័ន្ធ។"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ធ្វើជារបារស្ថានភាព"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"អនុញ្ញាតឲ្យកម្មវិធីនេះប្រើសេវាកម្ម IMS ដើម្បីធ្វើការហៅដោយគ្មានការអន្តរាគមន៍ពីអ្នក។"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"អាន​ស្ថានភាព និង​អត្តសញ្ញាណ​ទូរស័ព្ទ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ឲ្យ​កម្មវិធី​ចូល​ដំណើរការ​លក្ខណៈ​ទូរស័ព្ទ​នៃ​ឧបករណ៍។ សិទ្ធិ​នេះ​​ឲ្យ​កម្មវិធី​កំណត់​លេខ​ទូរស័ព្ទ និង​លេខ​សម្គាល់​ឧបករណ៍ ថា​តើ​ការ​ហៅ​សកម្ម និង​លេខ​ពី​ចម្ងាយ​បាន​ភ្ជាប់​ដោយ​ការ​ហៅ។"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"បញ្ជូន​ការ​ហៅ​ទូរសព្ទ​តាមរយៈ​ប្រព័ន្ធ"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​នេះ​បញ្ជូន​ការ​ហៅ​ទូរសព្ទ​របស់វា​តាមរយៈ​ប្រព័ន្ធ ​ដើម្បី​ធ្វើ​ឲ្យ​ការ​ហៅ​ទូរសព្ទ​ប្រសើរ​ជាង​មុន។"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"អានលេខទូរសព្ទ"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"អនុញ្ញាតឲ្យកម្មវិធីនេះចូលប្រើលេខទូរសព្ទរបស់ឧបករណ៍នេះ។"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ការពារ​​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"លុប"</string>
<string name="inputMethod" msgid="1653630062304567879">"វិធីសាស្ត្រ​បញ្ចូល"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"សកម្មភាព​អត្ថបទ"</string>
+ <string name="email" msgid="4560673117055050403">"អ៊ីមែល"</string>
+ <string name="dial" msgid="2275093056198652749">"ហៅ​ទូរសព្ទ"</string>
+ <string name="map" msgid="5441053548030107189">"ផែនទី"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់​ទំហំ​ផ្ទុក"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ​"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"មិន​មាន​ទំហំ​ផ្ទុក​​គ្រប់​គ្រាន់​សម្រាប់​ប្រព័ន្ធ​។ សូម​ប្រាកដ​ថា​អ្នក​មាន​ទំហំ​ទំនេរ​ 250MB ហើយ​ចាប់ផ្ដើម​ឡើង​វិញ។"</string>
@@ -1143,6 +1150,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"ប៉ះសម្រាប់ជម្រើសជាច្រើនទៀត"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"បាន​ភ្ជាប់​ការ​កែ​កំហុស​យូអេសប៊ី"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"ប៉ះដើម្បីបិទដំណើរការកែកំហុសយូអេសប៊ី"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ជ្រើស​ ដើម្បី​បិទ​ការ​កែ​កំហុស​យូអេសប៊ី។"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"កំពុងទទួលយករបាយការណ៍កំហុស…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
@@ -1199,6 +1207,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ឲ្យ​កម្មវិធី​អាន​សម័យ​ដំឡើង។ វា​អនុញ្ញាត​ឲ្យ​ឃើញ​ព័ត៌មាន​លម្អិត​អំពី​​ការដំឡើង​កញ្ចប់​សកម្ម។"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ស្នើសុំកញ្ចប់ដំឡើង"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"អនុញ្ញាតឲ្យកម្មវិធីស្នើសុំដំឡើងកញ្ចប់ (ឯកសារ/មាតិកា)។"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ស្នើសុំ​លុប​កញ្ចប់"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​ស្នើសុំលុប​កញ្ចប់។"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ស្នើឲ្យមិនអើពើចំពោះការបង្កើនប្រសិទ្ធភាពថ្ម"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"អនុញ្ញាតឲ្យកម្មវិធីស្នើសុំការអនុញ្ញាត ដើម្បីមិនអើពើចំពោះការបង្កើនប្រសិទ្ធភាពថ្ម។"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ប៉ះ ពីរ​ដង​ដើម្បី​ពិនិត្យ​ការ​ពង្រីក"</string>
@@ -1425,9 +1435,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"លុប​ចេញ"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"បង្កើន​កម្រិត​សំឡេង​លើស​ពី​កម្រិត​បាន​ផ្ដល់​យោបល់?\n\nការ​ស្ដាប់​នៅ​កម្រិត​សំឡេង​ខ្លាំង​យូរ​អាច​ធ្វើឲ្យ​ខូច​ត្រចៀក។"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"សង្កត់​ដោយ​ម្រាមដៃ​ពីរ ដើម្បី​បើក​ភាព​ងាយស្រួល។"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"បាន​បើក​មធ្យោបាយ​ងាយស្រួល​។"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"បាន​បោះបង់​ភាព​ងាយស្រួល។"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បើក"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"បើក ឬបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ដោយ​ចុច​ប៊ូតុង​កម្រិត​សំឡេង​ទាំង​ពីរ​ឲ្យ​ជាប់រយៈពេល​ 3 វិនាទី។\n\nអ្នក​អាច​ផ្លាស់​ប្តូរ​សេវាកម្ម​នេះ​បាន​នៅក្នុង​ការ​កំណត់ &gt; ភាព​ងាយស្រួល។"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"បិទ​ផ្លូវកាត់"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ទុក​ឲ្យ​បើក"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"អ្នក​ប្រើ​បច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
<string name="user_switching_message" msgid="2871009331809089783">"កំពុង​ប្ដូរ​ទៅ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"កំពុងចេញ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1673,20 +1686,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ដែលបានបិទដំណើរការ"</string>
<string name="conference_call" msgid="3751093130790472426">"ការហៅជាក្រុម"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ផ្ទាំងលោត"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ហ្គេម"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"តន្រ្តី និង​សំឡេង"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ភាពយន្ត និង​វីដេអូ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"រូបថត និង​រូបភាព"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"សង្គម និង​​ទំនាក់ទំនង"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ព័ត៌មាន និង​ទស្សនាវដ្ដី"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"ផែនទី និង​ការ​រុករក"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ផលិត​ភាព"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ទំហំផ្ទុកឧបករណ៍"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-kn-watch/styles_material.xml b/core/res/res/values-kn-watch/styles_material.xml
deleted file mode 100644
index 1ec23a4e3861..000000000000
--- a/core/res/res/values-kn-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ಅಭ್ಯರ್ಥಿಗಳು"</font></string>
-</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8c8ab2fb85c3..07400f59b353 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ನಿರ್ವಾಹಕ ಅಪ್ಲಿಕೇಶನ್ ಕಳೆದು ಹೋಗಿದೆ ಅಥವಾ ಹಾಳಾಗಿದೆ. ಇದರ ಪರಿಣಾಮವಾಗಿ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗಿದೆ. ಸಹಾಯಕ್ಕಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ನಿಮ್ಮ ಕಾರ್ಯ ಪ್ರೊಫೈಲ್ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್ನು ಮುಂದೆ ಲಭ್ಯವಿರುವುದಿಲ್ಲ."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಅನ್ನು ಮಾನಿಟರ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"ಹೆಚ್ಚಿನ ಮಾಹಿತಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"ನಿರ್ವಾಹಕ ಅಪ್ಲಿಕೇಶನ್‌ನ ಅಂಶಗಳು ಕಾಣೆಯಾಗಿವೆ ಅಥವಾ ದೋಷಪೂರಿತವಾಗಿದೆ ಮತ್ತು ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ. ಸಹಾಯಕ್ಕಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="me" msgid="6545696007631404292">"ನಾನು"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ಪ್ರದರ್ಶನದ ಝೂಮ್ ಮಟ್ಟ ಮತ್ತು ಸ್ಥಾನ ನಿರ್ಧಾರವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಮಾಡಿ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ಟ್ಯಾಪ್ ಮಾಡಬಹುದು, ಸ್ವೈಪ್ ಮಾಡಬಹುದು, ಪಿಂಚ್ ಮಾಡಬಹುದು ಮತ್ತು ಇತರ ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಮಾಡಬಹುದು."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್‌ ಸೂಚಕಗಳು"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ಸಾಧನದ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌ನಲ್ಲಿ ನಡೆಸಿದ ಸೂಚಕಗಳನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ ಇಲ್ಲವೇ ಮಾರ್ಪಡಿಸಿ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಥವಾ ಸೇರಿಸಲು ಮತ್ತು ಸಿಸ್ಟಂ ಐಕಾನ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಾಗಿರಲು"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ನಿಮ್ಮ ಮಧ್ಯಸ್ಥಿಕೆ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡಲು IMS ಸೇವೆಯನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ಫೋನ್ ಸ್ಥಿತಿ ಮತ್ತು ಗುರುತಿಸುವಿಕೆಯನ್ನು ಓದಿ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ಸಾಧನದ ಫೋನ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ಫೋನ್ ಸಂಖ್ಯೆ ಮತ್ತು ಸಾಧನದ ID ಗಳನ್ನು ನಿರ್ಧರಿಸಲು, ಕರೆಯು ಸಕ್ರಿಯವಾಗಿದೆಯೇ ಮತ್ತು ಕರೆಯ ಮೂಲಕ ರಿಮೋಟ್ ಸಂಖ್ಯೆಯು ಸಂಪರ್ಕಗೊಂಡಿವೆಯೇ ಎಂಬುದನ್ನೂ ನಿರ್ಧರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಕಲ್ಪಿಸುತ್ತದೆ."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ಕರೆಗಳನ್ನು ಸಿಸ್ಟಂ ಮೂಲಕ ರವಾನಿಸಿ"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"ಕರೆಯ ಅನುಭವವನ್ನು ಸುಧಾರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ನ ಕರೆಗಳನ್ನು ಸಿಸ್ಟಂ ಮೂಲಕ ರವಾನಿಸಲು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ಫೋನ್ ಸಂಖ್ಯೆ ಓದಿ"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ಸಾಧನದ ಫೋನ್ ಸಂಖ್ಯೆ ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ಟ್ಯಾಬ್ಲೆಟ್ ನಿದ್ರಾವಸ್ಥೆಯನ್ನು ತಡೆಯಿರಿ"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ಅಳಿಸು"</string>
<string name="inputMethod" msgid="1653630062304567879">"ಇನ್‌ಪುಟ್ ವಿಧಾನ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ಪಠ್ಯದ ಕ್ರಮಗಳು"</string>
+ <string name="email" msgid="4560673117055050403">"ಇಮೇಲ್"</string>
+ <string name="dial" msgid="2275093056198652749">"ಡಯಲ್"</string>
+ <string name="map" msgid="5441053548030107189">"ನಕ್ಷೆ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ಸಂಗ್ರಹಣೆ ಸ್ಥಳವು ತುಂಬಿದೆ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ಕೆಲವು ಸಿಸ್ಟಂ ಕಾರ್ಯವಿಧಾನಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ಸಿಸ್ಟಂನಲ್ಲಿ ಸಾಕಷ್ಟು ಸಂಗ್ರಹಣೆಯಿಲ್ಲ. ನೀವು 250MB ನಷ್ಟು ಖಾಲಿ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುವಿರಾ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ಸ್ಥಾಪಿತ ಸೆಷನ್‌ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ. ಸಕ್ರಿಯ ಪ್ಯಾಕೇಜ್‌ ಸ್ಥಾಪನೆಗಳ ಕುರಿತು ವಿವರಣೆಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಇದು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ಸ್ಥಾಪನೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ವಿನಂತಿಸಿ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ಪ್ಯಾಕೇಜ್‌ಗಳ ಸ್ಥಾಪನೆಯನ್ನು ವಿನಂತಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಅಳಿಸಲು ವಿನಂತಿ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ಅಳಿಸುವುದಕ್ಕಾಗಿ ವಿನಂತಿ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಕಡೆಗಣಿಸಲು ಕೇಳಿ"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಕಡೆಗಣಿಸುವುದಕ್ಕೆ ಅನುಮತಿಯನ್ನು ಕೇಳಲು ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ಝೂಮ್‌ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ತೆಗೆದುಹಾಕು"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ವಾಲ್ಯೂಮ್‌ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್‌ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ಪ್ರವೇಶಿಸುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಎರಡೂ ಬೆರಳುಗಳನ್ನು ಕೆಳಮುಖವಾಗಿ ಹಿಡಿದಿಟ್ಟುಕೊಂಡಿರಿ."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ಪ್ರವೇಶಿಸುವಿಕೆ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ಪ್ರವೇಶಿಸುವಿಕೆಯನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್ ಆನ್ ಆಗಿದೆ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳನ್ನು 3 ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿಯುವ ಮೂಲಕ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಅಥವಾ ಆಫ್ ಮಾಡಿ.\n\nನೀವು ಈ ಸೇವೆಯನ್ನು ಸೆಟ್ಟಿಂಗ್‌ಗಳು &gt; ಪ್ರವೇಶಿಸುವಿಕೆ ಆಯ್ಕೆಯಲ್ಲಿ ಬದಲಿಸಬಹುದು."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"ಶಾರ್ಟ್‌ಕಟ್‌ ಆಫ್ ಮಾಡಿ"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ಆನ್ ಆಗಿರಿಸಿ"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಿದೆ"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಿದೆ"</string>
<string name="user_switched" msgid="3768006783166984410">"ಪ್ರಸ್ತುತ ಬಳಕೆದಾರರು <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರನ್ನು ಲಾಗ್‌ ಔಟ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="conference_call" msgid="3751093130790472426">"ಕಾನ್ಫರೆನ್ಸ್ ಕರೆ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ಟೂಲ್‌ಟಿಪ್"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ಆಟಗಳು"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"ಸಂಗೀತ ಮತ್ತು ಆಡಿಯೋ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ಸಿನಿಮಾಗಳು ಮತ್ತು ವೀಡಿಯೊ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ಫೋಟೋಗಳು ಮತ್ತು ಚಿತ್ರಗಳು"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"ಸಾಮಾಜಿಕ ಮತ್ತು ಸಂವಹನ"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ಸುದ್ದಿ ಮತ್ತು ನಿಯತಕಾಲಿಕೆಗಳು"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"ನಕ್ಷೆಗಳು ಮತ್ತು ನ್ಯಾವಿಗೇಶನ್"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ಉತ್ಪಾದಕತೆ"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ಸಾಧನ ಸಂಗ್ರಹಣೆ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ko-watch/styles_material.xml b/core/res/res/values-ko-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ko-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f0a214ee80d4..b74094e6a024 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"직장 프로필 관리 앱이 없거나 손상되어 직장 프로필 및 관련 데이터가 삭제되었습니다. 도움이 필요한 경우 관리자에게 문의하세요."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"직장 프로필을 이 기기에서 더 이상 사용할 수 없습니다."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"네트워크 트래픽이 모니터링되고 있음"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"탭하여 세부정보 더보기"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"자세한 내용을 보려면 탭하세요."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"기기가 삭제됩니다."</string>
<string name="factory_reset_message" msgid="4905025204141900666">"관리 앱이 손상되었거나 구성요소가 없어서 사용할 수 없습니다. 이제 기기가 삭제됩니다. 도움이 필요한 경우 관리자에게 문의하세요."</string>
<string name="me" msgid="6545696007631404292">"나"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"디스플레이의 확대/축소 수준 및 위치를 제어합니다."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"동작 실행"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"탭, 스와이프, 확대/축소 및 기타 동작을 실행할 수 있습니다."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"지문 동작"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"기기 지문 센서에서 동작을 캡처합니다."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"상태 표시줄 사용 중지 또는 수정"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"앱이 상태 표시줄을 사용중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 허용합니다."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"상태 표시줄에 위치"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"앱이 IMS 서비스를 사용하여 자동으로 전화를 걸 수 있도록 허용합니다."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"휴대전화 상태 및 ID 읽기"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"앱이 기기의 휴대전화 기능에 접근할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 전화번호 및 기기의 ID, 활성 통화인지 여부, 통화가 연결된 원격 번호 등을 확인할 수 있습니다."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"시스템을 통해 통화 연결"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"통화 환경을 개선하기 위해 앱이 시스템을 통해 통화를 연결하도록 허용합니다."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"전화번호 읽기"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"앱에서 기기의 전화번호에 액세스할 수 있도록 허용합니다."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"삭제"</string>
<string name="inputMethod" msgid="1653630062304567879">"입력 방법"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"텍스트 작업"</string>
+ <string name="email" msgid="4560673117055050403">"이메일"</string>
+ <string name="dial" msgid="2275093056198652749">"전화걸기"</string>
+ <string name="map" msgid="5441053548030107189">"지도"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"시스템의 저장 공간이 부족합니다. 250MB의 여유 공간이 확보한 후 다시 시작하세요."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"옵션을 더 보려면 탭하세요."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB 디버깅을 사용하지 않으려면 탭하세요."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"버그 보고서 가져오는 중..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"애플리케이션의 설치 세션 읽기를 허용하면, 활성 패키지 설치에 대한 세부 정보를 볼 수 있습니다."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"패키지 설치 요청"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"애플리케이션이 패키지 설치를 요청하도록 허용합니다."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"패키지 삭제 요청"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"애플리케이션이 패키지 삭제를 요청하도록 허용합니다."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"배터리 최적화를 무시하도록 요청"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"앱에서 배터리 최적화를 무시할 수 있는 권한을 요청할 수 있도록 허용합니다."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"확대/축소하려면 두 번 탭하세요."</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"가상 현실 리스너"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR 리스너"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"알림 순위 지정 서비스"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"삭제"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"두 손가락으로 길게 누르면 접근성을 사용하도록 설정됩니다."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"접근성을 사용 설정했습니다."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"접근성이 취소되었습니다."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"접근성 단축키가 사용 설정됨"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"볼륨 버튼 두 개를 3초 동안 눌러 <xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용 또는 사용 중지할 수 있습니다.\n\n이 서비스는 설정 &gt; 접근성에서 변경할 수 있습니다."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"단축키 사용 중지"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"계속 사용"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
<string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 전환하는 중…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>님을 로그아웃하는 중…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> 사용 중지됨"</string>
<string name="conference_call" msgid="3751093130790472426">"다자간 통화"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"도움말"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"게임"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"음악/오디오"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"영화/동영상"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"사진/이미지"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"소셜/커뮤니케이션"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"뉴스/잡지"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"지도/내비게이션"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"생산성"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"기기 저장용량"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ky-watch/styles_material.xml b/core/res/res/values-ky-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ky-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f0f1ef88706d..7b1d1266d167 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Жумуш профилинин администратор колдонмосу жок же бузулгандыктан, жумуш профилиңиз жана ага байланыштуу дайындар жок кылынган. Жардам алуу үчүн администраторуңузга кайрылыңыз."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Жумуш профилиңиз бул түзмөктө жеткиликтүү болбой калды."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Тармак трафиги көзөмөлдөнүүдө"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Кеңири маалымат алуу үчүн басыңыз"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Көбүрөөк маалымат алуу үчүн таптап коюңуз"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Түзмөгүңүз тазаланат"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Администратор колдонмосунун курамдары жок же бузулгандыктан, аны колдонуу мүмкүн эмес. Түзмөгүңүз азыр тазаланат. Жардам алуу үчүн администраторуңузга кайрылыңыз."</string>
<string name="me" msgid="6545696007631404292">"Мен"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Экрандагы сүрөттүн өлчөмүн өзгөртүү жана жайгаштыруу."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жаңсоолорду аткаруу"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Таптап, серпип, чымчып жана башка жаңсоолорду аткара алат."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Манжа изинин жаңсоолору"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Түзмөктөрдөгү манжа изинин сенсорунда жасалган жаңсоолорду жаздырып алат."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"абал тилкесин өчүрүү же өзгөртүү"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Колдонмого абал тилкесин өчүрүү же тутум сүрөтчөлөрүн кошуу же алып салуу мүмкүнчүлүгүн берет."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"абал тилкесинин милдетин аткаруу"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен чалууларды жасоо мүмкүнчүлүгүн берет."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"телефондун абалын жана аныктыгын окуу"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Колдонмого түзмөктүн чалуу мүмкүнчүлүктөрүнө жетки алуу уруксатын берет. Бул уруксат колдонмого, телефондун номурун, түзмөктүн ID-син, чалуунун абалын жана байланышта чыккан номурду аныктоого жол берет."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"чалууларды тутум аркылуу өткөрүү"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Чалуунун сапатын жакшыртуу максатында колдонмого чалууларын тутум аркылуу өткөрүүгө уруксат берет."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"телефон номерин окуу"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Колдонмого түзмөктүн телефон номерин окуу мүмкүнчүлүгү берилет."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"планшетти уктатпай сактоо"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Жок кылуу"</string>
<string name="inputMethod" msgid="1653630062304567879">"Киргизүү ыкмасы"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Текст боюнча иштер"</string>
+ <string name="email" msgid="4560673117055050403">"Электрондук почта"</string>
+ <string name="dial" msgid="2275093056198652749">"Терүү"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сактагычта орун калбай баратат"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Кошумча параметрлерди ачуу үчүн таптап коюңуз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB аркылуу мүчүлүштүктөрдү оңдоо туташтырылган"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB арклуу мүчүлштктрдү жоюну өчр үчн тийп коюңуз."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"топтомдорду жок кылууга уруксат суроо"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Колдонмо топтомдорду жок кылууга уруксат сурай алат."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батареянын кубатын көп керектей берсин"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Колдонмо батареянын кубатын керектегенден мурун уруксат суралсын."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Алып салуу"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Атайын мүмкүнчүлүктөрдү иштетиш үчүн, эки манжаңыз менен басып туруңуз."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Жеткиликтүүлүк иштетилди."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Атайын мүмкүнчүлүктөр иштетилген жок."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Атайын мүмкүнчүлүктөр кыска жолу КҮЙГҮЗҮЛГӨН"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүзүп же өчүрүү үчүн үн көзөмөлдөөчү баскыстарды басып 3 секунд кармап туруңуз.\n\nКызматты Жөндөөлөр &gt; атайын мүмкүнчүлүктөр бөлүмүнөн өзгөртө аласыз."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Кыска жолду өчүрүү"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Күйгөн боюнча калтыруу"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүздү"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын өчүрдү"</string>
<string name="user_switched" msgid="3768006783166984410">"Учурдагы колдонуучу <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> дегенге которулууда…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> чыгууда…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өчүрүлдү"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференц чалуу"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Калкып чыгуучу кеңеш"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Оюндар"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музыка жана аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Тасмалар жана видеолор"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Фото жана сүрөттөр"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Социалдык жана коммуникация"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Жаңылыктар жана журналдар"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карталар жана чабыттоо"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Өндүрүш категориясы"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Түзмөктүн сактагычы"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-lo-watch/styles_material.xml b/core/res/res/values-lo-watch/styles_material.xml
deleted file mode 100644
index 1f845b9df48a..000000000000
--- a/core/res/res/values-lo-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ແຄນດິເດດ"</font></string>
-</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 06499617bfd9..5d7b4c330611 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"ແອັບ​ບໍ​ລິ​ຫານ​ໂປ​ຣ​ໄຟ​ລ໌​ວຽກ​ຂາດ​ໄປ ຫຼື​ຖືກ​​ເສຍ​ຫາຍ. ດ້ວຍ​ເຫດ​ຜົນ​ນັ້ນ, ໂປ​ຣ​ໄຟ​ລ໌​ບ່ອນ​ເຮັດວຽກ​ຂອງ​ທ່ານ ແລະ​ຂໍ້​ມູນ​ທີ່​ກ່ຽວ​ຂ້ອງ​ຈິ່ງ​ຖືກ​ລຶບ​ໄປ. ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸ​ມ​ຂອງ​ທ່ານ ເພື່ອ​ຂໍ​ຄວາມ​ຊ່ວຍ​ເຫຼືອ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ່ມີໃຫ້ໃຊ້ງານເທິງອຸປະກອນນີ້ອີກຕໍ່ໄປ."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ກຳລັງຕິດຕາມທຣາບຟິກເຄືອຂ່າຍ"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດເພີ່ມເຕີມ"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ລຶບ"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"ແອັບ​ບໍ​ລິ​ຫານ​ຂາດ​ອົງ​ປະ​ກອບ​ ຫ​ຼື​ຖືກ​ຂັດ​ຈັງ​ຫວະ, ແລະ​ບໍ່​ສາ​ມາດ​ໃຊ​ໄດ້. ດຽວ​ນີ້​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ລຶບ. ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ ເພື່ອ​ຂໍ​ຄວາມ​ຊ່ວຍ​ເຫຼືອ."</string>
<string name="me" msgid="6545696007631404292">"ຂ້າພະເຈົ້າ"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ຄວບຄຸມລະດັບການຊູມ ແລະການວາງຕຳແໜ່ງຂອງຈໍສະແດງຜົນ."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ດຳເນີນທ່າທາງຕ່າງໆ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ສາມາດແຕະ, ປັດນີ້ວມື, ຢິບນິ້ວມື ແລະ ດຳເນີນທ່າທາງອື່ນ."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ທ່າທາງລາຍນິ້ວມື"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ສາມາດບັນທຶກທ່າທາງທີ່ເກີດຂຶ້ນໃນອຸປະກອນເຊັນເຊີລາຍນິ້ວມືໄດ້."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ປິດການນນຳໃຊ້ ຫຼື ແກ້ໄຂແຖບສະຖານະ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ອະນຸຍາດໃຫ້ແອັບຯປິດການເຮັດວຽກຂອງແຖບສະຖານະ ຫຼືເພີ່ມ ແລະລຶບໄອຄອນລະບົບອອກໄດ້."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ເປັນ​ແຖບ​ສະ​ຖາ​ນະ"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ໃຊ້​ການ​ບໍ​ລິ​ການ IMS ເພື່ອ​ໂທ​ໂດຍ​ບໍ່​ມີ​ການ​ຊ່ວຍ​ເຫຼືອ​ຂອງ​ທ່ານ."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ອ່ານສະຖານະ ແລະຂໍ້ມູນລະບຸໂຕຕົນຂອງໂທລະສັບ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງຄວາມສາມາດການໂທລະສັບຂອງອຸປະກອນ. ການກຳນົດສິດນີ້ເຮັດໃຫ້ແອັບຯສາມາດກວດສອບເບີໂທລະສັບ ແລະ ID ຂອງອຸປະກອນ, ບໍ່ວ່າການໂທຈະຍັງດຳເນີນຢູ່ ແລະເບີປາຍທາງເຊື່ອມຕໍ່ຢູ່ຫຼືບໍ່ກໍຕາມ."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"route calls through the system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Allows the app to route its calls through the system in order to improve the calling experience."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"read phone number"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Allows the app to access the phone number of the device."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ລຶບ"</string>
<string name="inputMethod" msgid="1653630062304567879">"ຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string>
+ <string name="email" msgid="4560673117055050403">"ອີເມວ"</string>
+ <string name="dial" msgid="2275093056198652749">"ໂທອອກ"</string>
+ <string name="map" msgid="5441053548030107189">"ແຜນທີ່"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນກຳລັງຈະເຕັມ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ການເຮັດວຽກບາງຢ່າງຂອງລະບົບບາງອາດຈະໃຊ້ບໍ່ໄດ້"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"​ບໍ່​ມີ​ບ່ອນ​ເກັບ​ຂໍ້​ມູນ​ພຽງ​ພໍ​ສຳ​ລັບ​ລະ​ບົບ. ກວດ​ສອບ​ໃຫ້​ແນ່​ໃຈ​ວ່າ​ທ່ານ​ມີ​ພື້ນ​ທີ່​ຫວ່າງ​ຢ່າງ​ໜ້ອຍ 250MB ​ແລ້ວລອງ​ໃໝ່."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"ແຕະເພື່ອເບິ່ງຕົວເລືອກເພີ່ມເຕີມ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"ແຕະເພື່ອປິດການດີບັກຜ່ານ USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ກຳລັງຂໍລາຍງານຂໍ້ຜິດພາດ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ແບ່ງປັນລາຍງານບັນຫາບໍ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ກຳລັງແບ່ງປັນລາຍງານບັນຫາ…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພລິ​ເຄ​ຊັນ​ອ່ານ​ເຊດ​ຊັນ​ການ​ຕິດ​ຕັ້ງ​ໄດ້. ນີ້​ຈະ​ອະ​ນຸ​ຍາດ​ໃຫ້​ມັນ​ເບິ່ງ​ເຫັນ​ລາຍ​ລະ​ອຽດ​ກ່ຽວ​ກັບ​ການ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ​ທີ່​ເຮັດ​​ວຽກ​ຢູ່​ໄດ້."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ຂໍ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ຂອງ​ການ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ຮ້ອງຂໍການລຶບແພັກເກດ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຮ້ອງຂໍການລຶບແພັກເກດ."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ຖາມເພື່ອໃຫ້ເພີກເສີຍການປັບແຕ່ງແບັດເຕີຣີ"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ອະນຸຍາດໃຫ້ແອັບຖາມສິດອະນຸຍາດເພື່ອເພີກເສີຍຕໍ່ການປັບແຕ່ງແບັດເຕີຣີສຳລັບແອັບນັ້ນ."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ແຕະສອງເທື່ອເພື່ອຄວບຄຸມການຊູມ"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ລຶບອອກ"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ເພີ່ມ​ລະ​ດັບ​ສຽງ​ໃຫ້​ເກີນກວ່າ​ລະ​ດັບ​ທີ່​ແນະ​ນຳ​ບໍ?\n\n​ການ​ຮັບ​ຟັງ​ສຽງ​ໃນ​ລະ​ດັບ​ທີ່​ສູງ​ເປັນ​ໄລ​ຍະ​ເວ​ລາ​ດົນ​​ອາດ​ເຮັດ​ໃຫ້​ການ​ຟັງ​ຂອງ​ທ່ານ​ມີ​ບັນ​ຫາ​ໄດ້."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ກົດສອງນິ້ວຄ້າງໄວ້ເພື່ອເປີດໃຊ້ການຊ່ວຍເຂົ້າເຖິງ"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ເປີດການຊ່ວຍເຂົ້າເຖິງແລ້ວ."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ຍົກເລີກໂຕຊ່ວຍການເຂົ້າເຖິງແລ້ວ."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Accessibility Shortcut is ON"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Turn <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on or off by holding down both volume buttons for 3 seconds.\n\nYou can change the service in Settings &gt; Accessibility."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Turn Off Shortcut"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Leave on"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
<string name="user_switched" msgid="3768006783166984410">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
<string name="user_switching_message" msgid="2871009331809089783">"ກຳ​ລັງ​ສະ​ລັບ​​ໄປ​ຫາ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"ກຳລັງອອກຈາກລະບົບ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ປິດການນຳໃຊ້ <xliff:g id="LABEL">%1$s</xliff:g> ແລ້ວ"</string>
<string name="conference_call" msgid="3751093130790472426">"ການປະຊຸມສາຍ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ຄຳອະທິບາຍເຄື່ອງມື"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ເກມ"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Music &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Movies &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Photos &amp; Images"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social &amp; Communication"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ຜະລິດຕະພາບ"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ບ່ອນຈັດເກັບຂໍ້ມູນອຸປະກອນ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-lt-watch/styles_material.xml b/core/res/res/values-lt-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-lt-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index bd694dd9ae10..89ac3f2b4369 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Trūksta darbo profilio administratoriaus programos arba ji sugadinta. Todėl darbo profilis ir susiję duomenys buvo ištrinti. Dėl pagalbos susisiekite su administratoriumi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Darbo profilis nebepasiekiamas šiame įrenginyje."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Tinklo srautas stebimas"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Palieskite, kad gautumėte daugiau informacijos"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Palieskite, kad sužinotumėte daugiau"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Įrenginys bus ištrintas"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Trūksta administratoriaus programos komponentų arba programa sugadinta ir jos negalima naudoti. Dabar įrenginys bus ištrintas. Dėl pagalbos susisiekite su administratoriumi."</string>
<string name="me" msgid="6545696007631404292">"Aš"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Valdykite ekrano mastelio keitimo lygį ir pozicijos nustatymą."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Veiksmai gestais"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Galima paliesti, perbraukti, suimti ir atlikti kitus veiksmus gestais."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Kontrolinio kodo gestai"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Gali užfiksuoti gestus, atliktus naudojant įrenginio kontrolinio kodo jutiklį."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"išjungti ar keisti būsenos juostą"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Leidžiama programai neleisti būsenos juostos arba pridėti ir pašalinti sistemos piktogramas."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"būti būsenos juosta"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Programai leidžiama naudoti IMS paslaugą, kad būtų galima atlikti skambučius be jūsų įsikišimo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"skaityti telefono būseną ir tapatybę"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leidžiama programai pasiekti telefono funkcijas įrenginyje. Šis leidimas suteikia teisę programai nustatyti telefono numerį ir įrenginio ID, tai, ar skambutis aktyvus, ir skambučiu prijungtą nuotolinį numerį."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"nukreipti skambučius per sistemą"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Programai leidžiama nukreipti jos skambučius per sistemą siekiant pagerinti skambinimo paslaugas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"skaityti telefono numerį"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Programai leidžiama pasiekti įrenginio telefono numerį."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"neleisti planšetiniam kompiuteriui užmigti"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Ištrinti"</string>
<string name="inputMethod" msgid="1653630062304567879">"Įvesties būdas"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Teksto veiksmai"</string>
+ <string name="email" msgid="4560673117055050403">"Siųsti el. laišką"</string>
+ <string name="dial" msgid="2275093056198652749">"Rinkti numerį"</string>
+ <string name="map" msgid="5441053548030107189">"Žemėlapis"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistemos saugykloje nepakanka vietos. Įsitikinkite, kad yra 250 MB laisvos vietos, ir paleiskite iš naujo."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Palieskite, kad išjungtumėte USB derinimą."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pasirinkite, kas išjungtumėte USB derinimą."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Pateikiamas pranešimas apie riktą…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bendrinti pranešimą apie riktą?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bendrinamas pranešimas apie riktą..."</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Leidžiama programai skaityti diegimo seansus. Leidžiama peržiūrėti išsamią aktyvių paketų diegimo informaciją."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"pateikti užklausą dėl diegimo paketų"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Programai leidžiama pateikti užklausą dėl paketų diegimo."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"paketo ištrynimo užklausa"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Programai leidžiama pateikti užklausą dėl paketų ištrynimo."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"prašyti nepaisyti akumuliatoriaus optimizavimo nustatymų"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Programai leidžiama prašyti leidimo nepaisyti tai programai skirto akumuliatoriaus optimizavimo nustatymų."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Bakstelėkite du kartus, kad valdytumėte mastelio keitimą"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Laikykite palietę dviem pirštais, kad įgalintumėte pritaikymo neįgaliesiems režimą."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pritaikymas neįgaliesiems įgalintas."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pritaikymo neįgaliesiems režimas atšauktas."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Pritaikymo neįgaliesiems spartusis klavišas ĮJUNGTAS"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Įjunkite arba išjunkite „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ laikydami nuspaudę abu garsumo mygtukus 3 sekundes.\n\nGalite pakeisti paslaugą nuėję į „Nustatymai“ &gt; „Pritaikymas neįgaliesiems“."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Išjungti spartųjį klavišą"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Palikti įjungtą"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
<string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Perjungiama į <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Atsijungiama (<xliff:g id="NAME">%1$s</xliff:g>)…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencinis skambutis"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Patarimas"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Žaidimai"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzika ir garso įrašai"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmai ir vaizdo įrašai"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Nuotraukos ir vaizdai"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Socialiniai tinklai ir ryšiai"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Naujienos ir žurnalai"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Žemėlapiai ir navigacija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktyvumas"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Įrenginio saugykla"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-lv-watch/styles_material.xml b/core/res/res/values-lv-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-lv-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d17846f6ca76..516333453b42 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Trūkst darba profila administratora lietotnes, vai šī lietotne ir bojāta. Šī iemesla dēļ jūsu darba profils un saistītie dati tika dzēsti. Lai saņemtu palīdzību, sazinieties ar administratoru."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Jūsu darba profils šai ierīcē vairs nav pieejams."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Tīkla datplūsma tiek pārraudzīta"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Pieskarieties, lai iegūtu detalizētu informāciju"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Pieskarieties, lai uzzinātu vairāk"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Jūsu ierīces dati tiks dzēsti"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administratora lietotnē trūkst komponentu, vai šī lietotne ir bojāta. Lietotni nevar izmantot. Ierīces dati tūlīt tiks dzēsti. Lai saņemtu palīdzību, sazinieties ar administratoru."</string>
<string name="me" msgid="6545696007631404292">"Man"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolējiet displeja tālummaiņas līmeni un pozicionēšanu."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Žestu izpilde"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Atbalsta pieskaršanos, vilkšanu, savilkšanu un citus žestus."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pirksta nospieduma žesti"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Var uztvert žestus ierīces pirksta nospieduma sensorā."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"atspējot vai pārveidot statusa joslu"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ļauj lietotnei atspējot statusa joslu vai pievienot un noņemt sistēmas ikonas."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Būt par statusa joslu"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ļauj lietotnei izmantot tūlītējās ziņojumapmaiņas pakalpojumu, lai veiktu zvanus bez jūsu ziņas."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lasīt tālruņa statusu un identitāti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ļauj lietotnei piekļūt ierīces tālruņa funkcijām. Ar šo atļauju lietotne var noteikt tālruņa numuru un ierīču ID, zvana statusu un attālo numuru, ar ko ir izveidots savienojums, veicot zvanu."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"maršrutēt zvanus sistēmā"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Ļauj lietotnei maršrutēt tās zvanus sistēmā, lai uzlabotu zvanīšanas pieredzi."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lasīt tālruņa numuru"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ļauj lietotnei piekļūt ierīces tālruņa numuram."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"novērst planšetdatora pāriešanu miega režīmā"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Dzēst"</string>
<string name="inputMethod" msgid="1653630062304567879">"Ievades metode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Teksta darbības"</string>
+ <string name="email" msgid="4560673117055050403">"E-pasts"</string>
+ <string name="dial" msgid="2275093056198652749">"Sastādīt numuru"</string>
+ <string name="map" msgid="5441053548030107189">"Maps"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistēmai pietrūkst vietas. Atbrīvojiet vismaz 250 MB vietas un restartējiet ierīci."</string>
@@ -1161,6 +1168,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Pieskarieties, lai skatītu citas iespējas."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Pieskarieties, lai atspējotu USB atkļūdošanu."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Atlasiet, lai atspējotu USB atkļūdošanu."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Notiek kļūdas pārskata izveide…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vai kopīgot kļūdas pārskatu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Notiek kļūdas pārskata kopīgošana…"</string>
@@ -1217,6 +1225,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ļauj lietojumprogrammai lasīt instalēšanas sesijas. Tādējādi lietojumprogrammai ir pieejama informācija par aktīvajām pakotņu instalācijām."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Pieprasīt pakotņu instalēšanu"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ļauj lietojumprogrammai pieprasīt pakotņu instalēšanu."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"pakotņu dzēšanas pieprasīšana"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Atļauj lietojumprogrammai pieprasīt pakotņu dzēšanu."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Lūgt akumulatora optimizācijas ignorēšanu"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ļauj lietotnei lūgt atļauju ignorēt akumulatora optimizāciju šai lietotnei."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
@@ -1444,9 +1454,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">"  — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Lai iespējotu pieejamību, turiet nospiestus divus pirkstus."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pieejamības režīms ir iespējots."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pieejamība ir atcelta."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Pieejamības saīsne ir ieslēgta"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ieslēdziet vai izslēdziet lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiežot un 3 sekundes turot abas skaļuma pogas.\n\nPakalpojumu var mainīt šeit: Iestatījumi &gt; Pieejamība."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Izslēgt saīsni"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Atstāt ieslēgtu"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Notiek pāriešana uz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Notiek lietotāja <xliff:g id="NAME">%1$s</xliff:g> atteikšanās…"</string>
@@ -1702,20 +1715,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferences zvans"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Rīka padoms"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Spēles"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Mūzika un audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmas un video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotoattēli un attēli"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociālie tīkli un saziņa"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Ziņas un žurnāli"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kartes un navigācija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitāte"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Ierīces krātuve"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-mcc208-mnc10/config.xml b/core/res/res/values-mcc208-mnc10/config.xml
index d3640e5c4153..3ed78181ffe6 100644
--- a/core/res/res/values-mcc208-mnc10/config.xml
+++ b/core/res/res/values-mcc208-mnc10/config.xml
@@ -31,28 +31,4 @@
<item>[ApnSettingV3]INTERNET NRJ,internetnrj,,,,,,,,,208,10,,DUN,,,true,0,,,,,,,gid,4E</item>
</string-array>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc334-mnc050/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
index f6777d0391df..616a8e8fa283 100644
--- a/core/res/res/values-mcc334-mnc050/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -40,4 +40,8 @@
<item>Modem,modem.iusacellgsm.mx,,,iusacellgsm,iusacellgsm,,,,,334,050,1,DUN</item>
</string-array>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"#9"</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values-mcc334-mnc090/config.xml b/core/res/res/values-mcc334-mnc090/config.xml
new file mode 100644
index 000000000000..1632a4239923
--- /dev/null
+++ b/core/res/res/values-mcc334-mnc090/config.xml
@@ -0,0 +1,28 @@
+<?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 my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"#9"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
new file mode 100644
index 000000000000..10b647044c73
--- /dev/null
+++ b/core/res/res/values-mcc704-mnc01/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array name="config_twoDigitNumberPattern">
+ <item>"*1"</item>
+ <item>"*5"</item>
+ <item>"*9"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
new file mode 100755
index 000000000000..7b7c48d46b14
--- /dev/null
+++ b/core/res/res/values-mcc708-mnc001/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"*1"</item>
+ <item>"*5"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mk-watch/styles_material.xml b/core/res/res/values-mk-watch/styles_material.xml
deleted file mode 100644
index 89c3366d183f..000000000000
--- a/core/res/res/values-mk-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"кандидати"</font></string>
-</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 7d2ba9d982f4..66d538763488 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Апликацијата на администраторот за работниот профил недостасува или е оштетена. Како резултат на тоа, работниот профил и поврзаните податоци ќе се избришат. Контактирајте со администраторот за помош."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Работниот профил веќе не е достапен на уредов."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Се следи сообраќајот на мрежата"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Допрете за повеќе детали"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Допрете за да дознаете повеќе"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Уредот ќе се избрише"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"На апликацијата на администраторот ѝ недостасуваат компоненти или е оштетена, па не може да се користи. Уредот ќе се избрише сега. Контактирајте со администраторот за помош."</string>
<string name="me" msgid="6545696007631404292">"Јас"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролирајте го нивото на зумирање и позиционирање на екранот."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Користете движења"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да допрете, повлечете, штипнете и да користите други движења."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Движења за отпечатоци"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да сними движења што се направени на сензорот за отпечатоци на уредите."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"оневозможи или измени статусна лента"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволува апликацијата да ја оневозможи статусната лента или да додава или отстранува системски икони."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"да стане статусна лента"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дозволува апликацијата да ја користи услугата IMS за повици без ваша интервенција."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"прочитај ги статусот и идентитетот на телефонот"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Овозможува апликацијата да пристапи кон карактеристиките на телефонот на уредот. Оваа дозвола овозможува апликацијата да ги утврди телефонскиот број и ID на уредот, дали повикот е активен и далечинскиот број поврзан со повикот."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"пренасочи повици преку системот"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Дозволете ѝ на апликацијата да ги пренасочи повиците преку системот за да го подобри искуството при јавувањето."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"да го чита телефонскиот број"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ѝ дозволува на апликацијата да пристапи до телефонскиот број на уредот."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречи режим на штедење кај таблет"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метод на внес"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Дејства со текст"</string>
+ <string name="email" msgid="4560673117055050403">"E-пошта"</string>
+ <string name="dial" msgid="2275093056198652749">"Бирај"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијата е речиси полна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некои системски функции може да не работат"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Допрете за повеќе опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Се зема извештајот за грешки…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дозволува апликација да чита сесии на инсталирање. Тоа овозможува апликацијата да гледа детали за активни инсталации на пакет."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"барање пакети за инсталирање"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Дозволува апликацијата да бара инсталација на пакети."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"бара бришење пакети"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Дозволува апликацијата да бара бришење на пакетите."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"прашај дали да се игнорираат оптимизациите на батеријата"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Овозможува апликацијата да побара дозвола за игнорирање на оптимизациите на батеријата за таа апликација."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Допрете двапати за контрола на зумот"</string>
@@ -1425,9 +1436,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Отстрани"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Да го зголемиме звукот над препорачаното ниво?\n\nСлушањето звуци со голема јачина подолги периоди може да ви го оштети сетилото за слух."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Задржете со два прста за да се овозможи пристапност."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Овозможена е пристапност."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Пристапноста е откажана."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Кратенката за пристапност е ВКЛУЧЕНА"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Вклучете ја или исклучето ја <xliff:g id="SERVICE_NAME">%1$s</xliff:g> држејќи ги притиснати двете копчиња за јачина на звук 3 секунди.\n\nМоже да ја промените услугата во „Поставки“ &gt; „Пристапност“."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Исклучи ја кратенката за пристапност"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Остави ја вклучена"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Кратенката за пристапност ја вклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Кратенката за пристапност ја исклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Тековен корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Се префрла на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> се одјавува…"</string>
@@ -1673,20 +1687,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Оневозможен <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференциски повик"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Совет за алатка"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Игри"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музика и аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Филмови и видеа"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Фотографии и слики"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Социјални мрежи и комуникација"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Вести и списанија"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карти и навигација"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивност"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Простор на уредот"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ml-watch/styles_material.xml b/core/res/res/values-ml-watch/styles_material.xml
deleted file mode 100644
index 9d38c0d772f6..000000000000
--- a/core/res/res/values-ml-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"കാൻഡിഡേറ്റുകൾ"</font></string>
-</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index c0be3a438f7a..bb5455dd7684 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"ഔദ്യോഗിക പ്രൊഫൈൽ അഡ്‌മിൻ അപ്ലിക്കേഷൻ നഷ്‌ടപ്പെട്ടതോ കേടായതോ ആണ്. അക്കാരണത്താൽ നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും ബന്ധപ്പെട്ട വിവരവും ഇല്ലാതാക്കിയിരിക്കുന്നു. സഹായത്തിന് അഡ്‌മിനിസ്‌ട്രേറ്ററുമായി ബന്ധപ്പെടുക."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ഈ ഉപകരണത്തിൽ തുടർന്നങ്ങോട്ട് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ ലഭ്യമല്ല."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുന്നു"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"കൂടുതൽ വിശദാംശങ്ങൾക്ക് ടാപ്പുചെയ്യുക"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"കൂടുതലറിയുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"നിങ്ങളുടെ ഉപകരണം മായ്‌ക്കും"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"അഡ്‌മിൻ അപ്ലിക്കേഷൻ, ഘടകഭാഗങ്ങൾ നഷ്‌ടപ്പെട്ടതോ കേടായതോ ആണെങ്കിൽ ഉപയോഗിക്കാനാവില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ ഇല്ലാതാക്കും. സഹായത്തിന് നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
<string name="me" msgid="6545696007631404292">"ഞാന്‍"</string>
@@ -270,7 +270,7 @@
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"നിങ്ങൾ സംവദിക്കുന്ന ഒരു വിൻഡോയുടെ ഉള്ളടക്കം പരിശോധിക്കുക."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"സ്‌പർശനം വഴി പര്യവേക്ഷണം ചെയ്യുക ഓൺ ചെയ്യുക"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"ടാപ്പുചെയ്ത ഇനങ്ങൾ ഉച്ചത്തിൽ പറയപ്പെടും, ജെസ്റ്ററുകൾ ഉപയോഗിച്ച് സ്‌ക്രീൻ അടുത്തറിയാവുന്നതാണ്."</string>
- <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"മെച്ചപ്പെടുത്തിയ വെബ് പ്രവേശനക്ഷമത ഓണാക്കുക"</string>
+ <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"മെച്ചപ്പെടുത്തിയ വെബ് ഉപയോഗസഹായി ഓണാക്കുക"</string>
<string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"അപ്ലിക്കേഷൻ ഉള്ളടക്കം കൂടുതൽ ആക്‌സസ്സുചെയ്യാൻ കഴിയുന്നതാക്കാൻ സ്‌ക്രിപ്റ്റുകൾ ഇൻസ്റ്റാളുചെയ്യാനിടയുണ്ട്."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"നിങ്ങൾ ടൈപ്പുചെയ്യുന്ന വാചകം നിരീക്ഷിക്കുക"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ക്രെഡിറ്റ് കാർഡ് നമ്പറുകളും പാസ്‌വേഡുകളും പോലുള്ള വ്യക്തിഗത ഡാറ്റ ഉൾപ്പെടുന്നു."</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ഡിസ്പ്ലേയുടെ സൂം നിലയും പൊസിഷനിംഗും നിയന്ത്രിക്കുക."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ജെസ്‌റ്ററുകൾ നിർവഹിക്കുക"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ടാപ്പുചെയ്യാനോ സ്വൈപ്പുചെയ്യാനോ പിഞ്ചുചെയ്യാനോ മറ്റ് ജെസ്‌റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ഫിംഗർപ്രിന്റ് ജെസ്‌റ്ററുകൾ"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ഉപകരണത്തിന്റെ ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെയ്‌ത ജെസ്‌റ്ററുകൾ ക്യാപ്‌ചർ ചെയ്യാനാകും."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"സ്റ്റാറ്റസ് ബാർ പ്രവർത്തനരഹിതമാക്കുക അല്ലെങ്കിൽ പരിഷ്‌ക്കരിക്കുക"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"നില ബാർ പ്രവർത്തരഹിതമാക്കുന്നതിന് അല്ലെങ്കിൽ സിസ്‌റ്റം ഐക്കണുകൾ ചേർക്കുന്നതിനും നീക്കംചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"സ്റ്റാറ്റസ് ബാർ ആയിരിക്കുക"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ കോളുകൾ ചെയ്യാൻ IMS സേവനം ഉപയോഗിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ഫോൺ നിലയും ഐഡന്റിറ്റിയും റീഡുചെയ്യുക"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ഉപകരണത്തിന്റെ ഫോൺ സവിശേഷതകൾ ആക്‌സസ്സുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഈ അനുമതി ഫോൺ നമ്പർ, ഉപകരണ ഐഡികൾ, ഒരു കോൾ സജീവമാണോയെന്നത്, ഒരു കോൾ കണക്റ്റുചെയ്‌ത വിദൂര നമ്പർ എന്നിവ നിർണ്ണയിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"കോളുകൾ സിസ്റ്റത്തിലൂടെ വിടുക"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"കോളിംഗ് അനുഭവം ‌മെച്ചപ്പെടുത്തുന്നതിനായി തങ്ങളുടെ ‌കോളുകൾ സിസ്റ്റത്തിലേയ്ക്ക് വഴിതിരിച്ചുവിടാൻ ആപ്പുകളെ അനുവദിക്കുന്നു."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ഫോൺ നമ്പർ വായിക്കുക"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ഉപകരണത്തിന്റെ ഫോൺ നമ്പർ ആക്സസ്സ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"സുഷുപ്‌തിയിലാകുന്നതിൽ നിന്ന് ടാബ്‌ലെറ്റിനെ തടയുക"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ഇല്ലാതാക്കുക"</string>
<string name="inputMethod" msgid="1653630062304567879">"ടൈപ്പുചെയ്യൽ രീതി"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ടെക്‌സ്‌റ്റ് പ്രവർത്തനങ്ങൾ"</string>
+ <string name="email" msgid="4560673117055050403">"ഇമെയിൽ"</string>
+ <string name="dial" msgid="2275093056198652749">"ഡയൽ ചെയ്യുക"</string>
+ <string name="map" msgid="5441053548030107189">"മാപ്പ്"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"സംഭരണയിടം കഴിഞ്ഞു"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ചില സിസ്റ്റം പ്രവർത്തനങ്ങൾ പ്രവർത്തിക്കണമെന്നില്ല."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"സിസ്‌റ്റത്തിനായി മതിയായ സംഭരണമില്ല. 250MB സൗജന്യ സംഭരണമുണ്ടെന്ന് ഉറപ്പുവരുത്തി പുനരാരംഭിക്കുക."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്‌റ്റുചെയ്‌തു"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ഡീബഗ്ഗിംഗ് പ്രവർത്തനരഹിതമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ഇൻസ്റ്റാൾ ചെയ്‌ത സെഷനുകൾ റീഡുചെയ്യുന്നതിന് ഒരു അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. സജീവ പാക്കേജ് ഇൻസ്റ്റാളേഷനുകളെക്കുറിച്ചുള്ള വിശദാംശങ്ങൾ കാണുന്നതിന് ഇത് അനുവദിക്കുന്നു."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"പാക്കേജുകൾ ഇൻസ്റ്റാൾ ചെയ്യാൻ അഭ്യർത്ഥിക്കുക"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"പാക്കേജുകളുടെ ഇൻസ്റ്റാളേഷൻ അഭ്യർത്ഥിക്കാൻ ഒരു അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"പാക്കേജുകൾ ഇല്ലാതാക്കാൻ അഭ്യർത്ഥിക്കുക"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"പാക്കേജുകളെ ഇല്ലാതാക്കാനുള്ള അഭ്യർത്ഥന നടത്താൻ ആപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകൾ അവഗണിക്കാൻ ആവശ്യപ്പെടുക"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ആപ്പിന് വേണ്ടിയുള്ള ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകളെ അവഗണിക്കാനുള്ള അനുമതി ചോദിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"സൂം നിയന്ത്രണം ലഭിക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
@@ -1221,7 +1232,7 @@
<string name="forward_intent_to_work" msgid="621480743856004612">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നു"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"ടൈപ്പുചെയ്യൽ രീതി"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"സമന്വയിപ്പിക്കുക"</string>
- <string name="accessibility_binding_label" msgid="4148120742096474641">"പ്രവേശനക്ഷമത"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"ഉപയോഗസഹായി"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"വാൾപേപ്പർ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"വാൾപേപ്പർ മാറ്റുക"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"അറിയിപ്പ് ലിസണർ"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"നീക്കംചെയ്യുക"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്‌ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"പ്രവേശനക്ഷമത പ്രവർത്തനക്ഷമമാക്കാൻ രണ്ട് വിരലുകൾ അമർത്തിപ്പിടിക്കുക."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"പ്രവേശനക്ഷമത പ്രവർത്തനക്ഷമമാക്കി."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"പ്രവേശനക്ഷമത റദ്ദാക്കി."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി ഓൺ ആണ്"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"രണ്ട് ശബ്ദ ‌ബട്ടണുകളും 3 സെക്കന്റ് നേരം അമർത്തിപ്പിടിച്ച് <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ അല്ലെങ്കിൽ ഓഫ് ചെയ്യുക.\n\nക്രമീകരണങ്ങൾ&gt; ഉപയോഗസഹായി എന്നതിലൂടെ നിങ്ങൾക്ക് സേവനം മാറ്റാൻ കഴിയും."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"കുറുക്കുവഴി ‌ഓഫാക്കുക"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ഓണാക്കിയിടുക"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ ചെയ്തിരിക്കുന്നു"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫ് ചെയ്തിരിക്കുന്നു"</string>
<string name="user_switched" msgid="3768006783166984410">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="NAME">%1$s</xliff:g> ആണ്."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിലേക്ക് മാറുന്നു…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> ലോഗൌട്ട് ചെയ്യുന്നു…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="conference_call" msgid="3751093130790472426">"കോൺഫറൻസ് കോൾ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ടൂൾ ടിപ്പ്"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ഗെയിമുകള്‍"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"സംഗീതവും ഓഡിയോയും"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"സിനിമകളും വീഡിയോയും"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ഫോട്ടോകളും ചിത്രങ്ങളും"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"സാമൂഹിക ആപ്സുകളും ആശയവിനിമയവും"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"വാർത്തകളും മാസികകളും"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"മാപ്സും നാവിഗേഷനും"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ഉല്‍‌പ്പാദനക്ഷമത"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ഉപകരണ സ്റ്റോറേജ്"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-mn-watch/styles_material.xml b/core/res/res/values-mn-watch/styles_material.xml
deleted file mode 100644
index f65ea48e2376..000000000000
--- a/core/res/res/values-mn-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"нэр дэвшигч"</font></string>
-</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 907846074b48..0f7d43a76e13 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Ажлын профайлын зохицуулагч аппликейшн алга болсон эсвэл эвдэрсэн байна. Үүний улмаас таны ажлын профайл болон холбогдох мэдээллүүд устсан байна. Тусламж хэрэгтэй байгаа бол админтай холбоо барина уу."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Таны ажлын профайл энэ төхөөрөмж дээр ажиллахгүй болсон байна."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Сүлжээний ачааллыг хянаж байна"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Дэлгэрэнгүй мэдээлэл авахын тулд товшино уу"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Дэлгэрэнгүй үзэхийн тулд товшино уу"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Таны төхөөрөмж устах болно."</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Зохицуулагч аппликейшны зарим нэг хэсэг дутуу эсвэл эвдэрсэн байгаа тул ашиглах боломжгүй байна. Таны төхөөрөмжийг одоо устгах болно. Танд тусламж хэрэгтэй байгаа бол админтайгаа холбоо барина уу."</string>
<string name="me" msgid="6545696007631404292">"Би"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дэлгэцийн томруулах түвшин болон байршлыг хянах."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Зангах"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Товших, шудрах, жижигрүүлэх болон бусад зангааг хийх боломжтой."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Хурууны хээний зангаа"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Төхөөрөмжийн хурууны хээ мэдрэгчид зангасан зангааг танина."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"статус самбарыг идэвхгүй болгох болон өөрчлөх"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Апп нь статус самбарыг идэвхгүй болгох эсвэл систем дүрсийг нэмэх, хасах боломжтой."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"статусын хэсэг болох"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Апп нь дуудлага хийхдээ таны оролцоогүйгээр IMS үйлчилгээг ашиглах боломжтой."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"утасны статус ба таниулбарыг унших"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Апп нь төхөөрөмжийн утасны функцд хандах боломжтой. Энэ зөвшөөрөл нь апп-д утасны дугаар болон төхөөрөмжийн ID-г, дуудлага идэвхтэй эсэх, холын дугаар дуудлагаар холбогдсон байгаа эсэхийг тогтоох боломжийг олгоно,"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"системээр дамжуулах дуудлага"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Дуудлагыг сайжруулахын тулд дуудлагаа системээр дамжуулах зөвшөөрлийг апп-д олгодог."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"утасны дугаарыг харах"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Төхөөрөмжийн утасны дугаарт хандах зөвшөөрлийг аппд олгоно."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"таблетыг унтуулахгүй байлгах"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Устгах"</string>
<string name="inputMethod" msgid="1653630062304567879">"Оруулах арга"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Текст үйлдэл"</string>
+ <string name="email" msgid="4560673117055050403">"Имэйл"</string>
+ <string name="dial" msgid="2275093056198652749">"Залгах"</string>
+ <string name="map" msgid="5441053548030107189">"Газрын зураг"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сангийн хэмжээ дутагдаж байна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Зарим систем функц ажиллахгүй байна"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Системд хангалттай сан байхгүй байна. 250MБ чөлөөтэй зай байгаа эсэхийг шалгаад дахин эхлүүлнэ үү."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Бусад сонголтыг харахын тулд товшино уу."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB-н алдаа засварлахыг идэвхгүй болгохын тулд товшино уу."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Алдааны тайланг авч байна..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Аппликешн-д суулгах сешн уншихыг зөвшөөрнө. Энэ нь идэвхтэй багцуудыг суулгалтын талаар дэлгэрэнгүй мэдээллийг үзэх боломж олгоно."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"багц суулгахыг хүсэх"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Аппликейшн нь багц суулгахыг хүсэх боломжтой."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"багцыг устгах хүсэлт"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Апп-д багц устгах хүсэлт тавихыг зөвшөөрнө."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"батерейны оновчлол алгасахыг асуух"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Тухайн аппaaс батерейны оновчлол алгасах зөвшөөрөл асуухыг зөвшөөрдөг."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Өсгөх контрол дээр хоёр удаа товшино уу"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Виртуал Орчин (VR) сонсогч"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR сонсогч"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Мэдэгдлийг ангилах үйлчилгээ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN идэвхтэй болов"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Хялбар горимыг идэвхжүүлэх бол хоёр хуруугаараа доошлуулаад хүлээнэ үү."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Хялбаршуулсан горим идэвхжив."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Хандалт цуцлагдсан."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Хүртээмжийн товчлол АСААЛТТАЙ байна"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтрааж, эсвэл асаахын тулд дууны товчлуурыг 3 секунд дарна уу.\n\nТа энэ үйлчилгээг Тохиргоо &gt; Хүртээмж хэсэгт өөрчлөх боломжтой."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Товчлолыг унтраах"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Асаалттай орхих"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаасан"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраасан"</string>
<string name="user_switched" msgid="3768006783166984410">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> руу сэлгэж байна…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>-с гарч байна…"</string>
@@ -1669,20 +1682,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>-г цуцалсан"</string>
<string name="conference_call" msgid="3751093130790472426">"Хурлын дуудлага"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Зөвлөмж"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Тоглоом"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Хөгжим &amp; аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Кино &amp; видео"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Гэрэл зураг &amp; зураг"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Нийгмийн &amp; харилцаа холбоо"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Мэдээ &amp; сэтгүүл"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Газрын зураг &amp; зүг чиг"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Бүтээмж"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Төхөөрөмжийн сан"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-mr-watch/styles_material.xml b/core/res/res/values-mr-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-mr-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index e45517870990..69cf831adeb6 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -68,10 +68,10 @@
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"येणारा कॉलर ID"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"केला जाणारा कॉलर ID"</string>
- <string name="ColpMmi" msgid="3065121483740183974">"कनेक्ट केलेला रेखा ID"</string>
- <string name="ColrMmi" msgid="4996540314421889589">"कनेक्ट केलेला रेखा ID प्रतिबंध"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"येणारा कॉलर आयडी"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"केला जाणारा कॉलर आयडी"</string>
+ <string name="ColpMmi" msgid="3065121483740183974">"कनेक्ट केलेला रेखा आयडी"</string>
+ <string name="ColrMmi" msgid="4996540314421889589">"कनेक्ट केलेला रेखा आयडी प्रतिबंध"</string>
<string name="CfMmi" msgid="5123218989141573515">"कॉल अग्रेषण"</string>
<string name="CwMmi" msgid="9129678056795016867">"कॉल प्रतीक्षा"</string>
<string name="BaMmi" msgid="455193067926770581">"कॉल सोडून"</string>
@@ -83,12 +83,12 @@
<string name="RuacMmi" msgid="7827887459138308886">"अवांछित त्रासदायक कॉल ला नकार"</string>
<string name="CndMmi" msgid="3116446237081575808">"कॉल करणार्‍या नंबरचे वितरण"</string>
<string name="DndMmi" msgid="1265478932418334331">"व्यत्यय आणू नका"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित वर सेट असतो. पुढील कॉल: प्रतिबंधित"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"कॉलर आयडी डीफॉल्‍ट रूपात प्रतिबंधित वर सेट असतो. पुढील कॉल: प्रतिबंधित"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"कॉलर आयडी डीफॉल्‍ट रूपात प्रतिबंधित वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"कॉलर आयडी डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर आयडी डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवेची तरतूद केलेली नाही."</string>
- <string name="CLIRPermanent" msgid="3377371145926835671">"आपण कॉलर ID सेटिंग बदलू शकत नाही."</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"आपण कॉलर आयडी सेटिंग बदलू शकत नाही."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"डेटा सेवा अवरोधित केली आहे."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"आणीबाणी सेवा अवरोधित केली आहे."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"व्हॉइस सेवा अवरोधित केली आहे."</string>
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"कार्य प्रोफाईल प्रशासन अॅप गहाळ आहे किंवा दुषित आहे. यामुळे, आपले कार्य प्रोफाईल आणि संबंधित डेटा हटविला गेला आहे. सहाय्यासाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"आपले कार्य प्रोफाईल या डिव्‍डाइसवर यापुढे उपलब्‍ध नाही."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"नेटवर्क रहदारीचे परीक्षण केले जात आहे"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"अधिक तपशीलांसाठी टॅप करा"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"अधिक जाणून घेण्यासाठी टॅप करा"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"आपले डिव्हाइस मिटविले जाईल"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"प्रशासन अॅपमध्ये घटक गहाळ किंवा दूषित आहेत आणि वापरला जाऊ शकत नाही. आपले डिव्हाइस आता मिटविले जाईल. सहाय्यासाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="me" msgid="6545696007631404292">"मी"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनाचा झूम स्तर आणि स्थिती निर्धारण नियंत्रित करा."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"जेश्चर करा"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"टॅप, स्वाइप, पिंच आणि इतर जेश्चर करू शकते."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फिंगरप्रिंट जेश्चर"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"डिव्‍हाइसच्‍या फिंगरप्रिंट सेंसरवर केलेले जेश्चर कॅप्‍चर करू शकते."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्टेटस बार अक्षम करा किंवा सुधारित करा"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"स्टेटस बार अक्षम करण्यासाठी किंवा सिस्टीम चिन्हे जोडण्यासाठी आणि काढण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"स्टेटस बार होऊ द्या"</string>
@@ -381,7 +383,9 @@
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्‍ये प्रवेश करा"</string>
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"आपल्‍या हस्तक्षेपाशिवाय अ‍ॅपला कॉल करण्‍यासाठी IMS सेवा वापरण्याची अनुमती देते."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फोन स्थिती आणि ओळख वाचा"</string>
- <string name="permdesc_readPhoneState" msgid="1639212771826125528">"डिव्हाइसच्या फोन वैशिष्ट्यांवर प्रवेश करण्यास अॅप ला अनुमती देते. ही परवानगी कॉल सक्रिय असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस ID आणि कॉलद्वारे कनेक्ट केलेला रीमोट नंबर निर्धारित करण्यासाठी अॅप ला अनुमती देते."</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"डिव्हाइसच्या फोन वैशिष्ट्यांवर प्रवेश करण्यास अॅप ला अनुमती देते. ही परवानगी कॉल सक्रिय असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस आयडी आणि कॉलद्वारे कनेक्ट केलेला रीमोट नंबर निर्धारित करण्यासाठी अॅप ला अनुमती देते."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"प्रणालीच्या माध्यमातून कॉल रूट करा"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"कॉल करण्याचा अनुभव सुधारण्यासाठी अॅपला त्याचे कॉल प्रणालीच्या माध्यमातून रूट करू देते."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फोन नंबर वाचा"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"अॅपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टॅबलेट निष्क्रिय होण्यापासून प्रतिबंधित करा"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"हटवा"</string>
<string name="inputMethod" msgid="1653630062304567879">"इनपुट पद्धत"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"मजकूर क्रिया"</string>
+ <string name="email" msgid="4560673117055050403">"ईमेल"</string>
+ <string name="dial" msgid="2275093056198652749">"डायल करा"</string>
+ <string name="map" msgid="5441053548030107189">"नकाशा"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"संचयन स्थान संपत आहे"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"काही सिस्टम कार्ये कार्य करू शकत नाहीत"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टीमसाठी पुरेसे संचयन नाही. आपल्याकडे 250MB मोकळे स्थान असल्याचे सुनिश्चित करा आणि रीस्टार्ट करा."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"अधिक पर्यायांसाठी टॅप करा."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्‍ट केले"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करणे अक्षम करण्यासाठी टॅप करा."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"दोष अहवाल घेत आहे..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"अनुप्रयोगास स्‍थापना सत्र वाचण्‍याची अनुमती देते. हे सक्रिय पॅकेज स्‍थापनांविषयी तपशील पाहाण्‍याची यास अनुमती देते."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"पॅकेज स्थापित करण्यासाठी विनंती करा"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"पॅकेजच्या स्थापना करण्यासाठी अनुप्रयोगास अनुमती देते."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"पॅकेज हटवण्याची विनंती"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"अनुप्रयोगास पॅकेज हटवण्यासाठी विनंती करण्याची अनुमती देते."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यास सांगा"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"त्या अॅपसाठी बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यासाठी अॅपला परवानगी मागण्याची अनुमती देते."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"झूम नियंत्रणासाठी दोनदा टॅप करा"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"काढा"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"शिफारस केलेल्‍या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्‍याने आपल्‍या श्रवणशक्तीची हानी होऊ शकते."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"प्रवेशयोग्यता सक्षम करण्यासाठी दोन बोटांनी खाली धरून ठेवा."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"प्रवेशयोग्यता सक्षम."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"प्रवेशयोग्यता रद्द."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"प्रवेशयोग्यता शॉर्टकट चालू आहे"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"दोन्ही व्हॉल्यूम बटणे 3 सेकंदांसाठी धरून ठेवून <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू किंवा बंद करा.\n\nआपण सेटिंग्ज &gt; प्रवेशयोग्यता मधून सेवा बदलू शकता."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"शॉर्टकट बंद करा"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"तसेच सोडा"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू केली"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केली"</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान वापरकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> वर स्विच करत आहे…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करीत आहे…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> अक्षम केले"</string>
<string name="conference_call" msgid="3751093130790472426">"परिषद कॉल"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"गेम"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"संगीत आणि ऑडिओ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"चित्रपट आणि व्हिडिओ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"फोटो आणि प्रतिमा"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"सामाजिक आणि संप्रेषण"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"बातम्‍या आणि मासिके"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"नकाशे आणि नेव्हिगेशन"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादनक्षमता"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"डिव्‍हाइस संचय"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ms-watch/styles_material.xml b/core/res/res/values-ms-watch/styles_material.xml
deleted file mode 100644
index 3f5e68742a5e..000000000000
--- a/core/res/res/values-ms-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"calon"</font></string>
-</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index d41ff77fbcb6..ad053b9351db 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Apl admin profil kerja hilang atau pun rosak. Akibatnya, profil kerja anda dan data yang berkaitan telah dipadam. Hubungi pentadbir anda untuk mendapatkan bantuan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profil kerja anda tidak tersedia pada peranti ini lagi."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Trafik rangkaian sedang dipantau"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Ketik untuk mendapatkan butiran lanjut"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Ketik untuk mengetahui lebih lanjut"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Peranti anda akan dipadam"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Apl pentadbir kehilangan komponen atau rosak dan tidak boleh digunakan. Sekarang peranti anda akan dipadam. Hubungi pentadbir anda untuk mendapatkan bantuan."</string>
<string name="me" msgid="6545696007631404292">"Saya"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kawal tahap zum dan kedudukan paparan."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Lakukan gerak isyarat"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Boleh ketik, leret, cubit dan laksanakan gerak isyarat lain."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gerak isyarat cap jari"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Boleh menangkap gerak isyarat yang dilakukan pada penderia cap jari peranti."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"lumpuhkan atau ubah suai bar status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Membenarkan apl melumpuhkan bar status atau menambah dan mengalih keluar ikon sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"jadi bar status"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Membenarkan apl menggunakan perkhidmatan IMS untuk membuat panggilan tanpa campur tangan anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca status dan identiti telefon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Membenarkan apl mengakses ciri telefon pada peranti. Kebenaran ini membolehkan apl menentukan nombor telefon dan ID peranti, sama ada panggilan aktif dan nombor jauh yang dihubungkan dengan panggilan."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"halakan panggilan menerusi sistem"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Membenarkan apl menghalakan panggilan menerusi sistem untuk meningkatkan pengalaman panggilan."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"baca nombor telefon"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Membenarkan apl mengakses nombor telefon peranti."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"menghalang tablet daripada tidur"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Padam"</string>
<string name="inputMethod" msgid="1653630062304567879">"Kaedah input"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
+ <string name="email" msgid="4560673117055050403">"E-mel"</string>
+ <string name="dial" msgid="2275093056198652749">"Dail"</string>
+ <string name="map" msgid="5441053548030107189">"Peta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tidak cukup storan untuk sistem. Pastikan anda mempunyai 250MB ruang kosong dan mulakan semula."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Ketik untuk mendapatkan lagi pilihan."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Ketik untuk melumpuhkan penyahpepijatan USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk melumpuhkan penyahpepijatan USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan pepijat…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kongsi laporan pepijat?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Berkongsi laporan pepijat…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Membenarkan aplikasi membaca sesi pemasangan Ini membenarkan apl melihat butiran mengenai pemasangan pakej yang aktif."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"minta pakej pemasangan"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Membenarkan aplikasi meminta pemasangan pakej."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"minta pemadaman pakej"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Membenarkan aplikasi meminta pemadaman pakej."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"minta kebenaran untuk mengabaikan pengoptimuman bateri"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Membenarkan apl meminta kebenaran untuk mengabaikan pengoptimuman bateri untuk apl itu."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ketik dua kali untuk mendapatkan kawalan zum"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Teruskan menahan dengan dua jari untuk mendayakan kebolehcapaian."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Pintasan Kebolehaksesan DIHIDUPKAN"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Hidupkan atau matikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dengan menahan kedua-dua butang kelantangan selama 3 saat.\n\nAnda boleh menukar perkhidmatan dalam Tetapan &gt; Kebolehaksesan."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Matikan Pintasan"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Biarkan hidup"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Bertukar kepada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Log keluar daripada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
<string name="conference_call" msgid="3751093130790472426">"Panggilan Sidang"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan item"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Permainan"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzik &amp; Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filem &amp; Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto &amp; Imej"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosial &amp; Komunikasi"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Berita &amp; Majalah"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Peta &amp; Navigasi"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktiviti"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Storan peranti"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-my-watch/styles_material.xml b/core/res/res/values-my-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-my-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 291d92d453e1..4454c2b5c314 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"အလုပ်ပရိုဖိုင် အက်ဒမင် အပလီကေးရှင်းပျောက်နေသည် သို့မဟုတ် ပျက်စီးနေသည်။ ထို့ကြောင့် သင့်အလုပ်ပရိုဖိုင်နှင့် ဆက်စပ်နေသော ဒေတာများအား ပယ်ဖျက်ခြင်းခံရမည်။ အကူအညီတောင်းခံရန် သင့်အက်ဒမင်အား ဆက်သွယ်ပါ။"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ဤစက်ကိရိယာတွင် သင့်အလုပ်ပရိုဖိုင် မရှိတော့ပါ။"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ကွန်ရက်အသွားအလာကို စောင့်ကြည့်နေပါသည်"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"နောက်ထပ်အသေးစိတ် အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"ပိုမိုလေ့လာရန် တို့ပါ"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"အက်ဒမင် အက်ပ်၏ အစိတ်အပိုင်းများ ပျောက်နေသည် သို့မဟုတ် ပျက်စီးနေသည်။ သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်။ အကူအညီတောင်းခံရန် သင့်အက်ဒမင်အား ဆက်သွယ်ပါ။"</string>
<string name="me" msgid="6545696007631404292">"ကျွန်ုပ်"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"မျက်နှာပြင် ဇူးမ်အရွယ်နှင့် နေရာချထားခြင်းကို ထိန်းချုပ်ပါ။"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"လက်ဟန်များ အသုံးပြုပါ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"တို့ခြင်း၊ ပွတ်ဆွဲခြင်း၊ နှင့် အခြား လက်ဟန်များကို အသုံးပြုနိုင်ပါသည်။"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"လက်ဗွေရာများ"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ကိရိယာ၏ လက်ဗွေအာရုံခံကိရိယာတွင် နှိပ်ထားသည်များကို မှတ်သားထားနိုင်သည်။"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"အခြေအနေပြဘားအား အလုပ်မလုပ်ခိုင်းရန်သို့မဟုတ် မွမ်းမံရန်"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"အက်ပ်အား အခြေအနေပြ ဘားကို ပိတ်ခွင့် သို့မဟတ် စနစ် အိုင်ကွန်များကို ထည့်ခြင်း ဖယ်ရှားခြင်း ပြုလုပ်ခွင့် ပြုသည်။"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"သင့်ရဲ့ဝင်ရောက်စွက်ဖက်မှုမပါဘဲ IMS ဝန်ဆောင်မှုကိုအသုံးပြုပြီး ဖုန်းခေါ်ဆိုနိုင်ရန် အပ်ဖ်ကို ခွင့်ပြုထားပါ။"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ဖုန်းရဲ့ အခြေအနေ နှင့် အမှတ်သညာအား ဖတ်ခြင်း"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"အပလီကေးရှင်းအား ဖုန်းရဲ့ စွမ်းဆောင်ချက်များအား သုံးခွင့်ပြုပါ။ အပလီကေးရှင်းအနေဖြင့် ဖုန်းနံပါတ်၊ စက်နံပါတ်၊ ဖုန်းခေါ်နေမှု ရှိမရှိနှင့် တဖက်မှ ဖုန်းနံပါတ် များအား သိရှိနိုင်ပါသည်"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ခေါ်ဆိုမှုများကို စနစ်မှတစ်ဆင့် ဖြတ်သန်းခွင့်ပြုပါ"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"ခေါ်ဆိုမှု အတွေ့အကြုံ ပိုမိုကောင်းမွန်လာစေရန်အတွက် အက်ပ်၏ ခေါ်ဆိုမှုအား စနစ်မှတစ်ဆင့် ဖြတ်သန်းရန် ခွင့်ပြုပါသည်။"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ဖုန်းနံပါတ်ကို ဖတ်ရန်"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"အက်ပ်ကို စက်ပစ္စည်း၏ ဖုန်းနံပါတ် အသုံးပြုခွင့်ပေးပါ။"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"တက်ပလက်အား ပိတ်ခြင်းမှ ကာကွယ်ခြင်း"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ဖျက်ရန်"</string>
<string name="inputMethod" msgid="1653630062304567879">"ထည့်သွင်းရန်နည်းလမ်း"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"စာတို လုပ်ဆောင်ချက်"</string>
+ <string name="email" msgid="4560673117055050403">"အီးမေးလ်"</string>
+ <string name="dial" msgid="2275093056198652749">"ခေါ်ဆိုရန်"</string>
+ <string name="map" msgid="5441053548030107189">"မြေပုံ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"သိမ်းဆည်သော နေရာ နည်းနေပါသည်"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"တချို့ စနစ်လုပ်ငန်းများ အလုပ် မလုပ်ခြင်း ဖြစ်နိုင်ပါသည်"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"စနစ်အတွက် သိုလှောင်ခန်း မလုံလောက်ပါ။ သင့်ဆီမှာ နေရာလွတ် ၂၅၀ MB ရှိတာ စစ်ကြည့်ပြီး စတင်ပါ။"</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"နောက်ထပ်ရွေးချယ်စရာများအတွက် တို့ပါ။"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ဆက်သွယ်ရေးစနစ်ကို ပိတ်ရန် တို့ပါ။"</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ချွတ်ယွင်းချက် အစီရင်ခံစာပြုစုနေသည်..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"အပလီကေးရှင်းအား တပ်ဆင်ရေး ချိတ်ဆက်မှုများကို ဖတ်ခွင့်ပြုသည်။ ၎င်းသည် ဖွင့်သုံးနေသည့် အထုပ်အား တပ်ဆင်မှုဆိုင်ရာ အသေးိစတ်များကို ကြည့်ရှုခွင့် ပြုသည်။"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"တပ်ဆင်ရေး အထုပ်များကို တောင်းဆိုပါ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ပက်ကေ့များ သွင်းယူခြင်းအတွက် တောင်းဆိုရန် အပလီကေးရှင်းအား ခွင့်ပြုပါ"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ပက်ကေ့ဂျ်များကို ဖျက်ရန် တောင်းဆိုပါ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"အပလီကေးရှင်းတစ်ခုအား ပက်ကေ့ဂျ်များကို ဖျက်ရန် တောင်းဆိုခွင့်ပေးပါ။"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် ပြုလုပ်ခြင်းကို လျစ်လျူရှုရန် တောင်းဆိုပါ"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် ပြုလုပ်ခြင်းကို လျစ်လျူရှုရန်အတွက် ခွင့်ပြုချက်တောင်းရန် အက်ပ်ကို ခွင့်ပြုပါ။"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ဇူးမ်အသုံးပြုရန် နှစ်ချက်တို့ပါ"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ဖယ်ရှားရန်"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"လက်နှစ်ချောင်းကို ထိကိုင်ထားခြင်းဖြင့် သုံးစွဲနိုင်မှုကို ခွင့်ပြုပါ"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"သုံးစွဲခွင့် ကို ဖွင့်ထားသည်"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"အသုံးပြုခွင့် ဖျက်လိုက်သည်"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားသည်"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"အသံအတိုးလျှော့ခလုတ် နှစ်ခုလုံးကို ၃ စက္ကန့်ဖိထားခြင်းဖြင့် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> အား အဖွင့် သို့မဟုတ် အပိတ် လုပ်နိုင်ပါသည်။\n\nဝန်ဆောင်မှုကို ဆက်တင်များ &gt; အများသုံးစွဲနိုင်မှုတွင် ပြောင်းလဲနိုင်သည်။"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"ဖြတ်လမ်းလင့်ခ်ကို ပိတ်ရန်"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ဖွင့်ထားရန်"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ဖွင့်လိုက်ပါသည်"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ပိတ်လိုက်ပါသည်"</string>
<string name="user_switched" msgid="3768006783166984410">"လက်ရှိအသုံးပြုနေသူ <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>သို့ ပြောင်းနေ…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>ကို ထွက်ပစ်ပါတော့မည်..."</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ပိတ်ထားသည့် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"လူအမြောက်အမြားတပြိုင်နက် ခေါ်ဆိုမှု"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"အကြံပြုချက်ပြ ပေါ့အပ် ဝင်းဒိုး"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ဂိမ်းများ"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"တေးဂီတနှင့် အသံ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ရုပ်ရှင်နှင့် ဗီဒီယို"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ဓာတ်ပုံနှင့် ပုံများ"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"လူမှု ဆက်သွယ်ရေး"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"မြေပုံနှင့် ခရီးလမ်းညွှန်ချက်"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ထုတ်လုပ်နိုင်မှု"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"စက်ပစ္စည်း သိုလှောင်ခန်း"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-nb-watch/styles_material.xml b/core/res/res/values-nb-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-nb-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 70a8828dbea2..d23441f5e58e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Arbeidsprofilens admin-app mangler eller er ødelagt. Dette har ført til at arbeidsprofilen og alle data knyttet til den er blitt slettet. Kontakt administratoren for å få hjelp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Arbeidsprofilen din er ikke lenger tilgjengelig på denne enheten."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Nettverkstrafikken blir overvåket"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Trykk for å få flere detaljer"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Trykk for å finne ut mer"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Enheten blir slettet"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Admin-appen mangler komponenter eller er ødelagt, og kan ikke brukes. Enheten din blir nå slettet. Kontakt administratoren for å få hjelp."</string>
<string name="me" msgid="6545696007631404292">"Meg"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér zoomenivået og plasseringen for skjermen."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gjøre bevegelser"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, sveipe, klype og gjøre andre bevegelser."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bevegelser på fingeravtrykkssensor"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan fange inn bevegelser som utføres på enhetens fingeravtrykkssensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lar appen deaktivere statusfeltet eller legge til og fjerne systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vise appen i statusfeltet"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Lar appen bruke nettprattjenesten til å ringe uten at du gjør noe."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lese telefonstatus og -identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lar appen bruke enhetens telefonfunksjoner. Med denne tillatelsen kan appen finne telefonnummer og enhets-ID-er, registrere om en samtale pågår, og se det eksterne nummeret det opprettes en forbindelse med via oppringing."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"send anrop gjennom systemet"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Lar appen sende anrop gjennom systemet for å forbedre anropsopplevelsen."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"les telefonnummeret"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Gir appen tilgang til telefonnummeret til enheten."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"hindre nettbrettet fra å gå over til sovemodus"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Slett"</string>
<string name="inputMethod" msgid="1653630062304567879">"Inndatametode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
+ <string name="email" msgid="4560673117055050403">"E-post"</string>
+ <string name="dial" msgid="2275093056198652749">"Ring"</string>
+ <string name="map" msgid="5441053548030107189">"Kart"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det er ikke nok lagringsplass for systemet. Kontrollér at du har 250 MB ledig plass, og start på nytt."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Trykk for å få flere alternativ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Trykk for å slå av feilsøking via USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Velg for å deaktivere USB-debugging."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kjører feilrapport …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele feilrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler feilrapporten …"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillater en app å lese installeringsøkter. Dette gjør det mulig for den å se detaljer om aktive pakkeinstallasjoner."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"be om installasjon av pakker"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lar apper be om installasjon av pakker."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"be om pakkesletting"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Lar apper be om sletting av pakker."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"be om å ignorere batterioptimaliseringer"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Gjør det mulig for apper å be om tillatelse til å ignorere batterioptimaliseringer for disse appene."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trykk to ganger for zoomkontroll"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyttetjeneste for virtuell virkelighet"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyttetjeneste for VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Betingelsesleverandør"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste for rangering av varsler"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsett å holde nede to fingre for å aktivere tilgjengelighet."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Tilgjengelighet er aktivert."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgjengelighetstjenesten ble avbrutt."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Snarvei for tilgjengelighet er PÅ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Slå <xliff:g id="SERVICE_NAME">%1$s</xliff:g> på eller av ved å holde begge volumknappene nede i tre sekunder.\n\nDu kan endre tjenesten i Innstillinger og Tilgjengelighet."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Slå av snarveien"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"La den være på"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Bytter til <xliff:g id="NAME">%1$s</xliff:g> …"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Logger av <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferansesamtale"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Verktøytips"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Spill"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musikk og lyd"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmer og video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotografier og bilder"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosialt og kommunikasjon"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Nyheter og tidsskrifter"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kart og navigering"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Lagring på enheten"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ne-watch/styles_material.xml b/core/res/res/values-ne-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ne-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0653ab7e3954..d513ff3833a8 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"कार्य प्रोफाइल व्यवस्थापक अनुप्रयोग या त हराएको या त बिग्रेको छ। फलस्वरूप, तपाईँको कार्य प्रोफाइल र सम्बन्धित डेटा मेटिएको छ। सहयोगको लागि तपाईँको व्यवस्थापकसँग सम्पर्क गर्नुहोस्।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"यस यन्त्रमा तपाईँको कार्य प्रोफाइल अब उपलब्ध छैन।"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"नेटवर्कको ट्राफिकको अनुगमन गरिँदै छ"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"थप विवरणहरूको लागि ट्याप गर्नुहोस्"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"थप जान्न ट्याप गर्नुहोस्"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"तपाईंको यन्त्र मेटिनेछ"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"व्यवस्थापक अनुप्रयोगमा कम्पोनेन्टहरू या त हराएको वा भ्रष्ट छन्, र यसैले प्रयोग गर्न सकिँदैन। तपाईंको यन्त्र अब मेटिनेछ। सहयोगको लागि आफ्नो व्यवस्थापकलाई सम्पर्क गर्नुहोस्।"</string>
<string name="me" msgid="6545696007631404292">"मलाई"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनको जुम स्तर र स्थिति नियन्त्रण गर्नुहोस्।"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"इसाराहरू सम्बन्धी कार्य गर्नुहोस्"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ट्याप, स्वाइप गर्न, थिच्न र अन्य इसाराहरू सम्बन्धी कार्य गर्न सक्छ"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फिंगरप्रिन्टका इसाराहरू"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"यन्त्रहरूक‍ो फिंगरप्रिन्ट सेन्सरमा गरिएका इसाराहरू कैद गर्न सक्छ।"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति पट्टिलाई अक्षम वा संशोधित गर्नुहोस्"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"वस्तुस्थिति पट्टी हुन दिनुहोस्"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"तपाईँको हस्तक्षेप बिना नै कल गर्न IMS सेवा प्रयोग गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फोन स्थिति र पहिचान पढ्नुहोस्"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"उपकरणको फोन विशेषताहरूको पहुँच गर्न अनुप्रयोगलाई अनुमति दिन्छ। यस अनुमतिले फोन नम्बर र उपकरणको IDs, कल सक्षम छ कि छैन र कलद्वारा जोडिएको टाढाको नम्बर निर्धारण गर्न अनुमति दिन्छ।"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"प्रणाली मार्फत कल गर्न दिनुहोस्‌"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"कल गर्दाको अनुभवलाई सुधार्न यस अनुप्रयोगलाई प्रणाली मार्फत कलहरू गर्न अनुमति दिन्छ।"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"फोन नम्बर पढ्ने"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"यस अनुप्रयोगलाई यस यन्त्रको फोन नम्बरमाथि पहुँच राख्न दिनुहोस्।"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"मेट्नुहोस्"</string>
<string name="inputMethod" msgid="1653630062304567879">"निवेश विधि"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"पाठ कार्यहरू"</string>
+ <string name="email" msgid="4560673117055050403">"इमेल"</string>
+ <string name="dial" msgid="2275093056198652749">"डायल गर्नुहोस्"</string>
+ <string name="map" msgid="5441053548030107189">"नक्सा"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"भण्डारण ठाउँ सकिँदै छ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"सायद केही प्रणाली कार्यक्रमहरूले काम गर्दैनन्"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"प्रणालीको लागि पर्याप्त भण्डारण छैन। तपाईँसँग २५० मेगा बाइट ठाउँ खाली भएको निश्चित गर्नुहोस् र फेरि सुरु गर्नुहोस्।"</string>
@@ -1147,6 +1154,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"थप विकल्पहरूका लागि ट्याप गर्नुहोस्।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB डिबगिङलाई असक्षम गर्न ट्याप गर्नुहोस्।"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डिबगिङ असक्षम पार्न चयन गर्नुहोस्।"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट लिँदै..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्टलाई साझेदारी गर्दै ..."</string>
@@ -1203,6 +1211,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"स्थापित सत्र पढ्न अनुप्रयोगलाई अनुमति दिनुहोस्। यसले सक्रिय प्याकेज प्रतिष्ठानहरू बारेमा विवरण हेर्ने अनुमति दिन्छ।"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"स्थापना प्याकेजहरू अनुरोध गर्नुहोस्"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"प्याकेजहरूको स्थापना अनुरोध गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"प्याकेजहरू मेटाउने अनुरोध गर्नुहोस्"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"अनुप्रयोगलाई प्याकेजहरू मेटाउने अनुरोध गर्न अनुमति दिन्छ।"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्न सोध्नुहोस्"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"कुनै अनुप्रयोगलाई त्यसका ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्नका लागि अनुमति माग्न दिन्छ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"जुम नियन्त्रणको लागि दुई चोटि ट्याप गर्नुहोस्"</string>
@@ -1429,9 +1439,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"हटाउनुहोस्"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"उपलब्धता सक्षम पार्न दुईवटा औंलाहरूले थिचिरहनुहोस्।"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"पहुँच सक्षम गरिएको।"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुँचयोग्यता रद्द गरियो।"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"पहुँचको सर्टकट सक्रिय छ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"दुबै भोल्युम बटनहरूलाई ३ सेकेन्ड सम्म थिचेर <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय वा निष्क्रिय पार्नुहोस्‌।\n\nतपाईँले सेटिङहरू &gt; पहुँचमा गएर यो सेवा परिवर्तन गर्न सक्नुहुन्छ।"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"सर्टकट निष्क्रिय पार्नुहोस्"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"सक्रिय छोड्नुहोस्"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय पार्‍यो"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई निष्क्रिय पार्‍यो"</string>
<string name="user_switched" msgid="3768006783166984410">"अहिलेको प्रयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>।"</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> मा स्विच गर्दै..."</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"लग आउट गर्दै <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1677,20 +1690,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> लाई असक्षम गरियो"</string>
<string name="conference_call" msgid="3751093130790472426">"सम्मेलन कल"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"उपकरणको वर्णन"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"खेलहरू"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"संगीत तथा अडियो"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"चलचित्र तथा भिडियो"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"तस्बिर तथा छविहरू"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"सामाजिक तथा सञ्चार"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"समाचार तथा पत्रिकाहरू"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"नक्सा तथा नेभिगेसन"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादकत्व"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"यन्त्रको भण्डारण"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-nl-watch/styles_material.xml b/core/res/res/values-nl-watch/styles_material.xml
deleted file mode 100644
index b821347b7634..000000000000
--- a/core/res/res/values-nl-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidaten"</font></string>
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2e556480ea25..f3e02748cd05 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"De beheerapp van het werkprofiel ontbreekt of is beschadigd. Als gevolg hiervan zijn je werkprofiel en alle gerelateerde gegevens verwijderd. Neem voor hulp contact op met je beheerder."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Je werkprofiel is niet meer beschikbaar op dit apparaat."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Netwerkverkeer wordt bijgehouden"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tik voor meer informatie"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tik voor meer informatie"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Je apparaat wordt gewist"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Er ontbreken onderdelen van de beheerapp of de app is beschadigd, waardoor de app niet kan worden gebruikt. Je apparaat wordt nu gewist. Neem voor hulp contact op met je beheerder."</string>
<string name="me" msgid="6545696007631404292">"Ik"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Bedien het zoomniveau en de positionering van het scherm."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gebaren uitvoeren"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Vingerafdrukgebaren"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan gebaren registreren die op de vingerafdruksensor van het apparaat worden getekend."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Hiermee kan de app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"de statusbalk zijn"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Hiermee kan de app de IMS-service gebruiken om te bellen zonder je tussenkomst."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefoonstatus en -identiteit lezen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een oproep actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"oproepen doorschakelen via het systeem"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Hiermee kan de app de bijbehorende oproepen doorschakelen via het systeem om de belfunctionaliteit te verbeteren."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefoonnummer lezen"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Hiermee kan de app toegang krijgen tot het telefoonnummer van het apparaat."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Verwijderen"</string>
<string name="inputMethod" msgid="1653630062304567879">"Invoermethode"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstacties"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Bellen"</string>
+ <string name="map" msgid="5441053548030107189">"Kaart"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Onvoldoende opslagruimte voor het systeem. Zorg ervoor dat je 250 MB vrije ruimte hebt en start opnieuw."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tik voor meer opties."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-foutopsporing uit te schakelen."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Bugrapport genereren…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bugrapport delen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bugrapport delen…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Hiermee wordt een app toegestaan installatiesessies te lezen. Zo kan de app informatie bekijken over actieve pakketinstallaties."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"installatiepakketten aanvragen"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Hiermee kan een app installatie van pakketten aanvragen."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"verwijdering van pakketten aanvragen"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Hiermee kan een app verwijdering van pakketten aanvragen."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"vragen om batterijoptimalisatie te negeren"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Hiermee kan een app toestemming vragen om batterijoptimalisatie voor die app te negeren."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tik twee keer voor zoomregeling"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls u langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Blijf het scherm met twee vingers aanraken om toegankelijkheid in te schakelen."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Toegankelijkheid ingeschakeld."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toegankelijkheid geannuleerd."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"\'Snelle link voor toegankelijkheid\' is AAN"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Schakel <xliff:g id="SERVICE_NAME">%1$s</xliff:g> in of uit door beide volumeknoppen drie seconden ingedrukt te houden.\n\nJe kunt de service wijzigen in Instellingen &gt; Toegankelijkheid."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"\'Snelle link voor toegankelijkheid\' uitschakelen"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ingeschakeld laten"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
<string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Overschakelen naar <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> uitloggen…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonische vergadering"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Knopinfo"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Games"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muziek en audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Films en video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto\'s en afbeeldingen"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociaal en communicatie"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Nieuws en tijdschriften"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Maps en navigatie"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productiviteit"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Apparaatopslag"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-pa-watch/styles_material.xml b/core/res/res/values-pa-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-pa-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index cff0ddb96fa3..788efb892de1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਐਡਮਿਨ ਐਪ ਜਾਂ ਤਾਂ ਲੁਪਤ ਹੈ ਜਾਂ ਕਰਪਟ ਹੈ। ਇੱਕ ਸਿੱਟੇ ਦੇ ਤੌਰ ਤੇ, ਤੁਹਾਡੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਸੰਬੰਧਿਤ ਡੈਟਾ ਮਿਟਾਇਆ ਗਿਆ ਹੈ। ਸਹਾਇਤਾ ਲਈ ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ਤੁਹਾਡੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹੁਣ ਇਸ ਡੀਵਾਈਸ ਤੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"ਹੋਰ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"ਹੋਰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਮਿਟਾਈ ਜਾਏਗੀ"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"ਐਡਮਿਨ ਐਪ ਲੁਪਤ ਕੰਪੋਨੈਂਟ ਜਾਂ ਕਰਪਟ ਹੈ ਅਤੇ ਇਸਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਮਿਟਾ ਦਿੱਤੀ ਜਾਏਗੀ। ਸਹਾਇਤਾ ਲਈ ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="me" msgid="6545696007631404292">"ਮੈਂ"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ਡਿਸਪਲੇ ਦੇ ਜ਼ੂਮ ਪੱਧਰ ਅਤੇ ਸਥਿਤੀ ਨੂੰ ਨਿਯੰਤ੍ਰਿਤ ਕਰੋ।"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ਸੰਕੇਤ ਕਰਦੀ ਹੈ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ਟੈਪ ਕਰ ਸਕਦੀ ਹੈ, ਸਵਾਈਪ ਕਰ ਸਕਦੀ ਹੈ, ਪਿੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਹੋਰ ਸੰਕੇਤ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੰਕੇਤ"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ਡੀਵਾਈਸਾਂ ਦੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ \'ਤੇ ਕੀਤੇ ਗਏ ਸੰਕੇਤਾਂ ਨੂੰ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ਸਥਿਤੀ ਬਾਰ ਅਸਮਰੱਥ ਬਣਾਓ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ਐਪ ਨੂੰ ਸਥਿਤੀ ਬਾਰ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਜਾਂ ਸਿਸਟਮ ਆਈਕਨਾਂ ਨੂੰ ਜੋੜਨ ਅਤੇ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ਸਥਿਤੀ ਪੱਟੀ ਬਣਨ ਦਿਓ"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਨ ਲਈ IMS ਸੇਵਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ਫੋਨ ਸਥਿਤੀ ਅਤੇ ਪਛਾਣ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ਐਪ ਨੂੰ ਡੀਵਾਈਸ ਦੀਆਂ ਫੋਨ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਫ਼ੋਨ ਨੰਬਰ ਅਤੇ ਡੀਵਾਈਸ ID ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ, ਇੱਕ ਕਾਲ ਸਕਿਰਿਆ ਹੈ ਜਾਂ ਨਹੀਂ ਅਤੇ ਰਿਮੋਟ ਨੰਬਰ ਇੱਕ ਕਾਲ ਨਾਲ ਕਨੈਕਟ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ਸਿਸਟਮ ਰਾਹੀਂ ਕਾਲਾਂ ਰੂਟ ਕਰੋ"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"ਕਾਲ ਕਰਨ ਦੇ ਅਨੁਭਵ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਐਪ ਨੂੰ ਇਸਦੀਆਂ ਕਾਲਾਂ ਨੂੰ ਸਿਸਟਮ ਰਾਹੀਂ ਰੂਟ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ਫ਼ੋਨ ਨੰਬਰ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ਡੀਵਾਈਸ ਦੇ ਫ਼ੋਨ ਨੰਬਰ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਲਈ ਐਪ ਨੂੰ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ਟੈਬਲੇਟ ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ਮਿਟਾਓ"</string>
<string name="inputMethod" msgid="1653630062304567879">"ਇਨਪੁਟ ਵਿਧੀ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"ਟੈਕਸਟ ਕਿਰਿਆਵਾਂ"</string>
+ <string name="email" msgid="4560673117055050403">"ਈਮੇਲ ਕਰੋ"</string>
+ <string name="dial" msgid="2275093056198652749">"ਕਾਲ ਕਰੋ"</string>
+ <string name="map" msgid="5441053548030107189">"ਨਕਸ਼ਾ ਖੋਲ੍ਹੋ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ਸਟੋਰੇਜ ਸਪੇਸ ਖ਼ਤਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ਕੁਝ ਸਿਸਟਮ ਫੰਕਸ਼ਨ ਕੰਮ ਨਹੀਂ ਵੀ ਕਰ ਸਕਦੇ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ਸਿਸਟਮ ਲਈ ਪੂਰੀ ਸਟੋਰੇਜ ਨਹੀਂ। ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੇ ਕੋਲ 250MB ਖਾਲੀ ਸਪੇਸ ਹੈ ਅਤੇ ਰੀਸਟਾਰਟ ਕਰੋ।"</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB ਡੀਬੱਗਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਇੰਸਟੌਲ ਸੈਸ਼ਨ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਇਸਨੂੰ ਸਕਿਰਿਆ ਪੈਕੇਜ ਇੰਸਟੌਲੇਸ਼ਨਾਂ ਬਾਰੇ ਵੇਰਵੇ ਦੇਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ਪੈਕੇਜ ਸਥਾਪਿਤ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕਰੋ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ਪੈਕੇਜ ਦੀ ਸਥਾਪਨਾ ਦੀ ਬੇਨਤੀ ਕਰਨ ਲਈ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਅਨੁਮਤੀ ਦਿੰਦਾ ਹੈ"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ਪੈਕੇਜਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਬੇਨਤੀ ਕਰੋ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ਕਿਸੇ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਪੈਕੇਜਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਬੇਨਤੀ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ਬੈਟਰੀ ਸੁਯੋਗਤਾਵਾਂ ਨੂੰ ਅਣਡਿੱਠ ਕਰਨ ਲਈ ਪੁੱਛੋ"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ਕਿਸੇ ਐਪ ਨੂੰ ਉਸ ਵਾਸਤੇ ਬੈਟਰੀ ਸੁਯੋਗਤਾਵਾਂ ਨੂੰ ਅਣਡਿੱਠ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤ ਵਾਸਤੇ ਪੁੱਛਣ ਲਈ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ਜ਼ੂਮ ਕੰਟਰੋਲ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ਹਟਾਓ"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ਕੀ ਵੌਲਿਊਮ ਸਿਫਾਰਿਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ਪਹੁੰਚਯੋਗਤਾ ਨੂੰ ਸਮਰੱਥ ਬਣਾਉਣ ਲਈ ਦੋ ਉਂਗਲਾਂ ਨੂੰ ਹੇਠਾਂ ਹੋਲਡ ਕਰਕੇ ਰੱਖੋ।"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ਪਹੁੰਚਯੋਗਤਾ ਅਸਮਰਥਿਤ।"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ਪਹੁੰਚਯੋਗਤਾ ਰੱਦ ਕੀਤੀ।"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੈ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"ਦੋਵੇਂ ਵੌਲਿਊਮ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਕੇ ਰੱਖਣ ਦੁਆਰਾ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰੋ।\n\nਤੁਸੀਂ ਸੈਟਿੰਗਾਂ &gt; ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਜਾਕੇ ਸੇਵਾ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"ਸ਼ਾਰਟਕੱਟ ਬੰਦ ਕਰੋ"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ਚਾਲੂ ਛੱਡੋ"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ"</string>
<string name="user_switched" msgid="3768006783166984410">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="NAME">%1$s</xliff:g>।"</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> ਤੇ ਸਵਿਚ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਲਾਗ-ਆਉਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ …"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"ਕਾਨਫਰੰਸ ਕਾਲ"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ਟੂਲਟਿਪ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ਗੇਮਾਂ"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"ਸੰਗੀਤ ਅਤੇ ਔਡੀਓ"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ਮੂਵੀਆਂ ਅਤੇ ਵੀਡੀਓ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਚਿੱਤਰ"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"ਸਮਾਜਕ ਅਤੇ ਸੰਚਾਰ"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"ਨਕਸ਼ੇ ਅਤੇ ਆਵਾਗੌਣ"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ਉਤਪਾਦਕਤਾ"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-pl-watch/styles_material.xml b/core/res/res/values-pl-watch/styles_material.xml
deleted file mode 100644
index 384d91c50586..000000000000
--- a/core/res/res/values-pl-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"elementy"</font></string>
-</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 45b48f94f36d..3814f80260d8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Brakuje aplikacji administracyjnej profilu do pracy lub jest ona uszkodzona. Z tego powodu Twój profil do pracy i związane z nim dane zostały usunięte. Skontaktuj się ze swoim administratorem, by uzyskać pomoc."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Twój profil do pracy nie jest już dostępny na tym urządzeniu."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Ruch w sieci jest monitorowany"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Kliknij, aby wyświetlić szczegóły"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Kliknij, by dowiedzieć się więcej"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Twoje urządzenie zostanie wyczyszczone"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Aplikacja administracyjna nie ma wszystkich składników lub jest uszkodzona i nie można jej użyć. Twoje urządzenie zostanie teraz wyczyszczone. Skontaktuj się ze swoim administratorem, aby uzyskać pomoc."</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Regulowanie poziomu i obszaru powiększenia ekranu."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obsługa gestów"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Obsługuje kliknięcia, przesunięcia, ściągnięcia palców i inne gesty."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesty związane z odciskiem palca"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Może przechwytywać gesty wykonywane na czytniku linii papilarnych w urządzeniu."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"działanie jako pasek stanu"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zezwala aplikacji na korzystanie z usługi komunikatora, by nawiązywać połączenia bez Twojego udziału."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"odczytywanie stanu i informacji o telefonie"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pozwala aplikacji na dostęp do funkcji telefonicznych urządzenia. Aplikacja z tym uprawnieniem może odczytać numer telefonu i identyfikator urządzenia, sprawdzić, czy połączenie jest aktywne, oraz poznać numer, z którym jest nawiązane połączenie."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"przekazywanie połączeń przez system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Zezwala aplikacji na przekazywanie połączeń przez system, by poprawić ich jakość."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"odczyt numeru telefonu"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Zezwala aplikacji na dostęp do numeru telefonu urządzenia."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Usuń"</string>
<string name="inputMethod" msgid="1653630062304567879">"Sposób wprowadzania tekstu"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Działania na tekście"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Wybierz numer"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Za mało pamięci w systemie. Upewnij się, że masz 250 MB wolnego miejsca i uruchom urządzenie ponownie."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Kliknij, by wyświetlić więcej opcji."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Kliknij, by wyłączyć debugowanie USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zgłaszam błąd…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Udostępnić raport o błędzie?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Udostępniam raport o błędzie…"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Pozwala aplikacji odczytywać sesje instalacji. Umożliwia to jej na poznanie szczegółów aktywnych instalacji pakietów."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"żądanie instalacji pakietów"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Zezwala aplikacji żądanie instalacji pakietów."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"żądanie usunięcia pakietów"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Zezwala aplikacji na żądanie usunięcia pakietów."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Prośba o ignorowanie optymalizacji wykorzystania baterii"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Zezwala aplikacji na proszenie o uprawnienia do ignorowania optymalizacji wykorzystania baterii w przypadku danej aplikacji."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
@@ -1265,7 +1275,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Odbiornik rzeczywistości wirtualnej"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Odbiornik VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dostawca warunków"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Usługa rankingu powiadomień"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Aby włączyć ułatwienia dostępu, przytrzymaj dwa palce."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Włączono ułatwienia dostępu."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ułatwienia dostępu zostały anulowane."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Skrót ułatwień dostępu jest WŁĄCZONY"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Aby włączyć usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lub ją wyłączyć, przytrzymaj oba przyciski głośności przez 3 sekundy.\n\nUsługę możesz zmienić, klikając Ustawienia &gt; Ułatwienia dostępu."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Wyłącz skrót"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Pozostaw włączony"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Przełączam na użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Wylogowuję użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Połączenie konferencyjne"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Etykietka"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Gry"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzyka i nagrania audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmy i materiały wideo"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Zdjęcia i obrazy"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Społeczności i komunikacja"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Wiadomości i czasopisma"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapy i nawigacja"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktywność"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Pamięć urządzenia"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-pt-rBR-watch/styles_material.xml b/core/res/res/values-pt-rBR-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-pt-rBR-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8b50b0f5f6a8..a7a763f18c10 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Seu perfil de trabalho não está mais disponível neste dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"O tráfego de rede está sendo monitorado"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toque para ver mais detalhes"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toque para saber mais"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"O app para administrador está sem alguns componentes ou foi corrompido e não pode ser usado. Seu dispositivo será limpo agora. Entre em contato com seu administrador para receber assistência."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que o app use o serviço de mensagens instantâneas para fazer chamadas sem sua intervenção."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o app acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o app a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"encaminhar chamadas pelo sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite que o app encaminhe suas chamadas por meio do sistema para melhorar a experiência com chamadas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de telefone"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que o app acesse o número de telefone do dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Discar"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que um app leia sessões de instalação. Isso permite que ele veja detalhes sobre as instalações de pacote ativas."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que um app solicite a instalação de pacotes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar exclusão de pacotes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite que um app solicite a exclusão de pacotes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar que as otimizações de bateria sejam ignoradas"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"O atalho de acessibilidade está ATIVADO"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ative ou desative o <xliff:g id="SERVICE_NAME">%1$s</xliff:g> mantendo os dois botões de volume pressionados por três segundos.\n\nÉ possível alterar o serviço em Config. &gt; Acessibilidade."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desativar atalho"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Deixar ativado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Alternando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jogos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música e áudio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmes e vídeos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos e imagens"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social e comunicação"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-pt-rPT-watch/styles_material.xml b/core/res/res/values-pt-rPT-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-pt-rPT-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 736d6e0253c4..b87fe9e63077 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"A aplicação de administração do perfil de trabalho está em falta ou corrompida. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o seu administrador para obter assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"O seu perfil de trabalho já não está disponível neste dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"O tráfego de rede está a ser monitorizado"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toque para obter mais detalhes"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toque para saber mais"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"O seu dispositivo será apagado"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"A aplicação de administração tem componentes em falta ou corrompidos e não podem ser utilizados. O seu dispositivo será agora apagado. Contacte o seu administrador para obter assistência."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nível de zoom e o posicionamento do ecrã."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"É possível tocar, deslizar rapidamente, juntar os dedos e realizar outros gestos"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode capturar gestos realizados no sensor de impressões digitais do dispositivo."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser apresentada na barra de estado"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que a aplicação utilize o serviço IMS para fazer chamadas sem a sua intervenção."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do telemóvel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"encaminhar chamadas através do sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite que a aplicação encaminhe as respetivas chamadas através do sistema de modo a melhorar a experiência da chamada."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler o número de telefone"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que a aplicação aceda ao número de telefone do dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que o tablet entre em inactividade"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acções de texto"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Marcar"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não existe armazenamento suficiente para o sistema. Certifique-se de que tem 250 MB de espaço livre e reinicie."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toque para obter mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccione para desativar depuração USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"A criar relatório de erro…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que uma aplicação leia sessões de instalação. Isto permite que veja detalhes acerca de instalações de pacotes ativas."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que uma aplicação solicite a instalação de pacotes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar eliminação de pacotes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite que uma aplicação solicite a eliminação de pacotes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pedir para ignorar as otimizações da bateria"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que uma aplicação solicite autorização para ignorar as otimizações da bateria para a mesma."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocar duas vezes para controlar o zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha os dois dedos para ativar a acessibilidade."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"O Atalho de acessibilidade está ATIVADO"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ative ou desative o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ao manter premidos ambos os botões de volume durante 3 segundos.\n\nPode alterar o serviço em Definições &gt; Acessibilidade."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desativar atalho"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Deixar ativado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
<string name="user_switching_message" msgid="2871009331809089783">"A mudar para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"A terminar a sessão de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferência"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Sugestão"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jogos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música e áudio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmes e vídeo"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos e imagens"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social e comunicação"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-pt-watch/styles_material.xml b/core/res/res/values-pt-watch/styles_material.xml
deleted file mode 100644
index 898d2fdcb7e0..000000000000
--- a/core/res/res/values-pt-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidatos"</font></string>
-</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8b50b0f5f6a8..a7a763f18c10 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Seu perfil de trabalho não está mais disponível neste dispositivo."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"O tráfego de rede está sendo monitorado"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Toque para ver mais detalhes"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Toque para saber mais"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"O app para administrador está sem alguns componentes ou foi corrompido e não pode ser usado. Seu dispositivo será limpo agora. Entre em contato com seu administrador para receber assistência."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite que o app use o serviço de mensagens instantâneas para fazer chamadas sem sua intervenção."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o app acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o app a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"encaminhar chamadas pelo sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permite que o app encaminhe suas chamadas por meio do sistema para melhorar a experiência com chamadas."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ler número de telefone"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite que o app acesse o número de telefone do dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
<string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Discar"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que um app leia sessões de instalação. Isso permite que ele veja detalhes sobre as instalações de pacote ativas."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar pacotes de instalação"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite que um app solicite a instalação de pacotes."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar exclusão de pacotes"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite que um app solicite a exclusão de pacotes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar que as otimizações de bateria sejam ignoradas"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"O atalho de acessibilidade está ATIVADO"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ative ou desative o <xliff:g id="SERVICE_NAME">%1$s</xliff:g> mantendo os dois botões de volume pressionados por três segundos.\n\nÉ possível alterar o serviço em Config. &gt; Acessibilidade."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Desativar atalho"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Deixar ativado"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Alternando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jogos"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Música e áudio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmes e vídeos"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotos e imagens"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social e comunicação"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ro-watch/styles_material.xml b/core/res/res/values-ro-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ro-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 43b8f1fc829b..b407ae04157c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Aplicația de administrare a profilului de serviciu lipsește sau este deteriorată. Prin urmare, profilul de serviciu și datele asociate au fost șterse. Pentru asistență, contactați administratorul."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profilul de serviciu nu mai este disponibil pe acest dispozitiv."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Traficul de rețea este monitorizat"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Atingeți pentru mai multe detalii"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Atingeți ca să aflați mai multe"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Datele de pe dispozitiv vor fi șterse"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Aplicația de administrare nu poate fi utilizată, deoarece este deteriorată sau îi lipsesc componente. Datele de pe dispozitiv vor fi șterse. Pentru asistență, contactați administratorul."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlați nivelul de zoom și poziționarea afișajului."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Folosiți gesturi"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Se poate atinge, glisa, ciupi și se pot folosi alte gesturi."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesturi ce implică amprente"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Poate reda gesturile făcute pe senzorul de amprentă al dispozitivelor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"dezactivare sau modificare bare de stare"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"să fie bara de stare"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"citește starea și identitatea telefonului"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcțiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanță conectat printr-un apel."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"să direcționeze apelurile prin intermediul sistemului"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Permiteți aplicației să direcționeze apelurile prin intermediul sistemului pentru a îmbunătăți calitatea apelurilor."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"să citească numărul de telefon"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Permite aplicației să acceseze numărul de telefon al dispozitivului."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Ștergeți"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acțiuni pentru text"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Apelați"</string>
+ <string name="map" msgid="5441053548030107189">"Hartă"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spațiul de stocare aproape ocupat"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
@@ -1161,6 +1168,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Atingeți pentru mai multe opțiuni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Atingeți ca să dezactivați remedierea erorilor prin USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selectați pentru a dezactiva depanarea USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Se creează un raport de eroare…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Trimiteți raportul de eroare?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Se trimite raportul de eroare…"</string>
@@ -1217,6 +1225,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"să solicite pachete de instalare"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite unei aplicații să solicite instalarea pachetelor."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"să solicite ștergerea pachetelor"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite unei aplicații să solicite ștergerea pachetelor."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"să solicite ignorarea optimizărilor bateriei"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite unei aplicații să solicite permisiunea de a ignora optimizările bateriei pentru aplicația respectivă."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Apăsați de două ori pentru a controla mărirea/micșorarea"</string>
@@ -1245,7 +1255,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Schimbați imaginea de fundal"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Instrument de ascultare pentru Realitatea virtuală"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Instrument de ascultare pentru RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Serviciul de clasificare a notificărilor"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
@@ -1444,9 +1454,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminați"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mențineți două degete pe ecran pentru a activa accesibilitatea."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Comanda rapidă de accesibilitate este activată"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Activați sau dezactivați <xliff:g id="SERVICE_NAME">%1$s</xliff:g> apăsând lung ambele butoane de volum timp de 3 secunde.\n\nPuteți schimba serviciul în Setări și Accesibilitate."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Dezactivați comanda rapidă"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Mențineți-o activată"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Se comută la <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Se deconectează utilizatorul <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1702,20 +1715,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferință telefonică"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Balon explicativ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Jocuri"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzică și audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filme și videoclipuri"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotografii și imagini"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Rețele sociale și comunicare"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Știri și reviste"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Hărți și navigare"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivitate"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Stocare pe dispozitiv"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ru-watch/styles_material.xml b/core/res/res/values-ru-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-ru-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index cd6c871f0c65..2e2bd0be581e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Приложение Admin в рабочем профиле отсутствует или повреждено. Из-за этого рабочий профиль и связанные с ним данные были удалены. Если у вас возникли вопросы, обратитесь к администратору."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Ваш рабочий профиль больше не доступен на этом устройстве."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Включен мониторинг сетевого трафика"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Нажмите, чтобы показать подробную информацию"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Подробнее…"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Все данные с устройства будут удалены"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Приложение Admin нельзя использовать, так как оно отсутствует или повреждено. С устройства будут удалены все данные. Если у вас возникли вопросы, обратитесь к администратору."</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управлять позиционированием и размером изображения на экране."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жесты"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Может выполнять жесты нажатия, пролистывания, масштабирования и т. д."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жесты для отпечатков пальцев"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Сохраняет жесты, выполненные на сканере отпечатков пальцев."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Отключение/изменение строки состояния"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Приложение сможет отключать строку состояния, а также добавлять и удалять системные значки."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Замена строки состояния"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Позволяет приложению совершать звонки с помощью службы IMS без вашего вмешательства."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Получение данных о статусе телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Приложение получит доступ к функциям телефона на устройстве. Кроме того, оно сможет определять номера телефонов и серийные номера моделей, состояние активности вызова, а также удаленные номера, с которыми установлено соединение."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"перенаправлять звонки в системе"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Приложение сможет перенаправлять звонки в системе с целью улучшения качества связи."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"Чтение номера телефона"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Приложение получит доступ к телефонному номеру устройства."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Отключение спящего режима"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Удалить"</string>
<string name="inputMethod" msgid="1653630062304567879">"Способ ввода"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Операции с текстом"</string>
+ <string name="email" msgid="4560673117055050403">"Письмо"</string>
+ <string name="dial" msgid="2275093056198652749">"Вызов"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Недостаточно памяти"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые функции могут не работать"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостаточно свободного места для системы. Освободите не менее 250 МБ дискового пространства и перезапустите устройство."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Нажмите, чтобы показать дополнительные параметры."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Нажмите, чтобы отключить отладку по USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Нажмите, чтобы отключить отладку USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Подготовка отчета об ошибке"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Разрешить доступ к информации об ошибке?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Чтение данных текущих сеансов установки пакетов."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"Запрос пакетов установки"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Приложение сможет запрашивать разрешения на установку пакетов."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"запросы на удаление пакетов"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Приложение сможет запрашивать разрешения на удаление пакетов."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Без ограничения расхода батареи"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Разрешает приложению игнорировать ограничение на расход заряда батареи."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Нажмите дважды для изменения масштаба"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Удалить"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Чтобы включить специальные возможности, удерживайте пальцы на экране."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Специальные возможности включены."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Специальные возможности не будут включены."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Быстрое включение активировано"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Чтобы включить или отключить <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, нажмите обе кнопки громкости и удерживайте в течение трех секунд.\n\nЧтобы изменить сервис, откройте \"Настройки &gt; Специальные возможности\"."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Деактивировать быстрое включение"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Оставить включенным"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> включен"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> отключен"</string>
<string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Смена профиля на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Выход из аккаунта <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виджет <xliff:g id="LABEL">%1$s</xliff:g> отключен"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференц-связь"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Игры"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музыка и аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Видео"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Изображения"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Общение"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Новости и журналы"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карты и навигация"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Работа"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Хранилище устройства"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-si-watch/styles_material.xml b/core/res/res/values-si-watch/styles_material.xml
deleted file mode 100644
index 37b4afe842f6..000000000000
--- a/core/res/res/values-si-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"අපේක්ෂකයන්"</font></string>
-</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 031d9d02fd2d..74408884b46b 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"කාර්යාල පැතිකඩ පාලක යෙදුම නොමැති හෝ දූෂණය වී ඇත. ප්‍රතිඵලයක් ලෙස ඔබගේ කාර්යාල පැතිකඩ සහ අදාළ දත්ත මකා දමා ඇත. සහය සඳහා ඔබගේ පරිපාලකයා සම්බන්ධ කර ගන්න."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ඔබේ කාර්යාල පැතිකඩ මෙම උපාංගය මත තවදුරටත් ලබා ගැනීමට නොහැකිය."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"ජාල තදබදය නිරීක්ෂණය කරමින් පවතී"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"වැඩි විස්තර සඳහා තට්ටු කරන්න"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"තව දැන ගැනීමට තට්ටු කරන්න"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"යෙදුමේ කොටස් නොමැති හෝ දූෂණය වී ඇති නිසා, භාවිතා කළ නොහැක. ඔබගේ උපාංගය දැන් මකා දැමෙනු ඇත. සහය සඳහා ඔබගේ පරිපාලකයා සම්බන්ධ කරගන්න."</string>
<string name="me" msgid="6545696007631404292">"මම"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"සංදර්ශනයේ විශාලන මට්ටම සහ පිහිටීම පාලනය කරන්න."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"අභින සිදු කරන්න"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"තට්ටු කිරීමට, ස්වයිප් කිරීමට, පින්ච් කිරීමට, සහ වෙනත් අභින සිදු කිරීමට හැකිය."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ඇඟිලි සලකුණු ඉංගිත"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"උපාංග ඇඟිලි සලකුණු සංවේදකය මත සිදු කරන ඉංගිත ග්‍රහණය කළ හැකිය."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"තත්ව තීරුව අබල කරන්න හෝ වෙනස් කරන්න"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"තත්ව තීරුව අක්‍රිය කිරීමට හෝ පද්ධති නිරූපක එකතු හෝ ඉවත් කිරීමට යෙදුමට අවසර දේ."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"තත්ත්ව තීරුව බවට පත්වීම"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ඔබේ මැදිහත්වීමකින් තොරව ඇමතුම් සිදු කිරීමට IMS සේවාව භාවිතයට යෙදුමට ඉඩ දෙන්න."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"දුරකථනයේ තත්වය සහ අනන්‍යතාවය කියවීම"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"උපාංගයේ දුරකථන විශේෂාංග වෙත ප්‍රවේශයට යෙදුමට ඉඩ දෙයි. ඇමතුම සක්‍රිය වුවත්, සහ ඇමතුමකින් දුරස්ථ අංකය සම්බන්ධ වුවත් දුරකථන අංකය සහ උපාංග ID හඳුනා ගැනීමට මෙම අවසරය යෙදුමට ඉඩ දෙයි."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"පද්ධතිය හරහා ඇමතුම් මාර්ගගත කරන්න"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"ඇමතුම් අත්දැකීම වැඩිදියුණු කිරීම සඳහා යෙදුමට පද්ධතිය හරහා එහි ඇමතුම් මාර්ගගත කිරීමට ඉඩ දෙයි."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"දුරකථන අංකය කියවන්න"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"උපාංගයේ දුරකථන අංකය වෙත පිවිසීමට යෙදුමට ඉඩ දෙන්න."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ටැබ්ලටය නින්දෙන් වැළක්වීම"</string>
@@ -949,6 +953,9 @@
<string name="deleteText" msgid="6979668428458199034">"මකන්න"</string>
<string name="inputMethod" msgid="1653630062304567879">"ආදාන ක්‍රමය"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"පෙළ ක්‍රියාවන්"</string>
+ <string name="email" msgid="4560673117055050403">"ඊ-තැපෑල"</string>
+ <string name="dial" msgid="2275093056198652749">"අමතන්න"</string>
+ <string name="map" msgid="5441053548030107189">"සිතියම"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ආචයනය ඉඩ ප්‍රමාණය අඩු වී ඇත"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"සමහර පද්ධති කාර්යයන් ක්‍රියා නොකරනු ඇත"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"පද්ධතිය සඳහා ප්‍රමාණවත් ඉඩ නොමැත. ඔබට 250MB නිදහස් ඉඩක් තිබෙන ඔබට තිබෙන බව සහතික කරගෙන නැවත උත්සාහ කරන්න."</string>
@@ -1143,6 +1150,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"තවත් විකල්ප සඳහා තට්ටු කරන්න."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB නිදොස්කරණය අබල කිරීමට තට්ටු කරන්න."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB නිදොස්කරණය අබල කිරීමට තෝරන්න."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"දෝෂ වාර්තාව බෙදා ගන්නද?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"දෝෂ වාර්තාවක් බෙදා ගනිමින්..."</string>
@@ -1199,6 +1207,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ස්ථාපන සැසිය කියවීමට යෙදුමට ඉඩ දෙන්න. සක්‍රිය පැකේජ ස්ථාපනය පිළිබඳ විස්තර බැලීමට එයට මෙයින් ඉඩ දෙයි."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ස්ථාපන පැකේජ ඉල්ලීම"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ස්ථාපන පැකේජ ඉල්ලීමට යෙදුමකට අවසර දීම."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"පැකේජ මැකීමට ඉල්ලීම"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ස්ථාපන පැකේජ මැකීමට යෙදුමකට ඉඩ දීම."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"බැටරි ප්‍රශස්තකරණ නොසලකා හැරීමට ඉල්ලන්න"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"යෙදුමකට එම යෙදුම සඳහා බැටරි ප්‍රශස්තකරණ නොසලකා හැරීමට අවසර ඉල්ලීමට ඉඩ දෙයි."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"විශාලන පාලක සඳහා දෙවතාවක් තට්ටු කරන්න"</string>
@@ -1425,9 +1435,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ඉවත් කරන්න"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ප්‍රවේශ්‍යතාවය සබල කිරීමට ඇඟිලි දෙකක් පහළට රඳවා සිටින්න."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ප‍්‍රවේශ්‍යතාව සබල කරන ලදි."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ප‍්‍රවේශ්‍යතාව අවලංගු කර ඇත."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ප්‍රවේශ්‍යතා කෙටි මග ක්‍රියාත්මකයි"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් අල්ලාගෙන සිටීමෙන් <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාත්මක හෝ ක්‍රියාවිරහිත කරන්න.\n\nඔබට සැකසීම් &gt; ප්‍රවේශ්‍යතාව තුළ සේවාව වෙනස් කළ හැකිය."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"කෙටි මග ක්‍රියාවිරහිත කරන්න"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"සබල කර ඇත"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාත්මක කරන ලදී"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාවිරහිත කරන ලදී"</string>
<string name="user_switched" msgid="3768006783166984410">"දැනට සිටින පරිශීලකයා <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> වෙත මාරු කරමින්…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> වරමින්…"</string>
@@ -1673,20 +1686,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"අබල කළ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"සම්මන්ත්‍රණ ඇමතුම"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"මෙවලම් ඉඟිය"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"ක්‍රීඩා"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"සංගීතය සහ ශ්‍රව්‍ය"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"චිත්‍රපට සහ වීඩියෝ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ඡායාරූප සහ රූප"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"සමාජ සහ සන්නිවේදන"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"පුවත් සහ සඟරා"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"සිතියම් සහ සංචලනය"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ඵලදායිතාව"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"උපාංග ගබඩාව"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sk-watch/styles_material.xml b/core/res/res/values-sk-watch/styles_material.xml
deleted file mode 100644
index 5b604e837551..000000000000
--- a/core/res/res/values-sk-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidáti"</font></string>
-</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e483d397ad2a..47716dad7c50 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Správcovská aplikácia pracovného profilu buď chýba, alebo je poškodená. Z toho dôvodu boli váš pracovný profil a s ním súvisiace údaje odstránené. Ak potrebujete pomoc, kontaktujte svojho správcu."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Váš pracovný profil už nie je na tomto zariadení dostupný."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Sleduje sa sieťová premávka."</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Ďalšie podrobnosti získate klepnutím"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Klepnutím získate ďalšie informácie"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Vaše zariadenie bude vymazané"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"V správcovskej aplikácii chýbajú komponenty alebo je poškodená, a preto sa nedá použiť. Vaše zariadenie bude vymazané. Ak potrebujete pomoc, kontaktujte svojho správcu."</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ovládajte úroveň priblíženia/oddialenia obrazovky a umiestnenie"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gestá"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Je možné použiť klepnutie, prejdenie, stiahnutie prstami a ďalšie gestá."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestá odtlačkov prstov"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dokáže zaznamenať gestá vykonané na senzore odtlačkov prstov."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zakázanie alebo zmeny stavového riadka"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikácii vypnúť stavový riadok alebo pridať a odstrániť systémové ikony."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vydávanie sa za stavový riadok"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Umožňuje aplikácii používať službu okamžitých správ (IMS) na volanie bez intervencie používateľa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čítať stav a identitu telefónu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikácii pristupovať k telefónnym funkciám zariadenia. Aplikácia s týmto povolením môže určiť telefónne číslo a ID zariadenia, či práve prebieha hovor, a vzdialené číslo, s ktorým je prostredníctvom hovoru nadviazané spojenie."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"presmerovanie hovorov cez systém"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Umožňuje aplikácii presmerovať hovory cez systém na účely zlepšenia kvality hovorov."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"čítanie telefónneho čísla"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Umožňuje aplikácii pristupovať k telefónnemu číslu daného zariadenia."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Odstrániť"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metóda vstupu"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Operácie s textom"</string>
+ <string name="email" msgid="4560673117055050403">"E-mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Vytočiť"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V úložisku nie je dostatok voľného miesta pre systém. Zaistite, aby ste mali 250 MB voľného miesta a zariadenie reštartujte."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte ďalšie možnosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladenie cez USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Výberom zakážete ladenie USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Preberá sa hlásenie chyby…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Toto povolenie umožňuje aplikácii čítať relácie inštalácií a zobraziť tak podrobnosti o aktívnych inštaláciách balíkov."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"odosielanie žiadostí o inštaláciu balíkov"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Umožňuje aplikácii vyžiadať inštaláciu balíkov."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"vyžiadať odstránenie balíkov"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Umožňuje aplikácii vyžiadať odstránenie balíkov."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"požiadať o ignorovanie optimalizácií výdrže batérie"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Umožňuje aplikácii požiadať o povolenie ignorovať optimalizácie výdrže batérie pre danú aplikáciu."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dvojitým klepnutím môžete ovládať priblíženie"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Zjednodušenie ovládania povolíte dlhým stlačením dvoma prstami."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Zjednodušenie ovládania je povolené."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Zjednodušenie ovládania bolo zrušené."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Skratka dostupnosti je ZAPNUTÁ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zapnete a vypnete podržaním oboch tlačidiel hlasitosti na tri sekundy.\n\nSlužbu môžete zmeniť v časti Nastavenia &gt; Dostupnosť."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Vypnúť skratku"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Ponechať zapnutú"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Prepína sa na účet <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Prebieha odhlásenie používateľa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenčný hovor"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Popis"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Hry"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Hudba a zvuk"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmy a videá"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotky a obrázky"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sociálne siete a komunikácia"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Noviny a časopisy"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mapy a navigácia"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivita"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Úložisko zariadenia"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sl-watch/styles_material.xml b/core/res/res/values-sl-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-sl-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b74875af2fcf..13102b562c80 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Skrbniška aplikacija delovnega profila manjka ali pa je poškodovana, zaradi česar je bil delovni profil s povezanimi podatki izbrisan. Za pomoč se obrnite na skrbnika."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Vaš delovni profil ni več na voljo v tej napravi."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Omrežni promet je nadzorovan"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Dotaknite se za več podrobnosti"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Dotaknite se, če želite izvedeti več"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Podatki v napravi bodo izbrisani"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Skrbniška aplikacija je nepopolna ali poškodovana, zato je ni mogoče uporabiti. Podatki v napravi bodo izbrisani. Za pomoč se obrnite na skrbnika."</string>
<string name="me" msgid="6545696007631404292">"Jaz"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Nadziranje stopnje povečave in položaja prikaza."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvajanje potez"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mogoče je izvajanje dotikov, vlečenja, primikanja in razmikanja prstov ter drugih potez."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Poteze po tipalu prstnih odtisov"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Prepoznava poteze, narejene po tipalu prstnih odtisov naprave."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogočanje ali spreminjanje vrstice stanja"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikacijam omogoča onemogočenje vrstice stanja ali dodajanje in odstranjevanje ikon sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"postane vrstica stanja"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Aplikaciji dovoljuje uporabo storitev IMS za opravljanje klicev brez vašega posredovanja."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"branje stanja in identitete telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogoča dostop do funkcij telefona v napravi. S tem dovoljenjem lahko aplikacija določi telefonsko številko in ID-je naprave, določi lahko tudi, ali je klic aktiven, in oddaljeno številko, s katero je klic povezan."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"Usmeri klice prek sistema"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Dovoli, da aplikacija usmeri klice prek sistema, da se tako izboljša izkušnja klicanja."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"branje telefonske številke"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Aplikaciji dovoljuje dostop do telefonske številke naprave."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
<string name="inputMethod" msgid="1653630062304567879">"Način vnosa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Besedilna dejanja"</string>
+ <string name="email" msgid="4560673117055050403">"E-pošta"</string>
+ <string name="dial" msgid="2275093056198652749">"Kliči"</string>
+ <string name="map" msgid="5441053548030107189">"Zemljevid"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V shrambi ni dovolj prostora za sistem. Sprostite 250 MB prostora in znova zaženite napravo."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Dotaknite se za več možnosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje napak prek USB je povezano"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Dotaknite se za izklop odpravljanja napak prek USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zajemanje poročila o napakah …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite poslati poročilo o napakah?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Pošiljanje poročila o napakah …"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Aplikaciji omogoča branje sej namestitev. Tako lahko bere podrobnosti o aktivnih namestitvah paketov."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketov za namestitev"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Aplikaciji omogoča zahtevanje namestitve paketov."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"Zahteva za brisanje paketov"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Omogoča aplikaciji, da zahteva brisanje paketov."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"Dovoljenje za prezrtje optimizacij akumulatorja"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Aplikaciji dovoljuje, da vpraša za dovoljenje, ali naj prezre optimizacije akumulatorja."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tapnite dvakrat za nadzor povečave/pomanjšave"</string>
@@ -1265,7 +1275,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Poslušalec za navidezno resničnost"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Poslušalec za VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ponudnik pogojev"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Storitev za določanje stopenj pomembnosti obvestil"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Če želite omogočiti pripomočke za ljudi s posebnimi potrebami, na zaslonu pridržite z dvema prstoma."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pripomočki za ljudi s posebnimi potrebami so omogočeni."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Omogočanje pripomočkov za ljudi s posebnimi potrebami preklicano."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopljena"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Če želite vklopiti ali izklopiti <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, za tri sekunde pridržite oba gumba za glasnost.\n\nStoritev lahko spremenite v meniju Nastavitve &gt; Funkcije za ljudi s posebnimi potrebami."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Izklopi bližnjico"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Pusti vklopljeno"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Preklop na uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Odjavljanje uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenčni klic"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Opis orodja"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Igre"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Glasba in zvok"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmi in videoposnetki"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotografije in slike"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Druženje in komuniciranje"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Novice in revije"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Zemljevidi in navigacija"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Storilnost"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Shramba naprave"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sq-watch/styles_material.xml b/core/res/res/values-sq-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-sq-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 536c60f49761..fd76f7d9e847 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Aplikacioni i administratorit të profilit të punës mungon ose është dëmtuar. Si rezultat i kësaj, profili yt i punës dhe të dhënat përkatëse janë fshirë. Kontakto administratorin tënd për ndihmë."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profili yt i punës nuk është më i disponueshëm në këtë pajisje."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Trafiku i rrjetit po monitorohet"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Trokit për më shumë detaje"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Trokit për të mësuar më shumë"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Pajisja do të spastrohet"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Aplikacionit të administratorit i mungojnë përbërësit ose është dëmtuar dhe nuk mund të përdoret. Pajisja jote tani do të fshihet. Kontakto administratorin tënd për ndihmë."</string>
<string name="me" msgid="6545696007631404292">"Unë"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollo nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kryen gjeste"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gjestet e gjurmës së gishtit"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Mund të kapë gjestet e kryera në sensorin e gjurmës së gishtit të pajisjeve."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"çaktivizo ose modifiko shiritin e statusit"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"të bëhet shiriti i statusit"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Lejon aplikacionin të përdorë shërbimin IMS për të kryer telefonata pa ndërhyrjen tënde."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lexo statusin e telefonit dhe identitetin"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lejon aplikacionin të hyjë në funksionet telefonike të pajisjes. Kjo leje i mundëson aplikacionit të përcaktojë numrin e telefonit dhe ID-të e pajisjes, nëse një telefonatë është aktive apo nëse numri në distancë është i lidhur me një telefonatë."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"kalon telefonatat përmes sistemit"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Lejon që aplikacioni të kalojë telefonatat përmes sistemit për të përmirësuar përvojën e telefonatës."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"lexo numrin e telefonit"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Lejon që aplikacioni të ketë qasje te numri i telefonit i pajisjes."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"parandalo kalimin e tabletit në fjetje"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Fshi"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metoda e hyrjes"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Veprimet e tekstit"</string>
+ <string name="email" msgid="4560673117055050403">"Dërgo mail"</string>
+ <string name="dial" msgid="2275093056198652749">"Formo numrin"</string>
+ <string name="map" msgid="5441053548030107189">"Harta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Hapësira ruajtëse po mbaron"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Disa funksione të sistemit mund të mos punojnë"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nuk ka hapësirë të mjaftueshme ruajtjeje për sistemin. Sigurohu që të kesh 250 MB hapësirë të lirë dhe pastaj të rifillosh."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Trokit për më shumë opsione."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Trokit për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Po merret raporti i defekteve në kod…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Të ndahet raporti i defektit në kod?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Po ndan raportin e defekteve në kod..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Lejon një aplikacion të lexojë sesionet e instalimit. Kjo e lejon atë të shohë detaje rreth instalimeve të paketave aktive."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"kërko paketat e instalimit"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Lejon që një aplikacion të kërkojë instalimin e paketave."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"kërko fshirjen e paketave"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Lejon që një aplikacion të kërkojë fshirjen e paketave."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"kërko të shpërfillësh optimizimet e baterisë"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Lejon që një aplikacion të kërkojë leje për të shpërfillur optimizimet e baterisë për atë aplikacion."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trokit dy herë për të kontrolluar zmadhimin"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hiq"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mbaji shtypur dy gishtat për të aktivizuar qasjen."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Qasja u aktivizua."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Qasja u anulua."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Shkurtorja e qasshmërisë është AKTIVE"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Aktivizo ose çaktivizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g> duke mbajtur poshtë dy butonat e volumit për 3 sekonda.\n\nMund ta ndryshosh shërbimin te Cilësimet &gt; Qasshmëria."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Çaktivizo shkurtoren"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Lëre aktive"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Emri i përdoruesit aktual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"Po kalon në <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> po del…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonatë konferencë"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Këshilla për veglën"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Lojëra"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muzikë dhe audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filma dhe video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foto dhe imazhe"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Rrjete sociale dhe komunikim"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Lajme dhe revista"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Harta dhe navigim"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Hapësira ruajtëse e pajisjes"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sr-watch/styles_material.xml b/core/res/res/values-sr-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-sr-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c7d8fdff908c..54b0fae86fe5 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -185,7 +185,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Администраторска апликација пословног профила недостаје или је оштећена. Због тога су ваш пословни профил и повезани подаци избрисани. Обратите се администратору за помоћ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Профил за Work више није доступан на овом уређају."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Мрежни саобраћај се прати"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Додирните за више детаља"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Додирните да бисте сазнали више"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Уређај ће бити обрисан"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Администраторској апликацији недостају неке компоненте или је оштећена и не може да се користи. Уређај ће сада бити обрисан. Обратите се администратору за помоћ."</string>
<string name="me" msgid="6545696007631404292">"Ја"</string>
@@ -281,6 +281,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управља нивоом зумирања приказа и одређивањем положаја."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Обављање покрета"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да додирује, листа, скупља приказ и обавља друге покрете."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Покрети за отисак прста"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да региструје покрете на сензору за отисак прста на уређају."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"онемогућавање или измена статусне траке"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозвољава апликацији да онемогући статусну траку или да додаје и уклања системске иконе."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"функционисање као статусна трака"</string>
@@ -385,6 +387,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дозвољава апликацији да користи услугу размене тренутних порука да би упућивала позиве без ваше интервенције."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читање статуса и идентитета телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозвољава апликацији да приступа функцијама телефона на уређају. Ова дозвола омогућава апликацији да утврди број телефона и ИД-ове уређаја, затим да ли је позив активан, као и број даљинског уређаја са којим је успостављен позив."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"преусмеравање позива преко система"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Дозвољава апликацији да преусмерава позиве преко система да би побољшала доживљај позивања."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"читање броја телефона"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Дозвољава апликацији да приступа броју телефона на уређају."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречавање преласка таблета у стање спавања"</string>
@@ -967,6 +971,9 @@
<string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метод уноса"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
+ <string name="email" msgid="4560673117055050403">"Пошаљи имејл"</string>
+ <string name="dial" msgid="2275093056198652749">"Позови"</string>
+ <string name="map" msgid="5441053548030107189">"Мапа"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
@@ -1161,6 +1168,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Додирните за још опција."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Извештај о грешци се генерише…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
@@ -1217,6 +1225,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дозвољава апликацији да чита сесије инсталирања. То јој дозвољава да види детаље о активним инсталацијама пакета."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"захтевање пакета за инсталирање"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Омогућава да апликација захтева инсталацију пакета."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"захтевање брисања пакета"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Омогућава да апликација захтева брисање пакета."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"тражење дозволе за игнорисање оптимизација батерије"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Дозвољава апликацији да тражи дозволу за игнорисање оптимизација батерије за ту апликацију."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Додирните двапут за контролу зумирања"</string>
@@ -1444,9 +1454,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Држите са два прста да бисте омогућили приступачност."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Приступачност је омогућена."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Приступачност је отказана."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Пречица за приступачност је УКЉУЧЕНА"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Укључите или искључите услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> тако што ћете истовремено задржати оба дугмета за јачину звука 3 секунде.\n\nМожете да промените услугу у одељку Подешавања &gt; Приступачност."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Искључи пречицу"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Остави укључено"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Пречица за приступачност је укључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Пречица за приступачност је искључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Пребацивање на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Одјављује се <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1702,20 +1715,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виџет <xliff:g id="LABEL">%1$s</xliff:g> је онемогућен"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференцијски позив"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Објашњење"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Игре"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музика и аудио"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Филмови и видео"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Слике"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Друштвене мреже и комуникација"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Новости и часописи"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Мапе и навигација"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивност"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Меморијски простор уређаја"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sv-watch/styles_material.xml b/core/res/res/values-sv-watch/styles_material.xml
deleted file mode 100644
index f2ab18ad6908..000000000000
--- a/core/res/res/values-sv-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"kandidater"</font></string>
-</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f5e3445eef5a..e010b96f4fee 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Administratörsappen för jobbprofilen saknas eller är skadad. Det innebär att jobbprofilen och all relaterad data har raderats. Kontakta administratören om du vill ha hjälp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Din jobbprofil är inte längre tillgänglig på den här enheten."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Nätverkstrafiken övervakas"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tryck om du vill ha mer information"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Tryck här om du vill läsa mer"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Enheten kommer att rensas"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administratörsappen saknar delar eller är skadad och kan inte användas. Enheten kommer nu att rensas. Kontakta administratören om du behöver hjälp."</string>
<string name="me" msgid="6545696007631404292">"Jag"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Styr skärmens zoomnivå och positionering."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Göra rörelser"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trycka, svepa, nypa och göra andra rörelser."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingeravtrycksrörelser"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan registrera rörelser som utförs med hjälp av enhetens fingeravtryckssensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tillåter att appen inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"visas i statusfältet"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Tillåter att appen använder tjänsten för snabbmeddelanden för att ringa samtal utan åtgärd från dig."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"läsa telefonens status och identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillåter att appen kommer åt enhetens telefonfunktioner. Med den här behörigheten tillåts appen att identifiera mobilens telefonnummer och enhets-ID, om ett samtal pågår och vilket nummer samtalet är kopplat till."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"dirigera samtal via systemet"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Appen tillåts att dirigera samtal via systemet för att förbättra samtalsupplevelsen."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"läsa telefonnumret"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ger appen åtkomst till mobilnumret på enheten."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"förhindra att surfplattan går in i viloläge"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Ta bort"</string>
<string name="inputMethod" msgid="1653630062304567879">"Indatametod"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Textåtgärder"</string>
+ <string name="email" msgid="4560673117055050403">"Skicka e-post"</string>
+ <string name="dial" msgid="2275093056198652749">"Ring"</string>
+ <string name="map" msgid="5441053548030107189">"Karta"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det finns inte tillräckligt med utrymme för systemet. Kontrollera att du har ett lagringsutrymme på minst 250 MB och starta om."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Tryck för fler alternativ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj att inaktivera USB-felsökning."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Tillåt appen att läsa installationssessioner. Det ger den tillgång till uppgifter om aktiva paketinstallationer."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"begära installationspaket"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Tillåter att en app begär paketinstallation."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"begär paketborttagning"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Tillåter att en app begär paketborttagning."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"får be om tillstånd att ignorera batterioptimering"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Appen får be om tillstånd att ignorera batterioptimering."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyssnare för virtuell verklighet"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyssnare för VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Leverantör"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Rankningstjänst för aviseringar"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsätt trycka med två fingrar om du vill aktivera tillgänglighetsläget."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Tillgänglighetsläget har aktiverats."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Byte till tillgänglighetsläge avbrutet."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Aktivera tillgänglighet snabbt är PÅ"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Aktivera eller inaktivera <xliff:g id="SERVICE_NAME">%1$s</xliff:g> genom att hålla ned båda volymknapparna i tre sekunder.\n\nDu kan ändra tjänsten i Inställningar och Tillgänglighet."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Inaktivera Aktivera tillgänglighet snabbt"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Låt den vara aktiverad"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
<string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Byter till <xliff:g id="NAME">%1$s</xliff:g> …"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Loggar ut <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenssamtal"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Beskrivning"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Spel"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musik och ljud"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Film och video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Foton och bilder"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Socialt och kommunikation"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Nyheter och tidskrifter"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Kartor och navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Enhetens lagringsutrymme"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-sw-watch/styles_material.xml b/core/res/res/values-sw-watch/styles_material.xml
deleted file mode 100644
index 01392b243c57..000000000000
--- a/core/res/res/values-sw-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"yanayopendekezwa"</font></string>
-</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1c91e9985182..c363a2216fac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -181,7 +181,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Programu ya msimamizi wa wasifu wa kazini imepotea au ina hitilafu. Kwa sbabu hiyo, wasifu wako wa kazini na data husika imefutwa. Wasiliana na msimamizi wako kwa usaidizi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Wasifu wako wa kazini haupatikani tena kwenye kifaa hiki."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Trafiki ya mtandao inachunguzwa"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Gonga ili upate maelezo zaidi"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Gonga ili upate maelezo zaidi"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Data iliyomo kwenye kifaa chako itafutwa"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Programu ya msimamizi inakosa vipengele au ina hitilafu, na haiwezi kutumika. Data iliyomo kwenye kifaa chako sasa itafutwa. Wasiliana na msimamizi wako kwa usaidizi."</string>
<string name="me" msgid="6545696007631404292">"Mimi"</string>
@@ -276,6 +276,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Dhibiti kiwango cha kukuza na nafasi cha onyesho."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Tekeleza ishara"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Unaweza kugonga, kutelezesha kidole, kubana na kutekeleza ishara zingine."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Ishara za alama ya kidole"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Inaweza kurekodi ishara zinazotekelezwa kwenye kitambua alama ya kidole."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zima au rekebisha mwambaa hali"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa ikoni za mfumo."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"kuwa sehemu ya arifa"</string>
@@ -380,6 +382,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Huruhusu programu kutumia huduma ya IMS kupiga simu bila udhibiti wako."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Huruhusu programu kufikia vipengele vya simu vilivyo kwenye kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama kuna simu inayopigwa, na nambari ya mbali iliyounganishwa kwenye simu."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"elekeza simu kupitia mfumo"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Huruhusu programu kuelekeza simu zake kupitia mfumo ili kuboresha hali ya kupiga simu."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"kusoma nambari ya simu"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Inaruhusu programu kufikia nambari ya simu ya kifaa."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
@@ -945,6 +949,9 @@
<string name="deleteText" msgid="6979668428458199034">"Futa"</string>
<string name="inputMethod" msgid="1653630062304567879">"Mbinu ya uingizaji"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string>
+ <string name="email" msgid="4560673117055050403">"Barua pepe"</string>
+ <string name="dial" msgid="2275093056198652749">"Piga simu"</string>
+ <string name="map" msgid="5441053548030107189">"Ramani"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhafadhi inakwisha"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Hifadhi haitoshi kwa ajili ya mfumo. Hakikisha una MB 250 za nafasi ya hifadhi isiyotumika na uanzishe upya."</string>
@@ -1139,6 +1146,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Gonga ili upate chaguo zaidi."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Gonga ili uzime utatuaji wa USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chagua ili kulemaza utatuaji USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Inatayarisha ripoti ya hitilafu…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Ungependa kushiriki ripoti ya hitilafu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Inashiriki ripoti ya hitilafu…"</string>
@@ -1195,6 +1203,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Huruhusu programu kusoma vipindi vya kusanikisha. Hii huiruhusu kuona maelezo kuhusu usanikishaji wa programu unaoendelea."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"omba ruhusa ya kusakinisha vifurushi"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Huruhusu programu kuomba idhini ya kusakinisha vifurushi."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"omba idhini ya kufuta vifurushi"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Huruhusu programu kuomba idhini ya kufuta vifurushi."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"omba kupuuza uimarishji wa betri"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Huruhusu programu kuomba ruhusa ya kupuuza uimarishaji wa betri katika programu yako."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Gonga mara mbili kwa udhibiti wa kuza"</string>
@@ -1223,7 +1233,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Kisikilizaji cha Uhalisia Pepe"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Kisikilizaji cha VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa masharti"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Huduma ya kupanga arifa"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
@@ -1421,9 +1431,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ondoa"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Endelea kushikilia chini kwa vidole vyako viwili ili kuwezesha ufikivu."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Ufikivu umewezeshwa."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ufikivu umeghairiwa."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Umewasha njia ya mkato ya Zana za walio na matatizo ya kuona au kusikia"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Washa au uzime <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kwa kushikilia vitufe vyote viwili vya sauti kwa sekunde 3.\n\nUnaweza kubadilisha huduma hii katika Mipangilio &gt; Zana za walio na matatizo ya kuona au kusikia."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Zima Njia ya mkato"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Usizime"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Inabadili kwenda <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Inamwondoa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1669,20 +1682,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
<string name="conference_call" msgid="3751093130790472426">"Simu ya Kongamano"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Kidirisha cha vidokezo"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Michezo"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Muziki na Sauti"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filamu na Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Picha"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Mitandao Jamii na Mawasiliano"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Habari na Magazeti"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Ramani na Maelekezo"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Uzalishaji"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Hifadhi ya kifaa"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ta-watch/styles_material.xml b/core/res/res/values-ta-watch/styles_material.xml
deleted file mode 100644
index d4605e6eaea9..000000000000
--- a/core/res/res/values-ta-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"கேன்டிடேட்ஸ்"</font></string>
-</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index b04f928f2b35..8a70c4e27952 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"பணி சுயவிவர நிர்வாகி பயன்பாடு இல்லை அல்லது சேதமடைந்துள்ளது. இதன் விளைவாக, உங்கள் பணி சுயவிவரமும், அதனுடன் தொடர்புடைய தரவும் நீக்கப்பட்டன. உதவிக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"சாதனத்தில் இனி பணி சுயவிவரம் கிடைக்காது."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"நெட்வொர்க் ட்ராஃபிக் கண்காணிக்கப்படுகிறது"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"மேலும் விவரங்களுக்கு, தட்டவும்"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"மேலும் அறிய, தட்டவும்"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"சாதனத் தரவு அழிக்கப்படும்"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"நிர்வாகி பயன்பாடு இல்லை அல்லது சேதமடைந்துள்ளது மற்றும் பயன்படுத்த முடியாது. இப்போது சாதனத் தரவு அழிக்கப்படும். உதவிக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="me" msgid="6545696007631404292">"நான்"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"திரையின் ஜூம் அளவையும் நிலையையும் கட்டுப்படுத்தலாம்."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"சைகைகளைச் செயல்படுத்துதல்"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"தட்டலாம், ஸ்வைப் செய்யலாம், பின்ச் செய்யலாம் மற்றும் பிற சைகைகளைச் செயல்படுத்தலாம்."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"கைரேகை சைகைகள்"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"சாதனத்தின் கைரேகை உணர்வி மேல் செய்யப்படும் சைகைகளைப் படமெடுக்க முடியும்."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"நிலைப் பட்டியை முடக்குதல் அல்லது மாற்றுதல்"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"நிலைப் பட்டியை முடக்க அல்லது முறைமையில் ஐகான்களைச் சேர்க்க மற்றும் அகற்ற பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"நிலைப் பட்டியில் இருக்கும்"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"உங்கள் குறுக்கீடின்றி IMS சேவையைப் பயன்படுத்தி அழைப்பதற்கு, பயன்பாட்டை அனுமதிக்கும்."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"மொபைல் நிலை மற்றும் அடையாளத்தைப் படித்தல்"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"சாதனத்தின் மொபைல் அம்சங்களை அணுகப் பயன்பாட்டை அனுமதிக்கிறது. மொபைல் மற்றும் சாதன ஐடிகள், அழைப்பு செயலில் உள்ளதா மற்றும் அழைப்பு மூலம் இணைக்கப்பட்ட தொலைக் கட்டுப்பாட்டு எண் ஆகியவற்றைத் தீர்மானிக்க இந்த அனுமதி பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"சிஸ்டம் மூலம் அழைப்புகளை ரூட் செய்தல்"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"அழைக்கும் அனுபவத்தை மேம்படுத்தும் பொருட்டு, சிஸ்டம் மூலம் தனது அழைப்புகளை ரூட் செய்ய பயன்பாட்டை அனுமதிக்கும்."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"மொபைல் எண்ணைப் படி"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"சாதனத்தின் மொபைல் எண்ணை அணுக, பயன்பாட்டை அனுமதிக்கும்."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"டேப்லெட் உறக்க நிலைக்குச் செல்வதைத் தடுத்தல்"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"நீக்கு"</string>
<string name="inputMethod" msgid="1653630062304567879">"உள்ளீட்டு முறை"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"உரை நடவடிக்கைகள்"</string>
+ <string name="email" msgid="4560673117055050403">"மின்னஞ்சல்"</string>
+ <string name="dial" msgid="2275093056198652749">"டயல்"</string>
+ <string name="map" msgid="5441053548030107189">"வரைபடம்"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"சேமிப்பிடம் குறைகிறது"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"சில அமைப்பு செயல்பாடுகள் வேலை செய்யாமல் போகலாம்"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"முறைமையில் போதுமான சேமிப்பகம் இல்லை. 250மெ.பை. அளவு காலி இடவசதி இருப்பதை உறுதிசெய்து மீண்டும் தொடங்கவும்."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"மேலும் விருப்பங்களுக்கு, தட்டவும்."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB பிழை திருத்தத்தை முடக்க, தட்டவும்."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"பிழை அறிக்கையை எடுக்கிறது…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"நிறுவல் அமர்வுகளைப் படிக்க, பயன்பாட்டை அனுமதிக்கிறது. இது செயல்படும் தொகுப்பு நிறுவல்களைப் பற்றிய விவரங்களைப் பார்க்க அனுமதிக்கிறது."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"நிறுவல் தொகுப்புகளைக் கோருதல்"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"தொகுப்புகளின் நிறுவலைக் கோர, பயன்பாட்டை அனுமதிக்கும்."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"தொகுப்புகளை நீக்க கோரு"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"தொகுப்புகளை நீக்க கோர, பயன்பாட்டை அனுமதிக்கும்."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"பேட்டரி மேம்படுத்தல்களைப் புறக்கணிப்பதற்கான அனுமதியைக் கோரு"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"பயன்பாட்டிற்கான பேட்டரி மேம்படுத்தல்களைப் புறக்கணிப்பதற்கான அனுமதியைக் கோர, பயன்பாட்டை அனுமதிக்கும்."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"அளவை மாற்றுவதற்கான கட்டுப்பாட்டிற்கு, இருமுறை தட்டவும்"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"அகற்று"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"அணுகல்தன்மையை இயக்க இரண்டு விரல்களைத் தொடர்ந்து வைக்கவும்."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"அணுகல்தன்மை இயக்கப்பட்டது."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"அணுகல்தன்மை ரத்துசெய்யப்பட்டது."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"அணுகல்தன்மைக் குறுக்குவழி இயக்கப்பட்டது"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"இரண்டு ஒலியளவுப் பொத்தான்களையும் 3 வினாடிகளுக்குப் பிடித்திருப்பதன் மூலம், <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கவும் அல்லது முடக்கவும்.\n\nஅமைப்புகள் &gt; அணுகல்தன்மை என்பதற்குச் சென்று, சேவையை மாற்றிக்கொள்ளலாம்."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"குறுக்குவழியை முடக்கு"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"இயக்கத்திலேயே வை"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கியது"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ முடக்கியது"</string>
<string name="user_switched" msgid="3768006783166984410">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>க்கு மாறுகிறது…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> வெளியேறுகிறார்…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"முடக்கப்பட்டது: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"குழு அழைப்பு"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"உதவிக்குறிப்பு"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"கேம்கள்"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"இசையும் ஆடியோவும்"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"திரைப்படங்களும் வீடியோவும்"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"புகைப்படங்களும் படங்களும்"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"சமூகமும் தகவல்தொடர்பும்"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"செய்திகளும் பத்திரிகைகளும்"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"வரைபடங்களும் வழிசெலுத்தலும்"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"உற்பத்தித்திறன்"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"சாதனச் சேமிப்பகம்"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-te-watch/styles_material.xml b/core/res/res/values-te-watch/styles_material.xml
deleted file mode 100644
index 877cd58c199d..000000000000
--- a/core/res/res/values-te-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"క్యాండిడేట్‌లు"</font></string>
-</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7f2ffddf73d1..4d220922994d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"కార్యాలయ ప్రొఫైల్ నిర్వాహక అనువర్తనం లేదు లేదా పాడైంది. తత్ఫలితంగా, మీ కార్యాలయ ప్రొఫైల్ మరియు సంబంధిత డేటా తొలగించబడ్డాయి. సహాయం కోసం మీ నిర్వాహకుడిని సంప్రదించండి."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడుతోంది"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"మరిన్ని వివరాల కోసం నొక్కండి"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"మరింత తెలుసుకోవడానికి నొక్కండి"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"నిర్వాహక అనువర్తనంలో కొన్ని అంతర్భాగాలు లేవు లేదా అది పాడైపోయి, నిరుపయోగంగా మారింది. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది. సహాయం కోసం మీ నిర్వాహకుడిని సంప్రదించండి."</string>
<string name="me" msgid="6545696007631404292">"నేను"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"డిస్‌ప్లే జూమ్ స్థాయి మరియు స్థానాన్ని నియంత్రిస్తుంది."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"సంజ్ఞలను చేయడం"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"నొక్కగలరు, స్వైప్ చేయగలరు, స్క్రీన్‌పై రెండు వేళ్లను ఉంచి ఆ వేళ్లను దగ్గరకు లేదా దూరానికి లాగగలరు మరియు ఇతర సంజ్ఞలను చేయగలరు."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"వేలిముద్ర సంజ్ఞలు"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"పరికరాల వేలిముద్ర సెన్సార్‌లో నిర్వహించిన సంజ్ఞలను క్యాప్చర్ చేయవచ్చు."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"స్థితి బార్‌ను నిలిపివేయడం లేదా సవరించడం"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"స్థితి బార్‌ను నిలిపివేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"స్థితి పట్టీగా ఉండటం"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"మీ ప్రమేయం లేకుండా కాల్‌లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"పరికరం యొక్క ఫోన్ లక్షణాలను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"ఫోన్ నంబర్‌ను చదవడం"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"పరికరం యొక్క ఫోన్ నంబర్‌ను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"టాబ్లెట్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"తొలగించు"</string>
<string name="inputMethod" msgid="1653630062304567879">"ఇన్‌పుట్ పద్ధతి"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"వచనానికి సంబంధించిన చర్యలు"</string>
+ <string name="email" msgid="4560673117055050403">"ఇమెయిల్"</string>
+ <string name="dial" msgid="2275093056198652749">"డయల్ చేయి"</string>
+ <string name="map" msgid="5441053548030107189">"మ్యాప్"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"నిల్వ ఖాళీ అయిపోతోంది"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"కొన్ని సిస్టమ్ కార్యాచరణలు పని చేయకపోవచ్చు"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"సిస్టమ్ కోసం తగినంత నిల్వ లేదు. మీకు 250MB ఖాళీ స్థలం ఉందని నిర్ధారించుకుని, పునఃప్రారంభించండి."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"మరిన్ని ఎంపికల కోసం నొక్కండి."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB డీబగ్గింగ్‌ను నిలిపివేయడానికి నొక్కండి."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"బగ్ నివేదికను తీస్తోంది…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ఇన్‌స్టాల్ సెషన్‌లను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది సక్రియ ప్యాకేజీ ఇన్‌స్టాలేషన్‌ల గురించి వివరాలను చూడటానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ఇన్‌స్టాల్ ప్యాకేజీలను అభ్యర్థించడం"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ప్యాకేజీల ఇన్‌స్టాలేషన్ అభ్యర్థించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ప్యాకేజీలను తొలగించడానికి అభ్యర్థించు"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ప్యాకేజీల తొలగింపును అభ్యర్థించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"బ్యాటరీ అనుకూలీకరణలను విస్మరించడానికి అడగాలి"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ఆ అనువర్తనం కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"తీసివేయి"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"వాల్యూమ్‌ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్‌లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ప్రాప్యతను ప్రారంభించడానికి రెండు వేళ్లను నొక్కి ఉంచండి."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ప్రాప్యత ప్రారంభించబడింది."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ప్రాప్యత రద్దు చేయబడింది."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ప్రాప్యతా సత్వరమార్గం ఆన్ చేయబడింది"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"వాల్యూమ్ బటన్‌లు రెండింటినీ 3 సెకన్ల పాటు నొక్కి, పట్టుకోవడం ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఆన్ లేదా ఆఫ్ చేయండి.\n\nమీరు సెట్టింగ్‌లు &gt; ప్రాప్యతలో సేవని మార్చవచ్చు."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"ఆన్‌లో ఉంచు"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ప్రాప్యతా సత్వరమార్గం ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ప్రాప్యతా సత్వరమార్గం ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
<string name="user_switched" msgid="3768006783166984410">"ప్రస్తుత వినియోగదారు <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>కి మారుస్తోంది…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>ని లాగ్ అవుట్ చేస్తోంది…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> నిలిపివేయబడింది"</string>
<string name="conference_call" msgid="3751093130790472426">"కాన్ఫరెన్స్ కాల్"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"సాధనం చిట్కా"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"గేమ్‌లు"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"సంగీతం &amp; ఆడియో"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"చలనచిత్రాలు &amp; వీడియో"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ఫోటోలు &amp; చిత్రాలు"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"సామాజికం &amp; కమ్యూనికేషన్"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"వార్తలు &amp; వార్తాపత్రికలు"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"మ్యాప్స్ &amp; నావిగేషన్"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ఉత్పాదకత"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"పరికర నిల్వ"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-th-watch/styles_material.xml b/core/res/res/values-th-watch/styles_material.xml
deleted file mode 100644
index 3227ced76338..000000000000
--- a/core/res/res/values-th-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"ผู้สมัคร"</font></string>
-</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 7e2f78c8119b..38dfd84f5773 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"แอปผู้ดูแลระบบโปรไฟล์งานไม่มีอยู่หรือเสียหาย ระบบจึงทำการลบโปรไฟล์งานและข้อมูลที่เกี่ยวข้องของคุณออก โปรดติดต่อผู้ดูแลระบบเพื่อรับความช่วยเหลือ"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"โปรไฟล์งานของคุณไม่สามารถใช้บนอุปกรณ์นี้ได้อีกต่อไป"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"มีการติดตามดูการจราจรของข้อมูลในเครือข่าย"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"แตะเพื่อดูรายละเอียดเพิ่มเติม"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"แตะเพื่อเรียนรู้เพิ่มเติม"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"แอปผู้ดูแลระบบมีองค์ประกอบไม่ครบหรือเสียหาย และใช้งานไม่ได้ ระบบจะลบข้อมูลอุปกรณ์ของคุณ โปรดติดต่อผู้ดูแลระบบเพื่อรับความช่วยเหลือ"</string>
<string name="me" msgid="6545696007631404292">"ฉัน"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ควบคุมระดับการซูมและการวางตำแหน่งของการแสดงผล"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ทำท่าทางสัมผัส"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"สามารถแตะ เลื่อน บีบ และทำท่าทางสัมผัสอื่นๆ"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ท่าทางสัมผัสลายนิ้วมือ"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"สามารถจับท่าทางสัมผัสที่เกิดขึ้นบนเซ็นเซอร์ลายนิ้วมือของอุปกรณ์"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ปิดการใช้งานหรือแก้ไขแถบสถานะ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"อนุญาตให้แอปพลิเคชันปิดใช้งานแถบสถานะหรือเพิ่มและนำไอคอนระบบออก"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"เป็นแถบสถานะ"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"อนุญาตให้แอปใช้บริการ IMS เพื่อโทรออกโดยคุณไม่ต้องดำเนินการใดๆ เลย"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"อ่านสถานะและข้อมูลระบุตัวตนของโทรศัพท์"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"อนุญาตให้แอปพลิเคชันเข้าถึงคุณลักษณะโทรศัพท์ของอุปกรณ์ การอนุญาตนี้ทำให้แอปพลิเคชันสามารถตรวจสอบหมายเลขโทรศัพท์และรหัสอุปกรณ์ ตรวจสอบว่ามีการโทรที่ทำงานอยู่หรือไม่ และตรวจสอบหมายเลขระยะไกลที่เชื่อมต่อด้วยการโทร"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"กำหนดเส้นทางการโทรผ่านระบบ"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"อนุญาตให้แอปกำหนดเส้นทางการโทรของแอปผ่านระบบเพื่อปรับปรุงประสบการณ์ในการโทร"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"อ่านหมายเลขโทรศัพท์"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"อนุญาตให้แอปเข้าถึงหมายเลขโทรศัพท์ของอุปกรณ์"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"ลบ"</string>
<string name="inputMethod" msgid="1653630062304567879">"วิธีป้อนข้อมูล"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"การทำงานของข้อความ"</string>
+ <string name="email" msgid="4560673117055050403">"อีเมล"</string>
+ <string name="dial" msgid="2275093056198652749">"หมุนหมายเลข"</string>
+ <string name="map" msgid="5441053548030107189">"แผนที่"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"พื้นที่เก็บข้อมูลไม่เพียงพอสำหรับระบบ โปรดตรวจสอบว่าคุณมีพื้นที่ว่าง 250 MB แล้วรีสตาร์ท"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"แตะเพื่อปิดใช้การแก้ไขข้อบกพร่องของ USB"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"อนุญาตให้แอปพลิเคชันอ่านเซสชันการติดตั้ง ซึ่งจะอนุญาตให้อ่านรายละเอียดเกี่ยวกับการติดตั้งแพ็กเกจที่ใช้งาน"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ขอติดตั้งแพ็กเกจ"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"อนุญาตให้แอปพลิเคชันขอการติดตั้งแพ็กเกจ"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ขอการลบแพ็กเกจ"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"อนุญาตให้แอปพลิเคชันขอการลบแพ็กเกจ"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ขอเพิกเฉยต่อการเพิ่มประสิทธิภาพแบตเตอรี่"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"อนุญาตให้แอปขอสิทธิ์เพิกเฉยต่อการเพิ่มประสิทธิภาพแบตเตอรี่สำหรับแอปนั้น"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"แตะสองครั้งเพื่อควบคุมการซูม"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener ความเป็นจริงเสมือน"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR Listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"บริการตัวจัดอันดับการแจ้งเตือน"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ลบ"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ใช้สองนิ้วแตะค้างไว้เพื่อเปิดใช้งานการเข้าถึง"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"เปิดใช้งานการเข้าถึงแล้ว"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ยกเลิกการเข้าถึงแล้ว"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ทางลัดการเข้าถึงเปิดอยู่"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"เปิดหรือปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> โดยกดปุ่มปรับระดับเสียงทั้งสองค้างไว้ 3 วินาที\n\nคุณสามารถเปลี่ยนบริการได้ในการตั้งค่า &gt; การเข้าถึง"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"ปิดทางลัด"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"เปิดไว้"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ทางลัดการเข้าถึงเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ทางลัดการเข้าถึงปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="2871009331809089783">"กำลังเปลี่ยนเป็น <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"กำลังออกจากระบบ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ปิดใช้ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"การประชุมสาย"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"เคล็ดลับเครื่องมือ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"เกม"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"เพลงและเสียง"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"ภาพยนตร์และวิดีโอ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"รูปภาพ"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"โซเชียลและการสื่อสาร"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"ข่าวสารและนิตยสาร"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"แผนที่และการนำทาง"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"ประสิทธิภาพการทำงาน"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"พื้นที่เก็บข้อมูลของอุปกรณ์"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-tl-watch/styles_material.xml b/core/res/res/values-tl-watch/styles_material.xml
deleted file mode 100644
index 70e7a7aaa0f5..000000000000
--- a/core/res/res/values-tl-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"mga kandidato"</font></string>
-</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f245774a146a..06c6aa76251a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Ang admin app ng profile sa trabaho ay nawawala o sira. Bilang resulta, na-delete na ang iyong profile sa trabaho at nauugnay na data. Makipag-ugnayan sa iyong administrator para sa tulong."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Hindi na available ang iyong profile sa trabaho sa device na ito."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Sinusubaybayan ang trapiko sa network"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"I-tap para sa higit pang detalye"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"I-tap upang matuto pa"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Buburahin ang iyong device"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Ang admin app ay may mga kulang na bahagi o sira, at hindi ito magagamit. Buburahin na ngayon ang iyong device. Makipag-ugnayan sa iyong administrator para sa tulong."</string>
<string name="me" msgid="6545696007631404292">"Ako"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolin ang antas ng pag-zoom at pagpoposisyon ng display."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Magsagawa ng mga galaw"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"May kakayahang mag-tap, mag-swipe, mag-pinch at magsagawa ng iba pang mga galaw."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Mga galaw gamit ang fingerprint"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Makukunan ang mga galaw na ginawa sa sensor para sa fingerprint ng mga device."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"i-disable o baguhin ang status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Pinapayagan ang app na i-disable ang status bar o magdagdag at mag-alis ng mga icon ng system."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"maging status bar"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Pinapahintulutan ang app na gamitin ang serbisyo ng IMS upang tumawag nang walang pahintulot mo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"basahin ang katayuan at pagkakakilanlan ng telepono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pinapayagan ang app na i-access ang mga tampok ng telepono ng device. Pinapayagan ng pahintulot na ito ang app na tukuyin ang numero ng telepono at mga ID ng device, kung aktibo man ang isang tawag, at ang malayuang numerong ikinonekta ng isang tawag."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"iruta ang mga tawag sa pamamagitan ng system"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Pinapayagan ang app na iruta ang mga tawag nito sa pamamagitan ng system upang mapahusay ang karanasan sa pagtawag."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"basahin ang numero ng telepono"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Binibigyang-daan ang app na i-access ang numero ng telepono ng device."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"pigilan ang tablet mula sa pag-sleep"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"I-delete"</string>
<string name="inputMethod" msgid="1653630062304567879">"Pamamaraan ng pag-input"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Pagkilos ng teksto"</string>
+ <string name="email" msgid="4560673117055050403">"Mag-email"</string>
+ <string name="dial" msgid="2275093056198652749">"Mag-dial"</string>
+ <string name="map" msgid="5441053548030107189">"Mapa"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Walang sapat na storage para sa system. Tiyaking mayroon kang 250MB na libreng espasyo at i-restart."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Piliin upang i-disable ang debugging ng USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Pinapayagan ang isang application na magbasa ng mga session ng pag-install. Nagbibigay-daan ito upang makita ang mga detalye tungkol sa mga aktibong pag-install ng package."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"humiling ng mga package sa pag-install"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Pinapayagan ang isang application na hilingin ang pag-install ng mga package."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"humihiling na mag-delete ng mga package"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Pinapayagan ang isang application na humiling ng pag-delete ng mga package."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"hilingin na balewalain ang mga pag-optimize ng baterya"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Pinapayagang humingi ng pahintulot ang isang app na balewalain ang mga pag-optimize ng baterya para sa app na iyon."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tapikin ng dalawang beses para sa pagkontrol ng zoom"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Panatilihing nakapindot nang matagal ang iyong dalawang daliri upang paganahin ang pagiging naa-access."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Pinagana ang accessibility."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Nakansela ang pagiging naa-access."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"NAKA-ON ang Shortcut sa Accessibility"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"I-on o i-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sa pamamagitan ng pagpindot nang matagal sa parehong volume button sa loob ng 3 segundo.\n\nMaaari mong palitan ang serbisyo sa Mga Setting &gt; Accessibility."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"I-off ang Shortcut"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Iwanang naka-on"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Lumilipat kay <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Nila-log out si <xliff:g id="NAME">%1$s</xliff:g>..."</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Mga Laro"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musika at Audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Mga Pelikula at Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Mga Larawan at Imahe"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Social at Pakikipag-ugnayan"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Balita at Mga Magazine"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Mga Mapa at Navigation"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Storage ng device"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-tr-watch/styles_material.xml b/core/res/res/values-tr-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-tr-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0c3db29ea16f..c6dd402d7777 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"İş profili yönetici uygulaması eksik ya da bozuk. Bunun sonucunda iş profiliniz ve ilgili veriler silindi. Yardım almak için yöneticiniz ile iletişim kurun."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"İş profiliniz arık bu cihazda kullanılamıyor."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Ağ trafiği izleniyor"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Daha fazla ayrıntı için dokunun"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Daha fazla bilgi için dokunun"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Cihazınız silinecek"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Yönetici uygulamasında bileşen eksik ya da uygulama bozuk ve kullanılamaz durumda. Cihazınız şimdi silinecek. Yardım için yöneticinizle iletişim kurun."</string>
<string name="me" msgid="6545696007631404292">"Ben"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranın yakınlaştırma seviyesini ve konumunu kontrol edin."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Haraketleri yapma"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Hafifçe dokunabilir, hızlıca kaydırabilir, sıkıştırabilir ve diğer hareketleri yapabilirsiniz."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Parmak izi hareketleri"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Cihazların parmak izi sensörlerinde gerçekleştirilen hareketleri yakalayabilir."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"durum çubuğunda olma"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Uygulamanın, sizin müdahaleniz olmadan telefon etmek için IMS hizmetini kullanmasına izin verir."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonun durumunu ve kimliğini okuma"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Uygulamaya cihazdaki telefon özelliklerine erişme izni verir. Bu izin, uygulamanın telefon numarasını ve cihaz kimliğini, etkin bir çağrı olup olmadığını ve çağrıda bağlanılan karşı tarafın numarasını öğrenmesine olanak sağlar."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"çağrıları sistem üzerinden yönlendir"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Uygulamanın, çağrı deneyimini iyileştirmek için çağrılarını sistem üzerinden yönlendirmesine olanak tanır."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon numarasını oku"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Uygulamanın cihazın telefon numarasına erişmesine izin verir."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tabletin uykuya geçmesini önle"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Sil"</string>
<string name="inputMethod" msgid="1653630062304567879">"Giriş yöntemi"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Metin eylemleri"</string>
+ <string name="email" msgid="4560673117055050403">"E-posta"</string>
+ <string name="dial" msgid="2275093056198652749">"Çevir"</string>
+ <string name="map" msgid="5441053548030107189">"Harita"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem için yeterli depolama alanı yok. 250 MB boş alanınızın bulunduğundan emin olun ve yeniden başlatın."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Diğer seçenekler için dokunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için tıklayın."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hata raporu alınıyor…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Bir uygulamanın yükleme oturumlarını okumasına izin verir. Bu, etkin paket yüklemeleriyle ilgili ayrıntıların görülmesine olanak tanır."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paket yükleme isteğinde bulunma"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Uygulamaya, paketleri yükleme isteğinde bulunma izni verir."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"paketleri silme isteğinde bulunma"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Uygulamaya, paketleri silme isteğinde bulunma izni verir."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"pil optimizasyonlarını göz ardı etme izni iste"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Bir uygulamanın, kendisi için pil optimizasyonlarını göz ardı etme izni istemesine olanak sağlar."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zum denetimi için iki kez dokun"</string>
@@ -1225,7 +1235,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sanal Gerçeklik dinleyici"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR dinleyici"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Bildirim sıralama hizmeti"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Erişilebilirliği etkinleştirmek için iki parmağınızı basılı tutmaya devam edin."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Erişilebilirlik etkinleştirildi."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Erişilebilirlik Kısayolu AÇIK"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Ses düğmelerini 3 saniye basılı tutarak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açın veya kapatın.\n\nHizmeti, Ayarlar &gt; Erişilebilirlik seçeneğinden değiştirebilirsiniz."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Kısayolu Kapat"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Açık bırak"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
<string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> adlı kullanıcıya geçiliyor…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> hesabından çıkış yapılıyor…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferans Çağrısı"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"İpucu"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Oyunlar"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Müzik ve Ses"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Filmler ve Video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Fotoğraflar ve Görüntüler"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Sosyal Ağ ve İletişim"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Haberler ve Dergiler"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Haritalar ve Navigasyon"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Verimlilik"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Cihazdaki depolama alanı"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-uk-watch/styles_material.xml b/core/res/res/values-uk-watch/styles_material.xml
deleted file mode 100644
index 698d5b010878..000000000000
--- a/core/res/res/values-uk-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"варіанти"</font></string>
-</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 19e3798d650d..6b5070a46bc0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -187,7 +187,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Додаток адміністратора в робочому профілі відсутній або пошкоджений. У результаті ваш робочий профіль і пов’язані з ним дані видалено. Зверніться до свого адміністратора по допомогу."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Робочий профіль більше не доступний на цьому пристрої."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Відстежується мережевий трафік"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Торкніться, щоб дізнатися більше"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Торкніться, щоб дізнатися більше"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"З вашого пристрою буде стерто всі дані"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Неможливо скористатися додатком адміністратора, оскільки в ньому немає певних компонентів або його пошкоджено. З вашого пристрою буде стерто всі дані. Зверніться до свого адміністратора по допомогу."</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
@@ -284,6 +284,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролювати масштаб і розташування екрана."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Виконання жестів"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна торкатися, проводити пальцем, стискати пальці та виконувати інші жести."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жести на сканері відбитків пальців"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Фіксуються жести на сканері відбитків пальців."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"вимикати чи змін. рядок стану"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволяє програмі вимикати рядок стану чи додавати та видаляти піктограми системи."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"відображатися як рядок стану"</string>
@@ -388,6 +390,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Додаток зможе телефонувати за допомогою служби IMS без вашого відома."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читати статус та ідентифікаційну інформацію телефону"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозволяє програмі отримувати доступ до телефонних функцій пристрою. Такий дозвіл дає програмі змогу визначати номер телефону й ідентифікатори пристрою, активність виклику, а також віддалений номер, на який здійснюється виклик."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"маршрутизувати виклики через систему"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Дозволяє додатку маршрутизувати виклики через систему, щоб було зручніше телефонувати."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"переглядати номер телефону"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Дозволяє додатку отримувати доступ до номера телефону на пристрої."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"не доп.перехід пристр.в реж.сну"</string>
@@ -987,6 +991,9 @@
<string name="deleteText" msgid="6979668428458199034">"Видалити"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метод введення"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Дії з текстом"</string>
+ <string name="email" msgid="4560673117055050403">"Електронна пошта"</string>
+ <string name="dial" msgid="2275093056198652749">"Набрати номер"</string>
+ <string name="map" msgid="5441053548030107189">"Карта"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостатньо місця для системи. Переконайтесь, що на пристрої є 250 Мб вільного місця, і повторіть спробу."</string>
@@ -1181,6 +1188,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Торкніться, щоб переглянути більше опцій."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Торкніться, щоб вимкнути налагодження USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Вибер., щоб вимкн. налагодж. USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Створюється повідомлення про помилку…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
@@ -1237,6 +1245,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дозволяє додатку читати дані сеансів встановлення. Додаток може бачити деталі про активні встановлення пакетів."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"запитувати дані про пакети встановлення"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Додаток зможе надсилати запити на встановлення пакетів."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"запити на видалення пакетів"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Додаток зможе надсилати запити на видалення пакетів."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"запитувати дозвіл ігнорувати оптимізацію використання заряду акумулятора"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Додаток зможе запитувати дозвіл ігнорувати оптимізацію використання заряду акумулятора."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Двічі натис. для кер. масшт."</string>
@@ -1265,7 +1275,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Обробник віртуальної реальності"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-режим"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Служба встановлення пріоритетності сповіщень"</string>
<string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
@@ -1465,9 +1475,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Вилучити"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утримуйте двома пальцями, щоб увімкнути доступність."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Доступність увімкнено."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Доступність скасовано."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Ярлик спеціальних можливостей УВІМКНЕНО"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Умикайте й вимикайте <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуючи обидві кнопки регулювання гучності протягом 3 секунд.\n\nПараметри служби можна змінити в меню \"Налаштування &gt; Спеціальні можливості\"."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Вимкнути ярлик"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Не вимикати"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Перехід в обліковий запис \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Вихід з облікового запису користувача <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1733,20 +1746,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> вимкнено"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференц-виклик"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Спливаюча підказка"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Ігри"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Музика й аудіо"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Фільми та відео"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Фотографії та зображення"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Соцмережі та спілкування"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Новини та журнали"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Карти й навігація"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивність"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Пам’ять пристрою"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-ur-watch/styles_material.xml b/core/res/res/values-ur-watch/styles_material.xml
deleted file mode 100644
index e569c7c78d10..000000000000
--- a/core/res/res/values-ur-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"امیدواران"</font></string>
-</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3eb2025cd3e1..9f77dbb2c031 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"دفتری پروفائل کی منتظم ایپ یا تو غائب ہے یا خراب ہے۔ اس کی وجہ سے، آپ کا دفتری پروفائل اور متعلقہ ڈیٹا حذف کر دیے گئے ہیں۔ مدد کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"آپ کا دفتری پروفائل اس آلہ پر مزید دستیاب نہیں ہے۔"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"نیٹ ورک ٹریفک مانیٹر ہو رہی ہے"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"مزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"مزید جاننے کیلئے تھپتھپائیں"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"آپ کا آلہ صاف کر دیا جائے گا"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"منتظم کی ایپ میں گمشدہ اجزاء ہیں یا وہ خراب ہے اور اسے استعمال نہیں کیا جا سکتا ہے۔ آپ کے آلہ کو اب صاف کر دیا جائے گا۔ مدد کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
<string name="me" msgid="6545696007631404292">"میں"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ڈسپلے کے زوم کی سطح اور پوزیشن کو کنٹرول کریں۔"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اشارے انجام دیں"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"تھپتھپانا، سوائپ کرنا، چٹکی بھرنا اور دیگر اشارے انجام دے سکتی ہے"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"فنگرپرنٹ کے اشارے"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"آلات کے فنگر پرنٹ سینسر پر کیے گئے اشاروں کو کیپچر کر سکتا ہے۔"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"اسٹیٹس بار کو غیر فعال یا اس میں ترمیم کریں"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ایپ کو اسٹیٹس بار غیر فعال کرنے یا سسٹم آئیکنز شامل کرنے اور ہٹانے کی اجازت دیتا ہے۔"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"بطور اسٹیٹس بار کام لیں"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"‏آپ کی مداخلت کے بغیر کالیں کرنے کیلئے ایپ کو IMS سروس استعمال کرنے کی اجازت دیتی ہے۔"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"فون کے اسٹیٹس اور شناخت کو پڑھیں"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"‏ایپ کو آلے کی فون والی خصوصیات تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو فون نمبر اور آلے کے IDs کا تعین کرنے، آیا کوئی کال فعال ہے، اور کال کے ذریعہ مربوط ریموٹ نمبر کا تعین کرنے دیتی ہے۔"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"سسٹم کے ذریعہ کالز روٹ کریں"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"کالںگ کا تجربہ بہتر بنانے کے لیے سسٹم کے ذریعہ ایپ کو کالز روٹ کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"فون نمبر پڑھے"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"ایپ کو آلہ کے فون نمبر تک رسائی کرنے دیتا ہے۔"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ٹیبلیٹ کو سلیپ وضع میں جانے سے روکیں"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"حذف کریں"</string>
<string name="inputMethod" msgid="1653630062304567879">"اندراج کا طریقہ"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"متن کی کارروائیاں"</string>
+ <string name="email" msgid="4560673117055050403">"ای میل"</string>
+ <string name="dial" msgid="2275093056198652749">"ڈائل کریں"</string>
+ <string name="map" msgid="5441053548030107189">"نقشہ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"اسٹوریج کی جگہ ختم ہو رہی ہے"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ممکن ہے سسٹم کے کچھ فنکشنز کام نہ کریں"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"‏سسٹم کیلئے کافی اسٹوریج نہیں ہے۔ اس بات کو یقینی بنائیں کہ آپ کے پاس 250MB خالی جگہ ہے اور دوبارہ شروع کریں۔"</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"مزید اختیارات کیلئے تھپتھپائیں۔"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏USB ڈیبگ کرنا مربوط ہو گیا"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"‏USB ڈیبگنگ کو غیر فعال کرنے کیلئے تھپتھپائیں۔"</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"بگ رپورٹ لی جا رہی ہے…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ایک ایپلیکیشن کو انسٹال سیشنز پڑھنے کی اجازت دیتا ہے۔ یہ اسے فعال پیکیج انسٹالیشنز کے بارے میں تفصیلات دیکھنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"پیکجز انسٹال کرنے کی درخواست کریں"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ایک ایپلیکیشن کو پیکجز انسٹال کرنے کی اجازت دیتی ہے۔"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"پیکیجز حذف کرنے کی درخواست کریں"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ایپلیکیشن کو پیکجز حذف کرنے کیلئے درخواست کرنے کی اجازت ہے۔"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"بیٹری کی بہتریاں نظر انداز کرنے کا پوچھیں"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"اس ایپ کیلئے ایک ایپ کو بیٹری کی کارکردگی بہتر بنانے کو نظر انداز کرنے کی اجازت دیں۔"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"زوم کنٹرول کیلئے دوبار تھپتھپائیں"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ہٹائیں"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ایکسیسبیلٹی فعال کرنے کیلئے دو انگلیاں نیچے دبائے رکھیں۔"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"ایکسیسبیلٹی فعال۔"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ایکسیسبیلٹی منسوخ ہوگئی۔"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"ایکسیسبیلٹی شارٹ کٹ آن ہے"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"‏دونوں والیوم بٹنز کو 3 سیکنڈ تک دبائے رکھ کر <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن یا آف کریں۔\n\nآپ سروس کو ترتیبات &gt;ایکسیسبیلٹی میں تبدیل کر سکتے ہیں۔"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"شارٹ کٹ آف کریں"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"فعال رہنے دیں"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کر دیا"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آف کر دیا"</string>
<string name="user_switched" msgid="3768006783166984410">"موجودہ صارف <xliff:g id="NAME">%1$s</xliff:g>۔"</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> پر سوئچ کیا جا رہا ہے…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> لاگ آؤٹ ہو رہا ہے…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"غیر فعال کردہ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"کانفرنس کال"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"ٹول ٹپ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"گیمز"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"موسیقی اور آڈیو"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"موویز اور ویڈیو"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"فوٹوز اور تصاویر"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"سوشل اور مواصلات"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"خبریں اور میگزین"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"نقشے اور نیویگیشن"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"پروڈکٹیوٹی"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"آلہ کی اسٹوریج"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-uz-watch/styles_material.xml b/core/res/res/values-uz-watch/styles_material.xml
deleted file mode 100644
index 3cb38d6a45e0..000000000000
--- a/core/res/res/values-uz-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"nomzodlar"</font></string>
-</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c7068165ada7..6f07869a4bef 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Ishchi profilning administrator ilovasi yo‘q yoki buzilgan. Shuning uchun, ishchi profilingiz va unga aloqador ma’lumotlar o‘chirib tashlandi. Yordam olish uchun administratoringizga murojaat qiling."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Bu qurilmada endi ishchi profilingiz mavjud emas."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Tarmoq trafigi nazorat qilinmoqda"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Tafsilotlar uchun bosing"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Batafsil ma’lumot olish uchun bosing"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Administrator ilovasining ba’zi qismlari yo‘qolgan yoki buzilgan, shuning uchun undan foydalanib bo‘lmaydi. Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi. Yordam olish uchun administratoringizga murojaat qiling."</string>
<string name="me" msgid="6545696007631404292">"Men"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranni kattalashtirish darajasi va joylashuvini boshqaradi."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Imo-ishoralar bilan boshqarish"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Bosish, surish; jipslashtirish va boshqa imo-ishoralarni amalga oshirish mumkin."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Barmoq izi ishoralari"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Barmoq izi skanerlarida kiritilgan ishoralarni taniy oladi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"holat panelini o‘zgartirish yoki o‘chirish"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ilova holat panelini o‘chirib qo‘yishi hamda tizim ikonkalarini qo‘shishi yoki olib tashlashi mumkin."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"holat qatorida ko‘rinishi"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ilovaga sizning ishtirokingizsiz qo‘ng‘iroqlarni amalga oshirish uchun IMS xizmatidan foydalanishga ruxsat beradi."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefon holati haqidagi ma’lumotlarni olish"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ilovaga qurilmangizdagi telefon xususiyatlariga kirishga ruxsat beradi. Bu ruxsat ilovaga telefon raqami va qurilma nomlari, qo‘ng‘iroq faol yoki faolsizligi va masofadagi raqam qo‘ng‘rioq orqali bog‘langanligini aniqlashga imkon beradi."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"chaqiruvlarni tizim orqali yo‘naltirish"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Ilova aloqa sifatini yaxshilash maqsadida chaqiruvlarni tizim orqali yo‘naltirishi mumkin."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"telefon raqamini o‘qish"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ilovaga qurilmaning telefon raqamidan foydalanishiga ruxsat beradi."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"planshetni uyquga ketishiga yo‘l qo‘ymaslik"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"O‘chirish"</string>
<string name="inputMethod" msgid="1653630062304567879">"Kiritish uslubi"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Matn yozish"</string>
+ <string name="email" msgid="4560673117055050403">"E-pochta"</string>
+ <string name="dial" msgid="2275093056198652749">"Chaqiruv"</string>
+ <string name="map" msgid="5441053548030107189">"Xarita"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Xotirada bo‘sh joy tugamoqda"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ba‘zi tizim funksiyalari ishlamasligi mumkin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tizim uchun xotirada joy yetarli emas. Avval 250 megabayt joy bo‘shatib, keyin qurilmani o‘chirib yoqing."</string>
@@ -1141,6 +1148,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Boshqa parametrlarini ko‘rish uchun bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"O‘chirib qo‘yish uchun bu yerga bosing."</string>
+ <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+ <skip />
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Xatoliklar hisoboti olinmoqda…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Xatoliklar hisoboti yuborilsinmi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Xatoliklar hisoboti yuborilmoqda…"</string>
@@ -1197,6 +1206,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ilovaga o‘rnatilgan seanslarni o‘qish uchun ruxsat beradi. Bu unga faol paket o‘rnatmalari haqidagi ma’lumotlarni ko‘rish imkonini beradi."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"paketlarni o‘rnatish so‘rovini yuborish"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ilovaga paketlarni o‘rnatish so‘rovini yuborish imkonini beradi."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"paketlarni o‘chirib tashlash uchun so‘rov"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Ilovaga paketlarni o‘chirib tashlash so‘rovini yuborish imkonini beradi."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"batareya quvvatidan xohlagancha foydalanishni so‘rash"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ilovaga batareya quvvatidan xohlagancha foydalanish uchun ruxsat so‘rashga imkon beradi."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ko‘lamini o‘zgartirish uchun ikki marta bosing"</string>
@@ -1423,9 +1434,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"O‘chirish"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ovoz balandligi tavsiya etilgan darajadan ham yuqori ko‘tarilsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Qulayliklarni yoqish uchun ikki barmog‘ingiz bilan bosib turing."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Imkoniyatlar yoqilgan."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Qulaylik bekor qilindi."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Tezkor ishga tushirish yoniq"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatini yoqish yoki o‘chirib qo‘yish uchun ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\nXizmatni Sozlamalar &gt; Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Yoniq qoldirish"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
<string name="user_switched" msgid="3768006783166984410">"Joriy foydalanuvchi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Quyidagi foydalanuvchiga o‘tilmoqda: <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> hisobidan chiqilmoqda…"</string>
@@ -1671,20 +1685,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferens-aloqa"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Maslahat oynasi"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"O‘yinlar"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Musiqa va audio"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Video va filmlar"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Surat va rasmlar"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Ijtimoiy tarmoqlar va muloqot"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Yangiliklar va jurnallar"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Xaritalar va navigatsiya"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Ish va unumdorlik"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Qurilma xotirasi"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-vi-watch/styles_material.xml b/core/res/res/values-vi-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-vi-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a406656e08aa..f2d9c8f74e76 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Ứng dụng quản trị hồ sơ công việc bị thiếu hoặc hỏng. Do vậy, hồ sơ công việc của bạn và dữ liệu liên quan đã bị xóa. Hãy liên hệ với quản trị viên để được trợ giúp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Hồ sơ công việc của bạn không có sẵn trên thiết bị này nữa."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Lưu lượng truy cập mạng đang được giám sát"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Nhấn để biết thêm chi tiết"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Nhấn để tìm hiểu thêm"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Thiết bị của bạn sẽ bị xóa"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Ứng dụng quản trị đang bị thiếu thành phần hoặc bị hỏng và không thể sử dụng được. Bây giờ, thiết bị của bạn sẽ bị xóa. Hãy liên hệ với quản trị viên của bạn để được trợ giúp."</string>
<string name="me" msgid="6545696007631404292">"Tôi"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kiểm soát vị trí và mức thu phóng của màn hình."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Thực hiện cử chỉ"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Có thể nhấn, vuốt, chụm và thực hiện các cử chỉ khác."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Cử chỉ vân tay"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Có thể ghi lại các cử chỉ được thực hiện trên cảm biến vân tay của thiết bị."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"trở thành thanh trạng thái"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Cho phép ứng dụng sử dụng dịch vụ IMS để thực hiện cuộc gọi mà không có sự can thiệp của bạn."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"đọc trạng thái và nhận dạng của điện thoại"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Cho phép ứng dụng truy cập vào các tính năng điện thoại của thiết bị. Quyền này cho phép ứng dụng xác định số điện thoại và ID thiết bị, cho dù cuộc gọi có hiện hoạt hay không và số từ xa có được kết nối bằng một cuộc gọi hay không."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"định tuyến cuộc gọi thông qua hệ thống"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Cho phép ứng dụng định tuyến cuộc gọi thông qua hệ thống nhằm cải thiện trải nghiệm gọi điện."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"đọc số điện thoại"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Cho phép ứng dụng truy cập số điện thoại của thiết bị."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Xóa"</string>
<string name="inputMethod" msgid="1653630062304567879">"Phương thức nhập"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Tác vụ văn bản"</string>
+ <string name="email" msgid="4560673117055050403">"Email"</string>
+ <string name="dial" msgid="2275093056198652749">"Quay số"</string>
+ <string name="map" msgid="5441053548030107189">"Bản đồ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Không đủ bộ nhớ cho hệ thống. Đảm bảo bạn có 250 MB dung lượng trống và khởi động lại."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Nhấn để biết thêm tùy chọn."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Nhấn để vô hiệu hóa gỡ lỗi USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chọn để vô hiệu hóa gỡ lỗi USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Đang thu thập báo cáo lỗi…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chia sẻ báo cáo lỗi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Đang chia sẻ báo cáo lỗi…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Cho phép ứng dụng đọc phiên cài đặt. Thao tác này sẽ cho phép ứng dụng xem chi tiết về gói cài đặt đang hoạt động."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"yêu cầu gói cài đặt"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Cho phép ứng dụng yêu cầu cài đặt gói."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"yêu cầu xóa gói"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Cho phép ứng dụng yêu cầu xóa gói."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"hỏi để bỏ qua tối ưu hóa pin"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Cho phép ứng dụng hỏi quyền để bỏ qua tối ưu hóa pin cho ứng dụng đó."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Nhấn hai lần để kiểm soát thu phóng"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tiếp tục giữ hai ngón tay để bật trợ năng."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Trợ năng đã được bật."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Đã hủy trợ năng."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Phím tắt trợ năng BẬT"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Bật hoặc tắt <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bằng cách nhấn giữ cả hai phím âm lượng trong 3 giây.\n\nBạn có thể thay đổi dịch vụ trong Cài đặt &gt; Trợ năng."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Tắt phím tắt"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Để bật"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Đang chuyển sang <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Đang đăng xuất <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Cuộc gọi nhiều bên"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Chú giải công cụ"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Trò chơi"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Nhạc và âm thanh"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Phim và video"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Ảnh và hình ảnh"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Xã hội và truyền thông"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Tin tức và tạp chí"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Bản đồ và dẫn đường"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Sản xuất"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Bộ nhớ của thiết bị"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-zh-rCN-watch/styles_material.xml b/core/res/res/values-zh-rCN-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-zh-rCN-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 55773c64b181..96eba47e3c9e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"工作资料管理应用缺失或损坏,因此系统已删除您的工作资料及相关数据。请与您的管理员联系以寻求帮助。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"您的工作资料已不在此设备上。"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"网络流量正受到监控"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"点按可显示详情"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"点按即可了解详情"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"系统将清空您的设备"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"由于缺少组件或软件包已损坏,无法使用此管理应用。系统现在将清空您的设备。请与您的管理员联系以寻求帮助。"</string>
<string name="me" msgid="6545696007631404292">"我"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制显示内容的缩放级别和位置。"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"执行手势"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可执行点按、滑动、双指张合等手势。"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指纹手势"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可以捕获在设备指纹传感器上执行的手势。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改状态栏"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允许应用停用状态栏或者增删系统图标。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"用作状态栏"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允许应用自行使用即时通讯服务拨打电话。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"读取手机状态和身份"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允许该应用访问设备的电话功能。此权限可让该应用确定本机号码和设备 ID、是否正处于通话状态以及拨打的号码。"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"通过系统转接来电"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"允许该应用通过系统转接来电,以改善通话体验。"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"读取电话号码"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允许该应用访问该设备的电话号码。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"阻止平板电脑进入休眠状态"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"删除"</string>
<string name="inputMethod" msgid="1653630062304567879">"输入法"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
+ <string name="email" msgid="4560673117055050403">"电子邮件"</string>
+ <string name="dial" msgid="2275093056198652749">"拨号"</string>
+ <string name="map" msgid="5441053548030107189">"地图"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系统存储空间不足。请确保您有250MB的可用空间,然后重新启动。"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"点按即可查看更多选项。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"点按即可停用 USB 调试功能。"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"选择停用USB调试。"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在生成错误报告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"允许应用读取安装会话。这样,应用将可以查看有关当前软件包安装的详情。"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"请求安装文件包"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"允许应用请求安装文件包。"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"请求删除文件包"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"允许应用请求删除文件包。"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"请求忽略电池优化"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允许应用请求相应的权限,以便忽略针对该应用的电池优化。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"双击可以进行缩放控制"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要将音量调高到推荐水平以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用辅助功能。"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"无障碍快捷方式已开启"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"同时按住两个音量按钮 3 秒钟即可开启或关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>。\n\n您可以在“设置”&gt;“无障碍”中更改这项服务。"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"关闭快捷方式"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"保持开启状态"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"无障碍快捷方式已开启<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"无障碍快捷方式已关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="2871009331809089783">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出帐号…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"电话会议"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"游戏"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"音乐和音频"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"电影和视频"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"照片和图片"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"社交和通信"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"新闻和杂志"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"地图和导航"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"办公"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"设备存储空间"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-zh-rHK-watch/styles_material.xml b/core/res/res/values-zh-rHK-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-zh-rHK-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 300cc369b68a..234d45b2963e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"找不到工作設定檔應用程式,或工作設定檔應用程式已受損。因此,您的工作設定檔現在將被清除。請聯絡您的管理員以取得協助。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"無法在此裝置上再使用您的工作設定檔。"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"網絡流量現正受監控"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"輕按以瞭解詳情"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"輕按即可瞭解詳情"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"您的裝置將被清除"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"找不到管理員應用程式的元件,或管理員應用程式已受損並不能使用。您的裝置現在將被清除。請聯絡您的管理員以取得協助。"</string>
<string name="me" msgid="6545696007631404292">"我本人"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制顯示屏的縮放程度和位置。"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"執行手勢"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可以輕按、快速滑動和兩指縮放,並執行其他手勢。"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋手勢"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可擷取裝置指紋感應器上執行的手勢。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改狀態列"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"成為狀態列"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允許應用程式自行使用 IMS 服務撥打電話。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限允許應用程式確定手機號碼和裝置編號、是否正在通話中,以及所撥打的對方號碼。"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"透過系統轉接來電"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"允許應用程式透過系統轉接來電,以改善通話體驗。"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"讀取電話號碼"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允許應用程式存取裝置的電話號碼。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"刪除"</string>
<string name="inputMethod" msgid="1653630062304567879">"輸入法"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
+ <string name="email" msgid="4560673117055050403">"電郵"</string>
+ <string name="dial" msgid="2275093056198652749">"撥號"</string>
+ <string name="map" msgid="5441053548030107189">"地圖"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確認裝置有 250 MB 的可用空間,然後重新啟動。"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"輕按即可查看更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"輕按即可停用 USB 偵錯功能。"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取即可停用 USB 偵錯。"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在取得錯誤報告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"允許應用程式讀取安裝工作階段。應用程式將可查看目前安裝套裝的詳細資料。"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"要求安裝套件"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"允許應用程式要求安裝套件"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"要求刪除套件"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"允許應用程式要求刪除套件。"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"要求忽略電池優化"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允許應用程式要求就該應用程式忽略電池優化。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"輕觸兩下控制縮放"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"以兩隻手指按住不放,即可啟用無障礙功能。"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"無障礙功能已啟用。"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"無障礙功能已取消。"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"無障礙功能快速鍵已開啟"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"同時按住兩個音量按鈕 3 秒即可啟用或停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>。\n\n您可以前往「設定」&gt;「無障礙功能」變更這項服務。"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"停用快速鍵"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"繼續啟用"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"無障礙功能快速鍵已啟用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"無障礙功能快速鍵已停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"目前的使用者是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="2871009331809089783">"正在切換至<xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"正在登出 <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"「<xliff:g id="LABEL">%1$s</xliff:g>」已停用"</string>
<string name="conference_call" msgid="3751093130790472426">"會議通話"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"遊戲"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"音樂和音訊"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"電影和影片"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"相片和圖片"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"社交和通訊"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"新聞和雜誌"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"地圖和導航"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"生產力應用程式"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"裝置儲存空間"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-zh-rTW-watch/styles_material.xml b/core/res/res/values-zh-rTW-watch/styles_material.xml
deleted file mode 100644
index 36a459dc16a0..000000000000
--- a/core/res/res/values-zh-rTW-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"candidates"</font></string>
-</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ffa10d7aa1ec..0f0f17655244 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Work 設定檔管理員應用程式遺失或已毀損,因此系統刪除了您的 Work 設定檔和相關資料。如需協助,請與您的管理員聯絡。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"您的 Work 設定檔已不在這台裝置上。"</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"網路流量目前受到監控"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"輕觸即可查看更多詳細資料"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"輕觸即可瞭解詳情"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"您的裝置資料將遭到清除"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"管理員應用程式因遺失元件或已毀損而無法使用,您的裝置資料將隨即遭到清除。如需相關協助,請與您的管理員聯絡。"</string>
<string name="me" msgid="6545696007631404292">"我"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控管顯示畫面的縮放等級和位置。"</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"使用手勢"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可使用輕觸、滑動和雙指撥動等手勢。"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋手勢"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可以擷取在裝置指紋感應器上執行的手勢。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或變更狀態列"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"以狀態列顯示"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"允許應用程式自動使用 IMS 服務撥打電話。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限可讓應用程式判讀手機號碼和裝置 ID、是否正在通話中,以及所撥打的對方號碼。"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"透過系統接通來電"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"允許應用程式透過系統接通來電,以改善通話品質。"</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"讀取電話號碼"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"允許應用程式存取裝置的電話號碼。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"刪除"</string>
<string name="inputMethod" msgid="1653630062304567879">"輸入法"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"文字動作"</string>
+ <string name="email" msgid="4560673117055050403">"電子郵件"</string>
+ <string name="dial" msgid="2275093056198652749">"撥號"</string>
+ <string name="map" msgid="5441053548030107189">"地圖"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確定您已釋出 250MB 的可用空間,然後重新啟動。"</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"輕觸即可查看更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"輕觸即可停用 USB 偵錯。"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取以停用 USB 偵錯。"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在接收錯誤報告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"允許應用程式讀取安裝工作階段。應用程式將可查看目前的套件安裝詳細資料。"</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"要求安裝套件"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"允許應用程式要求安裝套件。"</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"要求刪除套件"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"允許應用程式要求刪除套件。"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"要求忽略電池效能最佳化設定"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"允許應用程式要求權限,以便忽略針對該應用程式的電池效能最佳化設定。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"點兩下以進行縮放控制"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使您的聽力受損。"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"協助工具捷徑已啟用"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"同時按住兩個音量按鈕 3 秒即可啟用或停用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」。\n\n你可以在 [設定] &gt; [協助工具] 中變更這項服務。"</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"停用捷徑"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"繼續啟用"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"協助工具捷徑啟用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"協助工具捷徑停用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
<string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="2871009331809089783">"正在切換至<xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"正在將<xliff:g id="NAME">%1$s</xliff:g>登出帳戶…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"電話會議"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"工具提示"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"遊戲"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"音樂和音訊"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"電影和影片"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"相片和圖片"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"社交和通訊"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"新聞和雜誌"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"地圖和導航"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"生產應用"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"裝置儲存空間"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values-zu-watch/styles_material.xml b/core/res/res/values-zu-watch/styles_material.xml
deleted file mode 100644
index 8b69fef9cb46..000000000000
--- a/core/res/res/values-zu-watch/styles_material.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
- -->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="candidates_style" msgid="8052530148128607468"><font color="#80cbc4">"amakhandidethi"</font></string>
-</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a5da794c2162..938b33266a2e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -183,7 +183,7 @@
<string name="work_profile_deleted_details" msgid="226615743462361248">"Uhlelo lokusebenza lomlawuli lephrofayela yomsebenzi kungenzeka alukho noma lumoshekile. Njengomphumela walokho, iphrofayela yakho yomsebenzi nedatha ehlobene kususiwe. Xhumana nomlawuli wakho ukuze uthole usizo."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Iphrofayela yakho yomsebenzi ayisatholakali kule divayisi."</string>
<string name="network_logging_notification_title" msgid="1805392571290161924">"Ithrafikhi yenethiwekhi iyangamelwa"</string>
- <string name="network_logging_notification_text" msgid="4448072433371155729">"Thepha ukuze uthole imininingwane engeziwe"</string>
+ <string name="network_logging_notification_text" msgid="2671761001956320094">"Thepha ukuze ufunde kabanzi"</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Idivayisi yakho izosulwa"</string>
<string name="factory_reset_message" msgid="4905025204141900666">"Uhlelo lokusebenza lomlawuli lushoda ngezingxenye noma lumoshekile, futhi alikwazi ukusetshenziswa. Idivayisi yakho manje izosulwa. Xhumana nomlawuli wakho ukuze uthole usizo."</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
@@ -278,6 +278,8 @@
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Lawula ileveli yokusondeza yesibonisi nendawo."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Yenza ukuthinta"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Ingathepha, iswayiphe, incinze, futhi yenze okunye ukuthintwa."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Ukuthinta kwezigxivizo zeminwe"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Ingathatha ukuthinta okwenziwe kunzwa yezigxivizo zeminwe zamadivayisi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"yiba yibha yesimo"</string>
@@ -382,6 +384,8 @@
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isevisi ye-IMS ukuze yenze amakholi ngaphandle kokungenelela kwakho."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"yanza imizila yamakholi ngesistimu"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Ivumela uhlelo lokusebenza ukwenza imizila yamakholi ngesistimu ukuze ithuthukise umuzwa wokushaya."</string>
<string name="permlab_readPhoneNumber" msgid="6421295519255154171">"funda inombolo yefoni"</string>
<string name="permdesc_readPhoneNumber" msgid="9135856402838173711">"Ivumela uhlelo lokusebenza ukuthi lifinyelele kunombolo yefoni yedivayisi."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
@@ -947,6 +951,9 @@
<string name="deleteText" msgid="6979668428458199034">"Susa"</string>
<string name="inputMethod" msgid="1653630062304567879">"Indlela yokufakwayo"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Izenzo zombhalo"</string>
+ <string name="email" msgid="4560673117055050403">"I-imeyili"</string>
+ <string name="dial" msgid="2275093056198652749">"Dayela"</string>
+ <string name="map" msgid="5441053548030107189">"Imephu"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Akusona isitoreji esanele sesistimu. Qiniseka ukuthi unesikhala esikhululekile esingu-250MB uphinde uqalise kabusha."</string>
@@ -1141,6 +1148,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Thepha ngezinketho eziningi."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Thepha ukuze ukhubaze ukususa isiphazamisi se-USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Ithatha umbiko wesiphazamisi..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Yabelana ngombiko wesiphazamisi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Yabelana ngombiko wesiphazamisi..."</string>
@@ -1197,6 +1205,8 @@
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Ivumela uhlelo lokusebenza ukufunda izikhathi. Lokhu kuzolivumela ukubona imininingwane mayelana nokufaka kwephakethi esebenzayo."</string>
<string name="permlab_requestInstallPackages" msgid="5782013576218172577">"cela amaphakheji wokufaka"</string>
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Ivumela uhlelo lokusebenza ukucela ukufakwa kwamaphakheji."</string>
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"cela amaphakheji okususa"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Ivumela uhlelo lokusebenza ukuthi lucele ukususwa kwamaphakheji."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"cela ukuziba ukulungiselelwa kwebhethri"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Ivumela uhlelo lokusebenza ukuthi licele imvume yokuziba ukulungiselela ibhethri yalolo hlelo lokusebenza."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Thepha kabili ukuthola ukulawula ukusondeza"</string>
@@ -1423,9 +1433,12 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Gcina ucindezele iminwe yakho emibili ukuze unike amandla ukufinyelela."</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"Ukufinyelela kunikwe amandla."</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ukufinyelela kukhanseliwe."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="5998592821749881862">"Isinqamuleli sokufinyelela SIVULIWE"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="2987297770937717543">"Vula noma vala i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ngokucindezela phansi zombili izinkinobho zevolomu amasekhondi angu-3.\n\nUngashintsha amasevisi kuzilungiselelo &gt; ukufinyelela."</string>
+ <string name="disable_accessibility_shortcut" msgid="3683951963271793789">"Vala isinqamuleli"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="8762106842437042969">"Shiya kuvuliwe"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"Ishintshela ku-<xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"Iyaphuma <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1671,20 +1684,15 @@
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
<string name="conference_call" msgid="3751093130790472426">"Ikholi yengqungquthela"</string>
<string name="tooltip_popup_title" msgid="5253721848739260181">"Ithulithiphu"</string>
- <!-- no translation found for app_category_game (5431836943981492993) -->
- <skip />
- <!-- no translation found for app_category_audio (1659853108734301647) -->
- <skip />
- <!-- no translation found for app_category_video (2728726078629384196) -->
- <skip />
- <!-- no translation found for app_category_image (4867854544519846048) -->
- <skip />
- <!-- no translation found for app_category_social (5842783057834965912) -->
- <skip />
- <!-- no translation found for app_category_news (7496506240743986873) -->
- <skip />
- <!-- no translation found for app_category_maps (5878491404538024367) -->
- <skip />
- <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <string name="app_category_game" msgid="5431836943981492993">"Amageyimu"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"Umculo nomsindo"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"Ama-Movie nevidiyo"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"Izithombe nezithombe"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"Okomphakathi nokuxhumana"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"Izindaba nomagazini"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"Amamephu nokuzula"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"Ukukhiqiza"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Isitoreji sedivayisi"</string>
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
<skip />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index df7a5f523caa..7f49f056d3bf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -64,6 +64,8 @@
<attr name="disabledAlpha" format="float" />
<!-- The alpha applied to the foreground color to create the primary text color. -->
<attr name="primaryContentAlpha" format="float" />
+ <!-- The alpha applied to the foreground color to create the secondary text color. -->
+ <attr name="secondaryContentAlpha" format="float" />
<!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
<attr name="backgroundDimAmount" format="float" />
<!-- Control whether dimming behind the window is enabled. The default
@@ -2274,13 +2276,16 @@
<!-- Sets the padding, in pixels, of the end edge; see {@link android.R.attr#padding}. -->
<attr name="paddingEnd" format="dimension" />
- <!-- Boolean that controls whether a view can take focus. By default the user can not
- move focus to a view; by setting this attribute to true the view is
- allowed to take focus. This value does not impact the behavior of
+ <!-- Controls whether a view can take focus. By default, this is "auto" which lets the
+ framework determine whether a user can move focus to a view. By setting this attribute
+ to true the view is allowed to take focus. By setting it to "false" the view will not
+ take focus. This value does not impact the behavior of
directly calling {@link android.view.View#requestFocus}, which will
always request focus regardless of this view. It only impacts where
focus navigation will try to move focus. -->
- <attr name="focusable" format="boolean" />
+ <attr name="focusable" format="boolean|enum">
+ <enum name="auto" value="0x00000010" />
+ </attr>
<!-- Boolean that controls whether a view can take focus while in touch mode.
If this is true for a view, that view can gain focus when clicked on, and can keep
@@ -2497,13 +2502,13 @@
<!-- Sets the id of a view before which this one is visited in accessibility traversal.
A screen-reader must visit the content of this view before the content of the one
it precedes.
- @see android.view.View#setAccessibilityTraversalBefore(int)} -->
+ {@see android.view.View#setAccessibilityTraversalBefore(int)} -->
<attr name="accessibilityTraversalBefore" format="integer" />
<!-- Sets the id of a view after which this one is visited in accessibility traversal.
A screen-reader must visit the content of the other view before the content of
this one.
- @see android.view.View#setAccessibilityTraversalAfter(int)} -->
+ {@see android.view.View#setAccessibilityTraversalAfter(int)} -->
<attr name="accessibilityTraversalAfter" format="integer" />
<!-- Name of the method in this View's context to invoke when the view is
@@ -3263,8 +3268,8 @@
<!-- The unique id for the subtype. The text service (spell checker) framework keeps track
of enabled subtypes by ID. When the spell checker package gets upgraded, enabled IDs
will stay enabled even if other attributes are different. If the ID is unspecified or
- or explicitly specified to 0 in XML resources,
- {@code Arrays.hashCode(new Object[] {subtypeLocale, extraValue}) will be used instead.
+ explicitly specified to 0 in XML resources,
+ {@code Arrays.hashCode(new Object[] {subtypeLocale, extraValue})} will be used instead.
-->
<attr name="subtypeId" />
<!-- The BCP-47 Language Tag of the subtype. This replaces
@@ -3387,6 +3392,10 @@
<flag name="flagRetrieveInteractiveWindows" value="0x00000040" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME} -->
<flag name="flagEnableAccessibilityVolume" value="0x00000080" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} -->
+ <flag name="flagRequestAccessibilityButton" value="0x00000100" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} -->
+ <flag name="flagCaptureFingerprintGestures" value="0x00000200" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->
@@ -3422,19 +3431,18 @@
<attr name="canRequestFilterKeyEvents" format="boolean" />
<!-- Attribute whether the accessibility service wants to be able to control
display magnification.
- <p>
- Required to allow setting the {@link android.accessibilityservice
- #AccessibilityServiceInfo#FLAG_CAN_CONTROL_MAGNIFICATION} flag.
- </p>
-->
<attr name="canControlMagnification" format="boolean" />
- <!-- Attribute whether the accessibility service wants to be able to perform gestures.
+ <!-- Attribute whether the accessibility service wants to be able to perform gestures. -->
+ <attr name="canPerformGestures" format="boolean" />
+ <!-- Attribute whether the accessibility service wants to be able to capture gestures from
+ the fingerprint sensor.
<p>
Required to allow setting the {@link android.accessibilityservice
- #AccessibilityServiceInfo#FLAG_CAN_PERFORM_GESTURES} flag.
+ #AccessibilityServiceInfo#FLAG_CAN_CAPTURE_FINGERPRINT_GESTURES} flag.
</p>
-->
- <attr name="canPerformGestures" format="boolean" />
+ <attr name="canCaptureFingerprintGestures" format="boolean" />
<!-- Short description of the accessibility service purpose or behavior.-->
<attr name="description" />
</declare-styleable>
@@ -5836,6 +5844,14 @@
<attr name="color" />
</declare-styleable>
+ <!-- Drawable used to draw masked icons with foreground and background layers. -->
+ <declare-styleable name="MaskableIconDrawableLayer">
+ <!-- The color to use for the layer, only if drawable is not defined. -->
+ <attr name="color" />
+ <!-- The drawable to use for the layer. -->
+ <attr name="drawable" />
+ </declare-styleable>
+
<!-- Drawable used to show animated touch feedback. -->
<declare-styleable name="RippleDrawable">
<!-- The color to use for ripple effects. This attribute is required. -->
@@ -7912,7 +7928,6 @@
<attr name="queryBackground" format="reference" />
<!-- Background for the section containing the action (e.g. voice search) -->
<attr name="submitBackground" format="reference" />
- <attr name="focusable" />
</declare-styleable>
<declare-styleable name="Switch">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dfa672d6782c..76f4a7654af7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -864,9 +864,8 @@
<flag name="density" value="0x1000" />
<!-- The layout direction has changed. For example going from LTR to RTL. -->
<flag name="layoutDirection" value="0x2000" />
- <!-- The colorimetry capabilities of the screen have changed (color gamut
- or dynamic range). -->
- <flag name="colorimetry" value="0x4000" />
+ <!-- The color mode of the screen has changed (color gamut or dynamic range). -->
+ <flag name="colorMode" value="0x4000" />
<!-- The font scaling factor has changed, that is the user has
selected a new global font size. -->
<flag name="fontScale" value="0x40000000" />
@@ -886,6 +885,12 @@
will run against. -->
<attr name="targetPackage" format="string" />
+ <!-- The name of an application's processes that an Instrumentation object
+ will run against. If not specified, only runs in the main process of the targetPackage.
+ Can either be a comma-separated list of process names or '*' for any process that
+ launches to run targetPackage code. -->
+ <attr name="targetProcess" format="string" />
+
<!-- Flag indicating that an Instrumentation class wants to take care
of starting/stopping profiling itself, rather than relying on
the default behavior of profiling the complete time it is running.
@@ -1002,6 +1007,13 @@
<enum name="preferExternal" value="2" />
</attr>
+ <!-- If set to <code>true</code>, indicates to the platform that any split APKs
+ installed for this application should be loaded into their own Context
+ objects and not appear in the base application's Context.
+
+ <p>The default value of this attribute is <code>false</code>. -->
+ <attr name="isolatedSplits" format="boolean" />
+
<!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or
{@code <application>} tag. If specified on the {@code <application>}
tag these will be considered defaults for all activities in the
@@ -1159,18 +1171,15 @@
resizeable activities when in multi-window mode. -->
<attr name="resizeableActivity" format="boolean" />
- <!-- Indicates that the activity supports the picture-in-picture (PiP) form of multi-window.
- While it makes sense to be able to resize most activities types in multi-window mode when
- {@link android.R.attr#resizeableActivity} is set. It only makes sense to put specific types
- of activities in PiP mode of multi-window. For example, activities that play video. When
- set the activity will be allowed to enter PiP mode when the system deems it appropriate on
- devices that support PiP.
+ <!-- Indicates that the activity specifically supports the picture-in-picture form of
+ multi-window. If true, this activity will support entering picture-in-picture, but will
+ only support split-screen and other forms of multi-window if
+ {@link android.R.attr#resizeableActivity} is also set to true.
- <p>The default value is <code>false</code> for applications with
- <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#N} and
- <code>true</code> otherwise.
+ Note that your activity may still be resized even if this attribute is true and
+ {@link android.R.attr#resizeableActivity} is false.
- <p>NOTE: Attribute is only used if {@link android.R.attr#resizeableActivity} is true. -->
+ <p>The default value is <code>false</code>. -->
<attr name="supportsPictureInPicture" format="boolean" />
<!-- This value indicates how tasks rooted at this activity will behave in lockTask mode.
@@ -1244,6 +1253,12 @@
split that contains the defined component. -->
<attr name="splitName" format="string" />
+ <!-- Specifies the target sandbox this app wants to use. Higher sanbox versions
+ will have increasing levels of security.
+
+ <p>The default value of this attribute is <code>1</code>. -->
+ <attr name="targetSandboxVersion" format="integer" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1270,6 +1285,8 @@
<attr name="sharedUserId" />
<attr name="sharedUserLabel" />
<attr name="installLocation" />
+ <attr name="isolatedSplits" />
+ <attr name="targetSandboxVersion" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
@@ -2039,13 +2056,20 @@
in a task/stack that isn't focusable. This flag allows them to be focusable.-->
<attr name="alwaysFocusable" format="boolean" />
<attr name="enableVrMode" />
- <!-- @hide This activity is a launcher which should always show up on the top of others.
- This attribute is ignored if the activity isn't a launcher. -->
- <attr name="onTopLauncher" format="boolean" />
<attr name="rotationAnimation" />
<attr name="visibleToInstantApps" />
<!-- The code for this component is located in the given split. -->
<attr name="splitName" />
+ <!-- Specify the color mode the activity desires. The requested color mode may be ignored
+ depending on the capabilities of the display the activity is displayed on. -->
+ <attr name="colorMode">
+ <!-- The default color mode (typically sRGB, low-dynamic range). -->
+ <enum name="default" value="0" />
+ <!-- Wide color gamut color mode. -->
+ <enum name="wideColorGamut" value="1" />
+ <!-- High dynamic range color mode. -->
+ <enum name="hdr" value="2" />
+ </attr>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
@@ -2276,6 +2300,7 @@
is a period then it is appended to your package name. -->
<attr name="name" />
<attr name="targetPackage" />
+ <attr name="targetProcess" />
<attr name="label" />
<attr name="icon" />
<attr name="roundIcon" />
@@ -2359,7 +2384,7 @@
</declare-styleable>
<!-- Declaration of an {@link android.content.Intent} object in XML. May
- also include zero or more {@link #IntentCategory <category> and
+ also include zero or more {@link #IntentCategory <category>} and
{@link #Extra <extra>} tags. -->
<declare-styleable name="Intent">
<!-- The action name to assign to the Intent, as per
@@ -2456,4 +2481,8 @@
<attr name="hash" format="string" />
</declare-styleable>
+ <declare-styleable name="AndroidManifestUsesSplit" parent="AndroidManifest">
+ <attr name="name" format="string" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 4164e5df76d5..b28c6f2d22e3 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -89,7 +89,7 @@
<color name="perms_dangerous_perm_color">#33b5e5</color>
<color name="shadow">#cc222222</color>
<color name="perms_costs_money">#fff4511e</color>
-
+
<!-- For search-related UIs -->
<color name="search_url_text_normal">#7fa87f</color>
<color name="search_url_text_selected">@android:color/black</color>
@@ -132,6 +132,10 @@
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
<drawable name="notification_template_divider">#29000000</drawable>
<drawable name="notification_template_divider_media">#29ffffff</drawable>
+ <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
+ <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
+ <color name="notification_secondary_text_color_light">@color/secondary_text_material_light</color>
+ <color name="notification_secondary_text_color_dark">@color/secondary_text_material_dark</color>
<color name="notification_material_background_color">#ffffffff</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index db89c22a6496..0a24565049ab 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -78,6 +78,8 @@
<item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
<item name="primary_content_alpha_material_light" format="float" type="dimen">1</item>
<item name="primary_content_alpha_material_dark" format="float" type="dimen">0.87</item>
+ <item name="secondary_content_alpha_material_light" format="float" type="dimen">.7</item>
+ <item name="secondary_content_alpha_material_dark" format="float" type="dimen">0.54</item>
<item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
<item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c36279c28fdb..581537d8dfa8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -283,6 +283,11 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+ <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
+ device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
+ This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkMeteredMultipathPreference">3</integer>
+
<!-- List of regexpressions describing the interface (if any) that represent tetherable
USB interfaces. If the device doesn't want to support tethering over USB this should
be empty. An example would be "usb.*" -->
@@ -2278,6 +2283,13 @@
<!-- Whether to use voip audio mode for ims call -->
<bool name="config_use_voip_mode_for_ims">false</bool>
+ <!-- ImsService package name to bind to by default. If none is specified in an overlay, an
+ empty string is passed in -->
+ <string name="config_ims_package"/>
+
+ <!-- Flag specifying whether or not IMS will use the dynamic ImsResolver -->
+ <bool name="config_dynamic_bind_ims">false</bool>
+
<bool name="config_networkSamplingWakesDevice">true</bool>
<string-array translatable="false" name="config_cdma_home_system" />
@@ -2625,8 +2637,14 @@
<!-- Component that is the default launcher when demo mode is enabled. -->
<string name="config_demoModeLauncherComponent">com.android.retaildemo/.DemoPlayer</string>
- <!-- Hashed password (SHA-256) used to restrict demo mode operation -->
- <string name="config_demoModePassword" translatable="false"></string>
+ <!-- Hashed password (SHA-256) used to restrict carrier demo mode operation. -->
+ <string name="config_carrierDemoModePassword" translatable="false"></string>
+
+ <!-- Secure setting used to activate carrier demo mode. -->
+ <string name="config_carrierDemoModeSetting" translatable="false"></string>
+
+ <!-- List of packages to enable in carrier demo mode (comma separated). -->
+ <string name="config_carrierDemoModePackages" translatable="false"></string>
<!-- Flag indicating whether round icons should be parsed from the application manifest. -->
<bool name="config_useRoundIcon">false</bool>
@@ -2712,6 +2730,9 @@
<!-- Component name of the default cell broadcast receiver -->
<string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+ <!-- Specifies the path that is used by MaskableIconDrawable class to crop launcher icons. -->
+ <string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
+
<!-- The component name, flattened to a string, for the default accessibility service to be
enabled by the accessibility shortcut. This service must be trusted, as it can be activated
without explicit consent of the user. If no accessibility service with the specified name
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e6358a37bded..de5fc9511010 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -174,7 +174,7 @@
<!-- height of the content margin on the bottom -->
<dimen name="notification_content_margin_bottom">16dp</dimen>
- <!-- The height of the background for a notification header on a group -->
+ <!-- The height of the background for a notification header on a group -->
<dimen name="notification_header_background_height">45.5dp</dimen>
<!-- Height of a small notification in the status bar -->
@@ -475,9 +475,6 @@
<dimen name="chooser_grid_padding">0dp</dimen>
- <item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
- <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
-
<item type="dimen" name="aerr_padding_list_top">15dp</item>
<item type="dimen" name="aerr_padding_list_bottom">8dp</item>
@@ -488,6 +485,9 @@
<!-- The default minimal size of a resizable task, in both dimensions. -->
<dimen name="default_minimal_size_resizable_task">220dp</dimen>
+ <!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
+ <dimen name="task_height_of_minimized_mode">80dp</dimen>
+
<!-- Minimum "smallest width" of the display for cascading menus to be enabled. -->
<dimen name="cascading_menus_min_smallest_width">720dp</dimen>
@@ -515,4 +515,9 @@
<dimen name="item_touch_helper_max_drag_scroll_per_frame">20dp</dimen>
<dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
<dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
+
+ <!-- The elevation of AutoFill fill window-->
+ <dimen name="autofill_fill_elevation">4dp</dimen>
+ <dimen name="autofill_fill_item_height">64dp</dimen>
+ <dimen name="autofill_fill_min_margin">16dp</dimen>
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index ebe577c73758..e3fdcece4ff1 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -149,6 +149,7 @@
<dimen name="timepicker_radial_picker_dimen">296dp</dimen>
<dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
<dimen name="timepicker_radial_picker_horizontal_margin">16dp</dimen>
+ <dimen name="timepicker_edit_text_size">24sp</dimen>
<!-- Used by RadialTimePicker in clock-style TimePicker. -->
<dimen name="timepicker_selector_radius">20dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 66dd1274632d..1b48469b100e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2777,7 +2777,7 @@
<public name="paddingVertical" />
<public name="visibleToInstantApps" />
<public name="keyboardNavigationCluster" />
- <public name="__removed0" />
+ <public name="targetProcess" />
<public name="nextClusterForward" />
<public name="__removed1" />
<public name="textColorError" />
@@ -2788,6 +2788,10 @@
<public name="restartOnConfigChanges" />
<public name="certDigest" />
<public name="splitName" />
+ <public name="colorMode" />
+ <public name="isolatedSplits" />
+ <public name="targetSandboxVersion" />
+ <public name="canCaptureFingerprintGestures" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2798,6 +2802,7 @@
</public-group>
<public type="attr" name="primaryContentAlpha" />
+ <public type="attr" name="secondaryContentAlpha" />
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index eece9fc36c30..19c5643cdaf8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -578,6 +578,9 @@
<!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
<string name="notification_header_divider_symbol" translatable="false">•</string>
+ <!-- The divider symbol between different parts of the notification header including spaces. not translatable [CHAR LIMIT=3] -->
+ <string name="notification_header_divider_symbol_with_spaces" translatable="false">" • "</string>
+
<!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
<string name="notification_hidden_text">Contents hidden</string>
@@ -678,6 +681,12 @@
<string name="capability_desc_canPerformGestures">Can tap, swipe, pinch, and perform other
gestures.</string>
+ <!-- Title for the capability of an accessibility service to capture fingerprint gestures. -->
+ <string name="capability_title_canCaptureFingerprintGestures">Fingerprint gestures</string>
+ <!-- Description for the capability of an accessibility service to perform gestures. -->
+ <string name="capability_desc_canCaptureFingerprintGestures">Can capture gestures performed on
+ the device's fingerprint sensor.</string>
+
<!-- Permissions -->
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3055,6 +3064,7 @@
<string name="adb_active_notification_title">USB debugging connected</string>
<!-- Message of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_message">Tap to disable USB debugging.</string>
+ <string name="adb_active_notification_message" product="tv">Select to disable USB debugging.</string>
<!-- Title of notification shown to indicate that bug report is being collected. -->
<string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
@@ -4457,4 +4467,24 @@
<!-- Category title for apps which are primarily productivity apps, such as cloud storage or workplace apps. [CHAR LIMIT=32] -->
<string name="app_category_productivity">Productivity</string>
+ <!-- Channel name for DeviceStorageMonitor notifications -->
+ <string name="device_storage_monitor_notification_channel">Device storage</string>
+ <!-- Channel name for UsbDeviceManager adb debugging notifications -->
+ <string name="adb_debugging_notification_channel_tv">USB debugging</string>
+
+ <!-- Label for the time picker hour input field. [CHAR LIMIT=20] -->
+ <string name="time_picker_hour_label">hour</string>
+ <!-- Label for the time picker minute input field. [CHAR LIMIT=20] -->
+ <string name="time_picker_minute_label">minute</string>
+ <!-- The title for the time picker dialog. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_header_text">Set time</string>
+ <!-- Error shown to the user if they type in invalid hour or minute in the time picker. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_input_error">Enter a valid time</string>
+ <!-- Label shown to the user in time picker to let them know that should type in time. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_prompt_label">Type in time</string>
+ <!-- Accessibility string used for describing the button in time picker that changes the dialog to text input mode. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_text_input_mode_description">Switch to text input mode for the time input.</string>
+ <!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
+
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 0b326e94382d..8f061a3862a3 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -426,6 +426,21 @@ please see styles_device_defaults.xml.
<item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
</style>
+ <style name="TextAppearance.Material.TimePicker.InputHeader" parent="TextAppearance.Material">
+ <item name="textSize">@dimen/text_size_display_1_material</item>
+ <item name="textColor">@color/white</item>
+ <item name="fontFamily">sans-serif-medium</item>
+ </style>
+
+ <style name="TextAppearance.Material.TimePicker.InputField" parent="TextAppearance.Material">
+ <item name="textSize">@dimen/timepicker_edit_text_size</item>
+ </style>
+
+ <style name="TextAppearance.Material.TimePicker.PromptLabel" parent="TextAppearance.Material">
+ <item name="textSize">@dimen/timepicker_text_size_normal</item>
+ <item name="fontFamily">sans-serif-medium</item>
+ </style>
+
<style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
<item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
<item name="textSize">@dimen/date_picker_year_label_size</item>
@@ -451,14 +466,14 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.Notification">
- <item name="textColor">@color/secondary_text_material_light</item>
+ <item name="textColor">@color/notification_secondary_text_color_light</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.Material.Notification.Reply" />
<style name="TextAppearance.Material.Notification.Title">
- <item name="textColor">@color/primary_text_default_material_light</item>
+ <item name="textColor">@color/notification_primary_text_color_light</item>
<item name="textSize">@dimen/notification_title_text_size</item>
</style>
@@ -467,7 +482,7 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.Notification.Info">
- <item name="textColor">@color/secondary_text_default_material_light</item>
+ <item name="textColor">@color/notification_secondary_text_color_light</item>
<item name="textSize">@dimen/notification_subtext_size</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 16356c73f79b..89269aad8277 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
<java-symbol type="id" name="permission_list" />
<java-symbol type="id" name="pickers" />
<java-symbol type="id" name="prefs" />
+ <java-symbol type="id" name="prefs_container" />
<java-symbol type="id" name="prefs_frame" />
<java-symbol type="id" name="prev" />
<java-symbol type="id" name="progress" />
@@ -254,6 +255,8 @@
<java-symbol type="bool" name="config_enableBurnInProtection" />
<java-symbol type="bool" name="config_hotswapCapable" />
<java-symbol type="bool" name="config_mms_content_disposition_support" />
+ <java-symbol type="string" name="config_ims_package" />
+ <java-symbol type="bool" name="config_dynamic_bind_ims" />
<java-symbol type="bool" name="config_networkSamplingWakesDevice" />
<java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" />
<java-symbol type="bool" name="config_sip_wifi_only" />
@@ -504,7 +507,6 @@
<java-symbol type="string" name="NetworkPreferenceSwitchTitle" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
- <java-symbol type="string" name="accessibility_enabled" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
<java-symbol type="string" name="activitychooserview_choose_application" />
<java-symbol type="string" name="activitychooserview_choose_application_error" />
@@ -601,7 +603,6 @@
<java-symbol type="string" name="contentServiceSync" />
<java-symbol type="string" name="contentServiceSyncNotificationTitle" />
<java-symbol type="string" name="contentServiceTooManyDeletesNotificationDesc" />
- <java-symbol type="string" name="continue_to_enable_accessibility" />
<java-symbol type="string" name="date_and_time" />
<java-symbol type="string" name="date_picker_decrement_day_button" />
<java-symbol type="string" name="date_picker_decrement_month_button" />
@@ -648,7 +649,6 @@
<java-symbol type="string" name="widget_default_class_name" />
<java-symbol type="string" name="emergency_calls_only" />
<java-symbol type="array" name="config_ephemeralResolverPackage" />
- <java-symbol type="string" name="enable_accessibility_canceled" />
<java-symbol type="string" name="eventTypeAnniversary" />
<java-symbol type="string" name="eventTypeBirthday" />
<java-symbol type="string" name="eventTypeCustom" />
@@ -1136,7 +1136,9 @@
<java-symbol type="string" name="config_ethernet_tcp_buffers" />
<java-symbol type="string" name="config_wifi_tcp_buffers" />
<java-symbol type="string" name="config_demoModeLauncherComponent" />
- <java-symbol type="string" name="config_demoModePassword" />
+ <java-symbol type="string" name="config_carrierDemoModePassword" />
+ <java-symbol type="string" name="config_carrierDemoModeSetting" />
+ <java-symbol type="string" name="config_carrierDemoModePackages" />
<java-symbol type="string" name="demo_starting_message" />
<java-symbol type="string" name="demo_restarting_message" />
<java-symbol type="string" name="conference_call" />
@@ -1254,6 +1256,11 @@
<java-symbol type="drawable" name="platlogo" />
<java-symbol type="drawable" name="stat_notify_sync_error" />
<java-symbol type="drawable" name="stat_notify_wifi_in_range" />
+ <java-symbol type="drawable" name="ic_wifi_signal_0" />
+ <java-symbol type="drawable" name="ic_wifi_signal_1" />
+ <java-symbol type="drawable" name="ic_wifi_signal_2" />
+ <java-symbol type="drawable" name="ic_wifi_signal_3" />
+ <java-symbol type="drawable" name="ic_wifi_signal_4" />
<java-symbol type="drawable" name="ic_signal_wifi_badged_0_bars" />
<java-symbol type="drawable" name="ic_signal_wifi_badged_1_bar" />
<java-symbol type="drawable" name="ic_signal_wifi_badged_2_bars" />
@@ -1447,7 +1454,6 @@
<java-symbol type="raw" name="color_fade_vert" />
<java-symbol type="raw" name="color_fade_frag" />
- <java-symbol type="raw" name="accessibility_gestures" />
<java-symbol type="raw" name="loaderror" />
<java-symbol type="raw" name="nodomain" />
@@ -1770,6 +1776,7 @@
<java-symbol type="id" name="replace_message" />
<java-symbol type="fraction" name="config_dimBehindFadeDuration" />
<java-symbol type="dimen" name="default_minimal_size_resizable_task" />
+ <java-symbol type="dimen" name="task_height_of_minimized_mode" />
<java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
<java-symbol type="fraction" name="config_autoBrightnessAdjustmentMaxGamma" />
<java-symbol type="integer" name="config_autoBrightnessAmbientLightHorizon"/>
@@ -1795,6 +1802,7 @@
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
+ <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
<java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
<java-symbol type="integer" name="config_notificationsBatteryLedOff" />
<java-symbol type="integer" name="config_notificationsBatteryLedOn" />
@@ -1874,6 +1882,7 @@
<java-symbol type="string" name="data_usage_wifi_limit_snoozed_title" />
<java-symbol type="string" name="data_usage_wifi_limit_title" />
<java-symbol type="string" name="default_wallpaper_component" />
+ <java-symbol type="string" name="device_storage_monitor_notification_channel" />
<java-symbol type="string" name="dlg_ok" />
<java-symbol type="string" name="dump_heap_notification" />
<java-symbol type="string" name="dump_heap_notification_detail" />
@@ -1906,6 +1915,7 @@
<java-symbol type="string" name="smv_process" />
<java-symbol type="string" name="tethered_notification_message" />
<java-symbol type="string" name="tethered_notification_title" />
+ <java-symbol type="string" name="adb_debugging_notification_channel_tv" />
<java-symbol type="string" name="usb_accessory_notification_title" />
<java-symbol type="string" name="usb_mtp_notification_title" />
<java-symbol type="string" name="usb_charging_notification_title" />
@@ -2786,8 +2796,14 @@
<java-symbol type="drawable" name="lockscreen_notselected" />
<java-symbol type="drawable" name="lockscreen_selected" />
+ <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
<java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+ <java-symbol type="color" name="notification_primary_text_color_light" />
+ <java-symbol type="color" name="notification_primary_text_color_dark" />
+ <java-symbol type="color" name="notification_secondary_text_color_light" />
+ <java-symbol type="color" name="notification_secondary_text_color_dark" />
+
<java-symbol type="string" name="app_category_game" />
<java-symbol type="string" name="app_category_audio" />
<java-symbol type="string" name="app_category_video" />
@@ -2799,7 +2815,7 @@
<java-symbol type="raw" name="fallback_categories" />
- <java-symbol type="attr" name="primaryContentAlpha" />
+ <java-symbol type="string" name="config_icon_mask" />
<!-- Accessibility Shortcut -->
<java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
@@ -2815,4 +2831,37 @@
<java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
<java-symbol type="dimen" name="item_touch_helper_swipe_escape_velocity"/>
<java-symbol type="dimen" name="item_touch_helper_swipe_escape_max_velocity"/>
+
+ <!-- com.android.server.autofill -->
+ <java-symbol type="dimen" name="autofill_fill_elevation" />
+ <java-symbol type="dimen" name="autofill_fill_item_height" />
+ <java-symbol type="dimen" name="autofill_fill_min_margin" />
+ <java-symbol type="layout" name="autofill_save"/>
+ <java-symbol type="id" name="autofill_save_title" />
+ <java-symbol type="id" name="autofill_save_no" />
+ <java-symbol type="id" name="autofill_save_yes" />
+
+ <!-- Accessibility fingerprint gestures -->
+ <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
+ <java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
+
+ <!-- Time picker -->
+ <java-symbol type="id" name="toggle_mode"/>
+ <java-symbol type="id" name="input_mode"/>
+ <java-symbol type="id" name="input_header"/>
+ <java-symbol type="id" name="input_separator"/>
+ <java-symbol type="id" name="input_hour"/>
+ <java-symbol type="id" name="input_minute"/>
+ <java-symbol type="id" name="am_pm_spinner"/>
+ <java-symbol type="id" name="label_hour"/>
+ <java-symbol type="id" name="label_minute"/>
+ <java-symbol type="id" name="label_error"/>
+ <java-symbol type="layout" name="time_picker_text_input_material"/>
+ <java-symbol type="drawable" name="btn_keyboard_key_material"/>
+ <java-symbol type="drawable" name="btn_event_material"/>
+ <java-symbol type="string" name="time_picker_text_input_mode_description"/>
+ <java-symbol type="string" name="time_picker_radial_mode_description"/>
+
+ <!-- resolver activity -->
+ <java-symbol type="drawable" name="resolver_icon_placeholder" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 3587fecb7b5d..b063baf386f4 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -49,6 +49,7 @@ please see themes_device_defaults.xml.
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
<item name="disabledAlpha">@dimen/disabled_alpha_material_dark</item>
<item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
@@ -59,7 +60,7 @@ please see themes_device_defaults.xml.
<item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
<item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
- <item name="textColorSecondary">@color/secondary_text_material_dark</item>
+ <item name="textColorSecondary">@color/text_color_secondary</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
<item name="textColorSecondaryActivated">@color/secondary_text_inverse_when_activated_material</item>
<item name="textColorTertiary">@color/secondary_text_material_dark</item>
@@ -415,6 +416,7 @@ please see themes_device_defaults.xml.
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
<item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
<item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_light</item>
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
@@ -424,7 +426,7 @@ please see themes_device_defaults.xml.
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
<item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
- <item name="textColorSecondary">@color/secondary_text_material_light</item>
+ <item name="textColorSecondary">@color/text_color_secondary</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorSecondaryActivated">@color/secondary_text_inverse_when_activated_material</item>
<item name="textColorTertiary">@color/secondary_text_material_light</item>
@@ -809,7 +811,7 @@ please see themes_device_defaults.xml.
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
- <item name="textColorSecondary">@color/secondary_text_material_light</item>
+ <item name="textColorSecondary">@color/text_color_secondary</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorTertiary">@color/secondary_text_material_light</item>
<item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
@@ -844,7 +846,7 @@ please see themes_device_defaults.xml.
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
- <item name="textColorSecondary">@color/secondary_text_material_dark</item>
+ <item name="textColorSecondary">@color/text_color_secondary</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
<item name="textColorTertiary">@color/secondary_text_material_dark</item>
<item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
diff --git a/core/tests/coretests/res/font/samplefont.ttf b/core/tests/coretests/res/font/samplefont.ttf
new file mode 100644
index 000000000000..285230293580
--- /dev/null
+++ b/core/tests/coretests/res/font/samplefont.ttf
Binary files differ
diff --git a/core/tests/coretests/res/font/samplefont2.ttf b/core/tests/coretests/res/font/samplefont2.ttf
new file mode 100644
index 000000000000..285230293580
--- /dev/null
+++ b/core/tests/coretests/res/font/samplefont2.ttf
Binary files differ
diff --git a/core/tests/coretests/res/font/samplefont3.ttf b/core/tests/coretests/res/font/samplefont3.ttf
new file mode 100644
index 000000000000..285230293580
--- /dev/null
+++ b/core/tests/coretests/res/font/samplefont3.ttf
Binary files differ
diff --git a/core/tests/coretests/res/font/samplefont4.ttf b/core/tests/coretests/res/font/samplefont4.ttf
new file mode 100644
index 000000000000..285230293580
--- /dev/null
+++ b/core/tests/coretests/res/font/samplefont4.ttf
Binary files differ
diff --git a/core/tests/coretests/res/font/samplexmlfont.xml b/core/tests/coretests/res/font/samplexmlfont.xml
new file mode 100644
index 000000000000..bb813e1f9c1b
--- /dev/null
+++ b/core/tests/coretests/res/font/samplexmlfont.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/samplefont" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/samplefont2" />
+ <font android:fontStyle="normal" android:fontWeight="800" android:font="@font/samplefont3" />
+ <font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
+</font-family> \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
new file mode 100644
index 000000000000..380a28774108
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.res;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.FontConfig;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Tests for {@link FontResourcesParser}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontResourcesParserTest {
+
+ private Instrumentation mInstrumentation;
+ private Resources mResources;
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mResources = mInstrumentation.getContext().getResources();
+ }
+
+ @Test
+ public void testParse() throws XmlPullParserException, IOException {
+ XmlResourceParser parser = mResources.getXml(R.font.samplexmlfont);
+
+ FontConfig result = FontResourcesParser.parse(parser, mResources);
+
+ assertNotNull(result);
+ List<FontConfig.Family> families = result.getFamilies();
+ assertEquals(1, families.size());
+ List<FontConfig.Font> fonts = families.get(0).getFonts();
+ assertEquals(4, fonts.size());
+ FontConfig.Font font1 = fonts.get(0);
+ assertEquals(400, font1.getWeight());
+ assertEquals(false, font1.isItalic());
+ assertEquals("res/font/samplefont.ttf", font1.getFontName());
+ FontConfig.Font font2 = fonts.get(1);
+ assertEquals(400, font2.getWeight());
+ assertEquals(true, font2.isItalic());
+ assertEquals("res/font/samplefont2.ttf", font2.getFontName());
+ FontConfig.Font font3 = fonts.get(2);
+ assertEquals(800, font3.getWeight());
+ assertEquals(false, font3.isItalic());
+ assertEquals("res/font/samplefont3.ttf", font3.getFontName());
+ FontConfig.Font font4 = fonts.get(3);
+ assertEquals(800, font4.getWeight());
+ assertEquals(true, font4.isItalic());
+ assertEquals("res/font/samplefont4.ttf", font4.getFontName());
+ }
+}
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index 0f75cb67795f..b9c973fb09cd 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -100,6 +100,7 @@ public class LogMakerTest extends TestCase {
builder.addTaggedData(2, 123);
builder.addTaggedData(3, 123L);
builder.addTaggedData(4, 123.0F);
+ builder.addTaggedData(5, null);
Object[] out = builder.serialize();
assertEquals("onetwothree", out[1]);
assertEquals(123, out[3]);
@@ -114,6 +115,13 @@ public class LogMakerTest extends TestCase {
assertEquals(10, out[1]);
}
+ public void testClearData() {
+ LogMaker builder = new LogMaker(0);
+ builder.addTaggedData(1, "onetwothree");
+ builder.clearTaggedData(1);
+ assertEquals(null, builder.getTaggedData(1));
+ }
+
public void testGiantLogOmitted() {
LogMaker badBuilder = new LogMaker(0);
StringBuilder b = new StringBuilder();
@@ -124,4 +132,78 @@ public class LogMakerTest extends TestCase {
assertTrue(badBuilder.serialize().length < LogMaker.MAX_SERIALIZED_SIZE);
}
+ public void testIdentityEquality() {
+ LogMaker a = new LogMaker(0);
+ a.addTaggedData(1, "onetwothree");
+ a.addTaggedData(2, 123);
+ a.addTaggedData(3, 123L);
+
+ assertTrue("objects should be equal to themselves", a.isSubsetOf(a));
+ }
+
+ public void testExactEquality() {
+ LogMaker a = new LogMaker(0);
+ a.addTaggedData(1, "onetwothree");
+ a.addTaggedData(2, 123);
+ a.addTaggedData(3, 123L);
+ LogMaker b = new LogMaker(0);
+ b.addTaggedData(1, "onetwothree");
+ b.addTaggedData(2, 123);
+ b.addTaggedData(3, 123L);
+
+ assertTrue("deep equality should be true", a.isSubsetOf(b));
+ assertTrue("deep equality shoudl be true", b.isSubsetOf(a));
+ }
+
+ public void testSubsetEquality() {
+ LogMaker a = new LogMaker(0);
+ a.addTaggedData(1, "onetwothree");
+ a.addTaggedData(2, 123);
+ LogMaker b = new LogMaker(0);
+ b.addTaggedData(1, "onetwothree");
+ b.addTaggedData(2, 123);
+ b.addTaggedData(3, 123L);
+
+ assertTrue("a is a strict subset of b", a.isSubsetOf(b));
+ assertTrue("b is not a strict subset of a", !b.isSubsetOf(a));
+ }
+
+ public void testInequality() {
+ LogMaker a = new LogMaker(0);
+ a.addTaggedData(1, "onetwofour");
+ a.addTaggedData(2, 1234);
+ LogMaker b = new LogMaker(0);
+ b.addTaggedData(1, "onetwothree");
+ b.addTaggedData(2, 123);
+ b.addTaggedData(3, 123L);
+
+ assertTrue("a is not a subset of b", !a.isSubsetOf(b));
+ assertTrue("b is not a subset of a", !b.isSubsetOf(a));
+ }
+
+ public void testWildcardEquality() {
+ LogMaker empty = new LogMaker(0);
+ empty.clearTaggedData(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY); //dirty trick
+ LogMaker b = new LogMaker(0);
+ b.addTaggedData(1, "onetwothree");
+ b.addTaggedData(2, 123);
+ b.addTaggedData(3, 123L);
+
+ assertTrue("empty builder is a subset of anything", empty.isSubsetOf(b));
+ }
+
+ public void testNullEquality() {
+ LogMaker a = new LogMaker(0);
+ a.addTaggedData(1, "onetwofour");
+ a.addTaggedData(2, 1234);
+
+ assertTrue("a is not a subset of null", !a.isSubsetOf(null));
+ }
+
+ public void testMajorCategory() {
+ LogMaker a = new LogMaker(1);
+ LogMaker b = new LogMaker(2);
+ assertFalse(a.isSubsetOf(b));
+ assertFalse(b.isSubsetOf(a));
+ }
}
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
new file mode 100644
index 000000000000..1afe9da2bfe6
--- /dev/null
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -0,0 +1,75 @@
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
+
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiSsid;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkKeyTest {
+ private static final String VALID_SSID = "\"ssid1\"";
+ private static final String VALID_BSSID = "00:00:00:00:00:00";
+ @Mock private WifiInfo mWifiInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void createFromWifi_nullInput() throws Exception {
+ assertNull(NetworkKey.createFromWifiInfo(null));
+ }
+
+ @Test
+ public void createFromWifi_nullSsid() throws Exception {
+ when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
+ assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+ }
+
+ @Test
+ public void createFromWifi_emptySsid() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn("");
+ when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
+ assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+ }
+
+ @Test
+ public void createFromWifi_noneSsid() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+ when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
+ assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+ }
+
+ @Test
+ public void createFromWifi_nullBssid() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
+ assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+ }
+
+ @Test
+ public void createFromWifi_emptyBssid() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
+ when(mWifiInfo.getBSSID()).thenReturn("");
+ assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+ }
+
+ @Test
+ public void createFromWifi_validWifiInfo() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
+ when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
+
+ NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
+ final NetworkKey actual = NetworkKey.createFromWifiInfo(mWifiInfo);
+ assertEquals(expected, actual);
+ }
+}
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 5bfff26b0813..ce5d3ef665bb 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -19,6 +19,7 @@ package android.net;
import static org.mockito.Mockito.when;
import android.Manifest.permission;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -30,13 +31,16 @@ import android.content.res.Resources;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.provider.Settings;
import android.test.InstrumentationTestCase;
+
import com.android.internal.R;
-import java.util.List;
+
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
@Mock private Context mMockContext;
@Mock private PackageManager mMockPm;
@@ -114,39 +118,40 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksDenied("package1");
- mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ mockScoreNetworksDenied(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
}
public void testGetNetworkRecommendationProviderData_available() throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
- mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
NetworkScorerAppData appData =
mNetworkScorerAppManager.getNetworkRecommendationProviderData();
assertNotNull(appData);
- assertEquals("package1", appData.packageName);
+ assertEquals(recoComponent, appData.getRecommendationServiceComponent());
assertEquals(924, appData.packageUid);
- assertEquals(".RecommendationService", appData.recommendationServiceClassName);
}
public void testGetActiveScorer_providerAvailable() throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
- mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
ContentResolver cr = mTargetContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNotNull(activeScorer);
- assertEquals("package1", activeScorer.packageName);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
assertEquals(924, activeScorer.packageUid);
- assertEquals(".RecommendationService", activeScorer.recommendationServiceClassName);
}
public void testGetActiveScorer_providerNotAvailable()
@@ -159,9 +164,10 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
}
public void testGetActiveScorer_recommendationsDisabled() throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
- mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
ContentResolver cr = mTargetContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
@@ -187,11 +193,11 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
.thenReturn(PackageManager.PERMISSION_DENIED);
}
- private void mockRecommendationServiceAvailable(final String packageName, int packageUid) {
+ private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
final ResolveInfo serviceInfo = new ResolveInfo();
serviceInfo.serviceInfo = new ServiceInfo();
- serviceInfo.serviceInfo.name = ".RecommendationService";
- serviceInfo.serviceInfo.packageName = packageName;
+ serviceInfo.serviceInfo.name = compName.getClassName();
+ serviceInfo.serviceInfo.packageName = compName.getPackageName();
serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
@@ -203,7 +209,7 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
Intent intent = (Intent) object;
return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
.equals(intent.getAction())
- && packageName.equals(intent.getPackage());
+ && compName.getPackageName().equals(intent.getPackage());
}
}), Mockito.eq(flags))).thenReturn(serviceInfo);
}
diff --git a/core/tests/coretests/src/android/net/RecommendationRequestTest.java b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
index bd2550073dd3..e2e68834de7b 100644
--- a/core/tests/coretests/src/android/net/RecommendationRequestTest.java
+++ b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
@@ -96,7 +96,7 @@ public class RecommendationRequestTest extends AndroidTestCase {
RecommendationRequest parceled = passThroughParcel(request);
- assertEquals(0, parceled.getLastSelectedNetworkId());
+ assertEquals(-1, parceled.getLastSelectedNetworkId());
assertEquals(0, parceled.getLastSelectedNetworkTimestamp());
}
diff --git a/core/tests/coretests/src/android/provider/SettingsTest.java b/core/tests/coretests/src/android/provider/SettingsTest.java
new file mode 100644
index 000000000000..1ff2056498f1
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/SettingsTest.java
@@ -0,0 +1,550 @@
+/*
+ * 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.provider;
+
+import static com.google.android.collect.Sets.newHashSet;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isPublic;
+import static java.lang.reflect.Modifier.isStatic;
+
+import android.annotation.TargetApi;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for Settings. */
+@TargetApi(25)
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SettingsTest {
+
+ /**
+ * The following blacklists contain settings that should *not* be backed up and restored to
+ * another device. As a general rule, anything that is not user configurable should be
+ * blacklisted (and conversely, things that *are* user configurable *should* be backed up)
+ */
+ private static final Set<String> BACKUP_BLACKLISTED_SYSTEM_SETTINGS =
+ newHashSet(
+ Settings.System.ADVANCED_SETTINGS, // candidate for backup?
+ Settings.System.ALARM_ALERT, // backup candidate?
+ Settings.System.ALARM_ALERT_CACHE, // internal cache
+ Settings.System.APPEND_FOR_LAST_AUDIBLE, // suffix deprecated since API 2
+ Settings.System.EGG_MODE, // I am the lolrus
+ Settings.System.END_BUTTON_BEHAVIOR, // bug?
+ Settings.System
+ .HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, // candidate for backup?
+ Settings.System.LOCKSCREEN_DISABLED, // ?
+ Settings.System.MEDIA_BUTTON_RECEIVER, // candidate for backup?
+ Settings.System.MUTE_STREAMS_AFFECTED, // candidate for backup?
+ Settings.System.NOTIFICATION_LIGHT_PULSE, // candidate for backup?
+ Settings.System.NOTIFICATION_SOUND_CACHE, // internal cache
+ Settings.System.POINTER_LOCATION, // backup candidate?
+ Settings.System.RINGTONE_CACHE, // internal cache
+ Settings.System.SCREEN_BRIGHTNESS_FOR_VR, // bug?
+ Settings.System.SETUP_WIZARD_HAS_RUN, // Only used by SuW
+ Settings.System.SHOW_GTALK_SERVICE_STATUS, // candidate for backup?
+ Settings.System.SHOW_TOUCHES, // bug?
+ Settings.System.SIP_ADDRESS_ONLY, // value, not a setting
+ Settings.System.SIP_ALWAYS, // value, not a setting
+ Settings.System.SYSTEM_LOCALES, // bug?
+ Settings.System.USER_ROTATION, // backup candidate?
+ Settings.System.VIBRATE_IN_SILENT, // deprecated?
+ Settings.System.VIBRATE_ON, // candidate for backup?
+ Settings.System.VOLUME_ALARM, // deprecated since API 2?
+ Settings.System.VOLUME_BLUETOOTH_SCO, // deprecated since API 2?
+ Settings.System.VOLUME_MASTER, // candidate for backup?
+ Settings.System.VOLUME_MUSIC, // deprecated since API 2?
+ Settings.System.VOLUME_NOTIFICATION, // deprecated since API 2?
+ Settings.System.VOLUME_RING, // deprecated since API 2?
+ Settings.System.VOLUME_SYSTEM, // deprecated since API 2?
+ Settings.System.VOLUME_VOICE, // deprecated since API 2?
+ Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
+ Settings.System.WINDOW_ORIENTATION_LISTENER_LOG // used for debugging only
+ );
+
+ private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS =
+ newHashSet(
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
+ Settings.Global.ADB_ENABLED,
+ Settings.Global.ADD_USERS_WHEN_LOCKED,
+ Settings.Global.AIRPLANE_MODE_ON,
+ Settings.Global.AIRPLANE_MODE_RADIOS,
+ Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+ Settings.Global.ALARM_MANAGER_CONSTANTS,
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
+ Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+ Settings.Global.ANIMATOR_DURATION_SCALE,
+ Settings.Global.APN_DB_UPDATE_CONTENT_URL,
+ Settings.Global.APN_DB_UPDATE_METADATA_URL,
+ Settings.Global.APP_IDLE_CONSTANTS,
+ Settings.Global.ASSISTED_GPS_ENABLED,
+ Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+ Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
+ Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
+ Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
+ Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+ Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST,
+ Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_ON, // Candidate for backup?
+ Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+ Settings.Global.BOOT_COUNT,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
+ Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ Settings.Global.CAPTIVE_PORTAL_MODE,
+ Settings.Global.CAPTIVE_PORTAL_SERVER,
+ Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
+ Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
+ Settings.Global.CAR_DOCK_SOUND,
+ Settings.Global.CARRIER_APP_WHITELIST,
+ Settings.Global.CAR_UNDOCK_SOUND,
+ Settings.Global.CDMA_CELL_BROADCAST_SMS,
+ Settings.Global.CDMA_ROAMING_MODE,
+ Settings.Global.CDMA_SUBSCRIPTION_MODE,
+ Settings.Global.CELL_ON,
+ Settings.Global.CERT_PIN_UPDATE_CONTENT_URL,
+ Settings.Global.CERT_PIN_UPDATE_METADATA_URL,
+ Settings.Global.COMPATIBILITY_MODE,
+ Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+ Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
+ Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
+ Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
+ Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ Settings.Global.DATABASE_DOWNGRADE_REASON,
+ Settings.Global.DATA_ROAMING,
+ Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
+ Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
+ Settings.Global.DEBUG_APP,
+ Settings.Global.DEBUG_VIEW_ATTRIBUTES,
+ Settings.Global.DEFAULT_DNS_SERVER,
+ Settings.Global.DEFAULT_INSTALL_LOCATION,
+ Settings.Global.DESK_DOCK_SOUND,
+ Settings.Global.DESK_UNDOCK_SOUND,
+ Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
+ Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
+ Settings.Global.DEVELOPMENT_FORCE_RTL,
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
+ Settings.Global.DEVICE_DEMO_MODE,
+ Settings.Global.DEVICE_IDLE_CONSTANTS,
+ Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH,
+ Settings.Global.DEVICE_NAME,
+ Settings.Global.DEVICE_PROVISIONED,
+ Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
+ Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+ Settings.Global.DISPLAY_SCALING_FORCE,
+ Settings.Global.DISPLAY_SIZE_FORCED,
+ Settings.Global.DNS_RESOLVER_MAX_SAMPLES,
+ Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
+ Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
+ Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+ Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
+ Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
+ Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
+ Settings.Global.DROPBOX_AGE_SECONDS,
+ Settings.Global.DROPBOX_MAX_FILES,
+ Settings.Global.DROPBOX_QUOTA_KB,
+ Settings.Global.DROPBOX_QUOTA_PERCENT,
+ Settings.Global.DROPBOX_RESERVE_PERCENT,
+ Settings.Global.DROPBOX_TAG_PREFIX,
+ Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
+ Settings.Global.ENABLE_CELLULAR_ON_BOOT,
+ Settings.Global.ENABLE_DISKSTATS_LOGGING,
+ Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+ Settings.Global.ENHANCED_4G_MODE_ENABLED,
+ Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
+ Settings.Global.ERROR_LOGCAT_PREFIX,
+ Settings.Global.FANCY_IME_ANIMATIONS,
+ Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
+ Settings.Global.FSTRIM_MANDATORY_INTERVAL,
+ Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ Settings.Global.GLOBAL_HTTP_PROXY_HOST,
+ Settings.Global.GLOBAL_HTTP_PROXY_PAC,
+ Settings.Global.GLOBAL_HTTP_PROXY_PORT,
+ Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+ Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+ Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
+ Settings.Global.HDMI_CONTROL_ENABLED,
+ Settings.Global.HDMI_SYSTEM_AUDIO_ENABLED,
+ Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+ Settings.Global.HTTP_PROXY,
+ Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
+ Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
+ Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
+ Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
+ Settings.Global.JOB_SCHEDULER_CONSTANTS,
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
+ Settings.Global.LOCK_SOUND,
+ Settings.Global.LOW_BATTERY_SOUND,
+ Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
+ Settings.Global.LOW_POWER_MODE,
+ Settings.Global.LTE_SERVICE_FORCED,
+ Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
+ Settings.Global.MDC_INITIAL_MAX_RETRY,
+ Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
+ Settings.Global.MHL_POWER_CHARGE_ENABLED,
+ Settings.Global.MOBILE_DATA, // Candidate for backup?
+ Settings.Global.MOBILE_DATA_ALWAYS_ON,
+ Settings.Global.MODE_RINGER,
+ Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
+ Settings.Global.MULTI_SIM_SMS_PROMPT,
+ Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
+ Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
+ Settings.Global.MULTI_SIM_VOICE_PROMPT,
+ Settings.Global.NETSTATS_DEV_BUCKET_DURATION,
+ Settings.Global.NETSTATS_DEV_DELETE_AGE,
+ Settings.Global.NETSTATS_DEV_PERSIST_BYTES,
+ Settings.Global.NETSTATS_DEV_ROTATE_AGE,
+ Settings.Global.NETSTATS_ENABLED,
+ Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES,
+ Settings.Global.NETSTATS_POLL_INTERVAL,
+ Settings.Global.NETSTATS_SAMPLE_ENABLED,
+ Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE,
+ Settings.Global.NETSTATS_UID_BUCKET_DURATION,
+ Settings.Global.NETSTATS_UID_DELETE_AGE,
+ Settings.Global.NETSTATS_UID_PERSIST_BYTES,
+ Settings.Global.NETSTATS_UID_ROTATE_AGE,
+ Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION,
+ Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
+ Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
+ Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
+ Settings.Global.NETWORK_AVOID_BAD_WIFI,
+ Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+ Settings.Global.NETWORK_PREFERENCE,
+ Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
+ Settings.Global.NETWORK_SCORER_APP,
+ Settings.Global.NETWORK_SCORING_PROVISIONED,
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+ Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+ Settings.Global.NEW_CONTACT_AGGREGATOR,
+ Settings.Global.NITZ_UPDATE_DIFF,
+ Settings.Global.NITZ_UPDATE_SPACING,
+ Settings.Global.NSD_ON,
+ Settings.Global.NTP_SERVER,
+ Settings.Global.NTP_TIMEOUT,
+ Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
+ Settings.Global.OVERLAY_DISPLAY_DEVICES,
+ Settings.Global.PAC_CHANGE_DELAY,
+ Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+ Settings.Global.PACKAGE_VERIFIER_ENABLE,
+ Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
+ Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE,
+ Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
+ Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT,
+ Settings.Global.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
+ Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
+ Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
+ Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS,
+ Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
+ Settings.Global.POLICY_CONTROL,
+ Settings.Global.POWER_MANAGER_CONSTANTS,
+ Settings.Global.PREFERRED_NETWORK_MODE,
+ Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
+ Settings.Global.RADIO_BLUETOOTH,
+ Settings.Global.RADIO_CELL,
+ Settings.Global.RADIO_NFC,
+ Settings.Global.RADIO_WIFI,
+ Settings.Global.RADIO_WIMAX,
+ Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
+ Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
+ Settings.Global.RETAIL_DEMO_MODE_CONSTANTS,
+ Settings.Global.SAFE_BOOT_DISALLOWED,
+ Settings.Global.SAMPLING_PROFILER_MS,
+ Settings.Global.SELINUX_STATUS,
+ Settings.Global.SELINUX_UPDATE_CONTENT_URL,
+ Settings.Global.SELINUX_UPDATE_METADATA_URL,
+ Settings.Global.SEND_ACTION_APP_ERROR,
+ Settings.Global.SET_GLOBAL_HTTP_PROXY,
+ Settings.Global.SET_INSTALL_LOCATION,
+ Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL,
+ Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
+ Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
+ Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+ Settings.Global.SHOW_TEMPERATURE_WARNING,
+ Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
+ Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
+ Settings.Global.SMS_SHORT_CODE_CONFIRMATION,
+ Settings.Global.SMS_SHORT_CODE_RULE,
+ Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL,
+ Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL,
+ Settings.Global.STORAGE_BENCHMARK_INTERVAL,
+ Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
+ Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
+ Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
+ Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
+ Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+ Settings.Global.TCP_DEFAULT_INIT_RWND,
+ Settings.Global.TETHER_DUN_APN,
+ Settings.Global.TETHER_DUN_REQUIRED,
+ Settings.Global.TETHER_SUPPORTED,
+ Settings.Global.THEATER_MODE_ON,
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ Settings.Global.TRUSTED_SOUND,
+ Settings.Global.TZINFO_UPDATE_CONTENT_URL,
+ Settings.Global.TZINFO_UPDATE_METADATA_URL,
+ Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
+ Settings.Global.UNLOCK_SOUND,
+ Settings.Global.USE_GOOGLE_MAIL,
+ Settings.Global.VT_IMS_ENABLED,
+ Settings.Global.WAIT_FOR_DEBUGGER,
+ Settings.Global.WARNING_TEMPERATURE,
+ Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
+ Settings.Global.WEBVIEW_MULTIPROCESS,
+ Settings.Global.WEBVIEW_PROVIDER,
+ Settings.Global.WFC_IMS_ENABLED,
+ Settings.Global.WFC_IMS_MODE,
+ Settings.Global.WFC_IMS_ROAMING_ENABLED,
+ Settings.Global.WFC_IMS_ROAMING_MODE,
+ Settings.Global.WIFI_BADGING_THRESHOLDS,
+ Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
+ Settings.Global.WIFI_COUNTRY_CODE,
+ Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
+ Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON,
+ Settings.Global.WIFI_DISPLAY_ON,
+ Settings.Global.WIFI_DISPLAY_WPS_CONFIG,
+ Settings.Global.WIFI_ENHANCED_AUTO_JOIN,
+ Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
+ Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
+ Settings.Global.WIFI_FREQUENCY_BAND,
+ Settings.Global.WIFI_IDLE_MS,
+ Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
+ Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ Settings.Global.WIFI_NETWORK_SHOW_RSSI,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ Settings.Global.WIFI_ON,
+ Settings.Global.WIFI_P2P_DEVICE_NAME,
+ Settings.Global.WIFI_REENABLE_DELAY_MS,
+ Settings.Global.WIFI_SAVED_STATE,
+ Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+ Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
+ Settings.Global.WIFI_SLEEP_POLICY,
+ Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
+ Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
+ Settings.Global.WIFI_WATCHDOG_ON,
+ Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ Settings.Global.WINDOW_ANIMATION_SCALE,
+ Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+ Settings.Global.WTF_IS_FATAL,
+ Settings.Global.ZEN_MODE,
+ Settings.Global.ZEN_MODE_CONFIG_ETAG,
+ Settings.Global.ZEN_MODE_RINGER_LEVEL);
+
+ private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
+ newHashSet(
+ Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
+ Settings.Secure.ALWAYS_ON_VPN_APP,
+ Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+ Settings.Secure.ANDROID_ID,
+ Settings.Secure.ANR_SHOW_BACKGROUND,
+ Settings.Secure.ASSISTANT,
+ Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
+ Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
+ Settings.Secure.ASSIST_STRUCTURE_ENABLED,
+ Settings.Secure.AUTO_FILL_SERVICE,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DOWNLOADS_DAYS_TO_RETAIN,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
+ Settings.Secure.BACKUP_AUTO_RESTORE,
+ Settings.Secure.BACKUP_ENABLED,
+ Settings.Secure.BACKUP_PROVISIONED,
+ Settings.Secure.BACKUP_TRANSPORT,
+ Settings.Secure.BLUETOOTH_HCI_LOG,
+ Settings.Secure.CARRIER_APPS_HANDLED,
+ Settings.Secure.COMPLETED_CATEGORY_PREFIX,
+ Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ Settings.Secure.DEMO_USER_SETUP_COMPLETE,
+ Settings.Secure.DEVICE_PAIRED,
+ Settings.Secure.DIALER_DEFAULT_APPLICATION,
+ Settings.Secure.DISABLED_PRINT_SERVICES,
+ Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
+ Settings.Secure.DISPLAY_DENSITY_FORCED,
+ Settings.Secure.DOWNLOADS_BACKUP_ALLOW_METERED, // Candidate?
+ Settings.Secure.DOWNLOADS_BACKUP_CHARGING_ONLY, // Candidate?
+ Settings.Secure.DOWNLOADS_BACKUP_ENABLED, // Candidate?
+ Settings.Secure.DOZE_ALWAYS_ON,
+ Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
+ Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ Settings.Secure.ENABLED_PRINT_SERVICES,
+ Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
+ Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
+ Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY,
+ Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
+ Settings.Secure.INSTALL_NON_MARKET_APPS,
+ Settings.Secure.LAST_SETUP_SHOWN,
+ Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_PREVIOUS_MODE,
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, // Candidate?
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
+ Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, // Candidate?
+ Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
+ Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH,
+ Settings.Secure.MULTI_PRESS_TIMEOUT,
+ Settings.Secure.NFC_PAYMENT_FOREGROUND,
+ Settings.Secure.PACKAGE_VERIFIER_STATE,
+ Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
+ Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
+ Settings.Secure.PAYMENT_SERVICE_SEARCH_URI,
+ Settings.Secure.PRINT_SERVICE_SEARCH_URI,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, // Candidate?
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, // Candidate?
+ Settings.Secure.SCREENSAVER_COMPONENTS,
+ Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, // Candidate?
+ Settings.Secure.SCREENSAVER_ENABLED, // Candidate?
+ Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY,
+ Settings.Secure.SEARCH_MAX_RESULTS_PER_SOURCE,
+ Settings.Secure.SEARCH_MAX_RESULTS_TO_DISPLAY,
+ Settings.Secure.SEARCH_MAX_SHORTCUTS_RETURNED,
+ Settings.Secure.SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS,
+ Settings.Secure.SEARCH_MAX_STAT_AGE_MILLIS,
+ Settings.Secure.SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING,
+ Settings.Secure.SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING,
+ Settings.Secure.SEARCH_NUM_PROMOTED_SOURCES,
+ Settings.Secure.SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT,
+ Settings.Secure.SEARCH_PREFILL_MILLIS,
+ Settings.Secure.SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS,
+ Settings.Secure.SEARCH_QUERY_THREAD_CORE_POOL_SIZE,
+ Settings.Secure.SEARCH_QUERY_THREAD_MAX_POOL_SIZE,
+ Settings.Secure.SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE,
+ Settings.Secure.SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE,
+ Settings.Secure.SEARCH_SOURCE_TIMEOUT_MILLIS,
+ Settings.Secure.SEARCH_THREAD_KEEPALIVE_SECONDS,
+ Settings.Secure.SEARCH_WEB_RESULTS_OVERRIDE_LIMIT,
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
+ Settings.Secure.SETTINGS_CLASSNAME,
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, // candidate?
+ Settings.Secure.SKIP_FIRST_USE_HINTS, // candidate?
+ Settings.Secure.SMS_DEFAULT_APPLICATION,
+ Settings.Secure.TRUST_AGENTS_INITIALIZED,
+ Settings.Secure.TV_INPUT_CUSTOM_LABELS,
+ Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
+ Settings.Secure.UI_NIGHT_MODE, // candidate?
+ Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS,
+ Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED,
+ Settings.Secure.USER_SETUP_COMPLETE,
+ Settings.Secure.VOICE_INTERACTION_SERVICE,
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ Settings.Secure.VR_DISPLAY_MODE, // Candidate?
+ Settings.Secure.WEB_ACTION_ENABLED);
+
+ @Test
+ public void systemSettingsBackedUpOrBlacklisted() {
+ checkSettingsBackedUpOrBlacklisted(
+ getCandidateSettings(Settings.System.class),
+ newHashSet(Settings.System.SETTINGS_TO_BACKUP),
+ BACKUP_BLACKLISTED_SYSTEM_SETTINGS);
+ }
+
+ @Test
+ public void globalSettingsBackedUpOrBlacklisted() {
+ checkSettingsBackedUpOrBlacklisted(
+ getCandidateSettings(Settings.Global.class),
+ newHashSet(Settings.Global.SETTINGS_TO_BACKUP),
+ BACKUP_BLACKLISTED_GLOBAL_SETTINGS);
+ }
+
+ @Test
+ public void secureSettingsBackedUpOrBlacklisted() {
+ checkSettingsBackedUpOrBlacklisted(
+ getCandidateSettings(Settings.Secure.class),
+ newHashSet(Settings.Secure.SETTINGS_TO_BACKUP),
+ BACKUP_BLACKLISTED_SECURE_SETTINGS);
+ }
+
+ private static void checkSettingsBackedUpOrBlacklisted(
+ Set<String> settings, Set<String> settingsToBackup, Set<String> blacklist) {
+ Set<String> settingsNotBackedUp = difference(settings, settingsToBackup);
+ Set<String> settingsNotBackedUpOrBlacklisted = difference(settingsNotBackedUp, blacklist);
+ assertThat(
+ "Settings not backed up or blacklisted",
+ settingsNotBackedUpOrBlacklisted,
+ is(empty()));
+
+ assertThat(
+ "blacklisted settings backed up",
+ intersect(settingsToBackup, blacklist),
+ is(empty()));
+ }
+
+ private static Set<String> getCandidateSettings(Class<? extends Settings.NameValueTable> clazz) {
+ HashSet<String> result = new HashSet<String>();
+ for (Field field : clazz.getDeclaredFields()) {
+ if (looksLikeValidSetting(field)) {
+ try {
+ result.add((String) field.get(null));
+ } catch (IllegalAccessException e) {
+ // Impossible for public fields
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static boolean looksLikeValidSetting(Field field) {
+ int modifiers = field.getModifiers();
+ return isPublic(modifiers)
+ && isStatic(modifiers)
+ && isFinal(modifiers)
+ && field.getType() == String.class
+ && field.getAnnotation(Deprecated.class) == null;
+ }
+
+ private static <T> Set<T> difference(Set<T> s1, Set<T> s2) {
+ HashSet<T> result = new HashSet<T>(s1);
+ result.removeAll(s2);
+ return result;
+ }
+
+ private static <T> Set<T> intersect(Set<T> s1, Set<T> s2) {
+ HashSet<T> result = new HashSet<T>(s1);
+ result.retainAll(s2);
+ return result;
+ }
+
+}
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
index dc6042311095..7e7e8151cc50 100644
--- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -21,7 +21,7 @@ import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.transition.Transition.TransitionListener;
-import android.transition.Transition.TransitionListenerAdapter;
+import android.transition.TransitionListenerAdapter;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index a73f5a64c2cc..44fcd13b5313 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -16,9 +16,17 @@
package android.view;
+import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.frameworks.coretests.R;
public class ViewAttachTest extends
ActivityInstrumentationTestCase2<ViewAttachTestActivity> {
@@ -51,4 +59,38 @@ public class ViewAttachTest extends
SystemClock.sleep(250);
}
}
+
+ /**
+ * Make sure that on any attached view, if the view is full-screen and hosted
+ * on a round device, the round scrollbars will be displayed even if the activity
+ * window is offset.
+ *
+ * @throws Throwable
+ */
+ @UiThreadTest
+ public void testRoundScrollbars() throws Throwable {
+ final ViewAttachTestActivity activity = getActivity();
+ final View rootView = activity.getWindow().getDecorView();
+ final WindowManager.LayoutParams params =
+ new WindowManager.LayoutParams(
+ rootView.getWidth(),
+ rootView.getHeight(),
+ 50, /* xPosition */
+ 0, /* yPosition */
+ WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT);
+
+ rootView.setLayoutParams(params);
+
+ View contentView = activity.findViewById(R.id.view_attach_view);
+ boolean shouldDrawRoundScrollbars = contentView.shouldDrawRoundScrollbar();
+
+ if (activity.getResources().getConfiguration().isScreenRound()) {
+ assertTrue(shouldDrawRoundScrollbars);
+ } else {
+ // Never draw round scrollbars on non-round devices.
+ assertFalse(shouldDrawRoundScrollbars);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/ViewInvalidateTest.java b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
index 4db70ec4a1c4..9de7d9c6b375 100644
--- a/core/tests/coretests/src/android/view/ViewInvalidateTest.java
+++ b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
@@ -219,7 +219,27 @@ public class ViewInvalidateTest {
public void testInvalidateChild_childHardwareLayer() throws Throwable {
WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
// do in runnable, so tree won't be dirty
- mChild.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ });
+
+ mActivityRule.runOnUiThread(() -> {
+ validateInvalFlags(mParent,
+ View.PFLAG_DRAWING_CACHE_VALID,
+ View.PFLAG_DRAWN);
+
+ mParent.invalidateChild(mChild, new Rect(0, 0, 1, 1));
+
+ validateInvalFlags(mParent,
+ View.PFLAG_DIRTY,
+ View.PFLAG_DRAWN); // Note: note invalidated, since HW damage handled in native
+ });
+ }
+
+ @Test
+ public void testInvalidateChild_childSoftwareLayer() throws Throwable {
+ WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
+ // do in runnable, so tree won't be dirty
+ mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
});
mActivityRule.runOnUiThread(() -> {
@@ -232,7 +252,7 @@ public class ViewInvalidateTest {
validateInvalFlags(mParent,
View.PFLAG_DIRTY,
View.PFLAG_DRAWN,
- View.PFLAG_INVALIDATED);
+ View.PFLAG_INVALIDATED); // Note: invalidated, since SW damage handled here
});
}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index b276d16adae8..7edab008c4ef 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -40,7 +40,6 @@ import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.pressKey;
import static android.support.test.espresso.action.ViewActions.replaceText;
-import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
@@ -78,16 +77,16 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testTypedTextIsOnScreen() throws Exception {
final String helloWorld = "Hello world!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ // We use replaceText instead of typeTextIntoFocusedView to input text to avoid
+ // unintentional interactions with software keyboard.
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
}
public void testPositionCursorAtTextAtIndex() throws Exception {
final String helloWorld = "Hello world!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
// Delete text at specified index and see if we got the right one.
@@ -99,7 +98,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
// Arabic text. The expected cursorable boundary is
// | \u0623 \u064F | \u067A | \u0633 \u0652 |
final String text = "\u0623\u064F\u067A\u0633\u0652";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
@@ -119,7 +117,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testPositionCursorAtTextAtIndex_devanagari() throws Exception {
// Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
final String text = "\u0915\u093E";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
@@ -133,7 +130,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testLongPressToSelect() throws Exception {
final String helloWorld = "Hello Kirk!";
onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(
longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
@@ -142,8 +139,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testLongPressEmptySpace() throws Exception {
final String helloWorld = "Hello big round sun!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
// Move cursor somewhere else
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
// Long-press at end of line.
@@ -156,8 +152,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testLongPressAndDragToSelect() throws Exception {
final String helloWorld = "Hello little handsome boy!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(
longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
@@ -166,7 +161,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testLongPressAndDragToSelect_emoji() throws Exception {
final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
@@ -180,8 +174,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testDragAndDrop() throws Exception {
final String text = "abc def ghi.";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
onView(withId(R.id.textview)).perform(
@@ -201,8 +194,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testDoubleTapToSelect() throws Exception {
final String helloWorld = "Hello SuetYi!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
+
onView(withId(R.id.textview)).perform(
doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
@@ -211,8 +204,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testDoubleTapAndDragToSelect() throws Exception {
final String helloWorld = "Hello young beautiful girl!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(
doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
@@ -221,7 +213,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testDoubleTapAndDragToSelect_multiLine() throws Exception {
final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(
doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
@@ -230,8 +221,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectBackwordsByTouch() throws Exception {
final String helloWorld = "Hello king of the Jungle!";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(replaceText(helloWorld));
onView(withId(R.id.textview)).perform(
doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
@@ -240,9 +230,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testToolbarAppearsAfterSelection() throws Exception {
final String text = "Toolbar appears after selection.";
- onView(withId(R.id.textview)).perform(click());
assertFloatingToolbarIsNotDisplayed();
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(
longPressOnTextAtIndex(text.indexOf("appears")));
@@ -250,7 +239,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
assertFloatingToolbarIsDisplayed();
final String text2 = "Toolbar disappears after typing text.";
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2));
+ onView(withId(R.id.textview)).perform(replaceText(text2));
+ sleepForFloatingToolbarPopup();
assertFloatingToolbarIsNotDisplayed();
}
@@ -271,7 +261,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
});
getInstrumentation().waitForIdleSync();
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView("test"));
+ onView(withId(R.id.textview)).perform(replaceText("test"));
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
clickFloatingToolbarItem(
getActivity().getString(com.android.internal.R.string.cut));
@@ -283,8 +273,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testToolbarAndInsertionHandle() throws Exception {
final String text = "text";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
assertFloatingToolbarIsNotDisplayed();
@@ -302,8 +291,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testToolbarAndSelectionHandle() throws Exception {
final String text = "abcd efg hijk";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
sleepForFloatingToolbarPopup();
@@ -337,8 +325,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testInsertionHandle() throws Exception {
final String text = "abcd efg hijk ";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
@@ -356,8 +343,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testInsertionHandle_multiLine() throws Exception {
final String text = "abcd\n" + "efg\n" + "hijk\n";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
@@ -375,12 +361,11 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles() throws Exception {
final String text = "abcd efg hijk lmn";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(replaceText(text));
assertNoSelectionHandles();
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
onHandleView(com.android.internal.R.id.selection_start_handle)
.check(matches(isDisplayed()));
@@ -399,12 +384,11 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_bidi() throws Exception {
final String text = "abc \u0621\u0622\u0623 def";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
assertNoSelectionHandles();
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0622')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
onHandleView(com.android.internal.R.id.selection_start_handle)
.check(matches(isDisplayed()));
@@ -423,7 +407,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
onHandleView(com.android.internal.R.id.selection_start_handle)
- .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623') + 1,
+ .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623'),
false));
onView(withId(R.id.textview)).check(hasSelection("\u0623"));
@@ -443,9 +427,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_multiLine() throws Exception {
final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -466,7 +449,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
}
public void testSelectionHandles_multiLine_japanese() throws Exception {
- onView(withId(R.id.textview)).perform(click());
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100; ++i) {
@@ -477,8 +459,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
break;
}
}
-
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(3));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(3));
final int lineEnd = textView.getLayout().getLineEnd(0);
onHandleView(com.android.internal.R.id.selection_end_handle)
@@ -492,10 +473,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
+ "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
+ "\u0639\u063A\u063B";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
- onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0634')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634')));
final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -521,16 +500,15 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception {
final String text = "abcd efg hijk lmn";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
onHandleView(com.android.internal.R.id.selection_start_handle)
.perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
onView(withId(R.id.textview)).check(hasSelection("g"));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
onHandleView(com.android.internal.R.id.selection_end_handle)
.perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
onView(withId(R.id.textview)).check(hasSelection("e"));
@@ -538,16 +516,15 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() throws Exception {
final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
onHandleView(com.android.internal.R.id.selection_start_handle)
.perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
onView(withId(R.id.textview)).check(hasSelection("k"));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
onHandleView(com.android.internal.R.id.selection_end_handle)
.perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
onView(withId(R.id.textview)).check(hasSelection("h"));
@@ -555,9 +532,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_snapToWordBoundary() throws Exception {
final String text = "abcd efg hijk lmn opqr";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
@@ -582,7 +558,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
.perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
onHandleView(com.android.internal.R.id.selection_end_handle)
.perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
@@ -607,9 +584,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSelectionHandles_snapToWordBoundary_multiLine() throws Exception {
final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
- onView(withId(R.id.textview)).perform(click());
- onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('m')));
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m')));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
@@ -625,7 +601,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
.perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
onView(withId(R.id.textview)).check(hasSelection("lmn"));
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
onHandleView(com.android.internal.R.id.selection_end_handle)
.perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
@@ -642,7 +618,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testSetSelectionAndActionMode() throws Exception {
final String text = "abc def";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
@@ -654,7 +629,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
assertFloatingToolbarIsNotDisplayed();
// Make sure that "Select All" is included in the selection action mode when the entire text
// is not selected.
- onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('e')));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
sleepForFloatingToolbarPopup();
assertFloatingToolbarIsDisplayed();
// Changing the selection range by API should not interrupt the selection action mode.
@@ -705,7 +680,6 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
public void testTransientState() throws Exception {
final String text = "abc def";
- onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(replaceText(text));
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index 97ea88557cdc..d89dc637f5e0 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -81,35 +81,23 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
public void testVoiceImes() throws Exception {
// locale: en_US
assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
+ "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme");
- assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
- assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
+ "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
"DummyNonDefaultAutoVoiceIme1");
// locale: en_GB
assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
- assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme");
- assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
+ "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
+ "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
"DummyNonDefaultAutoVoiceIme1");
// locale: ja_JP
assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
- assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
- !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme");
- assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
+ "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
- IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
+ "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
"DummyNonDefaultAutoVoiceIme1");
}
@@ -117,54 +105,35 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
public void testKeyboardImes() throws Exception {
// locale: en_US
assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.latin",
- "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
// locale: en_GB
assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.latin",
- "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
// locale: en_IN
assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.hindi",
+ "com.android.apps.inputmethod.hindi",
"com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
// locale: hi
assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.hindi",
- "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin",
+ "com.android.apps.inputmethod.voice");
// locale: ja_JP
assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.japanese",
- "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.japanese", "com.android.apps.inputmethod.voice");
// locale: zh_CN
assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.pinyin",
- "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.pinyin", "com.android.apps.inputmethod.voice");
// locale: zh_TW
// Note: In this case, no IME is suitable for the system locale. Hence we will pick up a
// fallback IME regardless of the "default" attribute.
assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
- !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin");
- assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
- IS_SYSTEM_READY, "com.android.apps.inputmethod.latin",
- "com.android.apps.inputmethod.voice");
+ "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
}
@SmallTest
@@ -792,10 +761,10 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
}
private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
- final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) {
+ final Locale systemLocale, String... expectedImeNames) {
final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
final String[] actualImeNames = getPackageNames(
- InputMethodUtils.getDefaultEnabledImes(context, isSystemReady, preinstalledImes));
+ InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes));
assertEquals(expectedImeNames.length, actualImeNames.length);
for (int i = 0; i < expectedImeNames.length; ++i) {
assertEquals(expectedImeNames[i], actualImeNames[i]);
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
deleted file mode 100644
index 5a7766b816b7..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
+++ /dev/null
@@ -1,91 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-public class CounterParserTest extends ParserTest {
-
- public CounterParserTest() {
- mParser = new CounterParser();
- }
-
- public void testGoodData() throws Throwable {
- String name = "foo";
- int value = 5;
- Object[] objects = new Object[2];
- objects[0] = name;
- objects[1] = value;
-
- validateGoodData(name, value, objects);
- }
-
- private void validateGoodData(String name, int value, Object[] objects) {
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, times(1)).incrementBy(mNameCaptor.capture(), mCountCaptor.capture());
-
- assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
- assertEquals(value, mCountCaptor.getValue().intValue());
- }
-
- public void testMissingName() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testWrongTypes() throws Throwable {
- String name = "foo";
- int value = 5;
- Object[] objects = new Object[2];
- objects[0] = value;
- objects[1] = name;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreMissingInput() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- String name = "foo";
- int value = 5;
- Object[] objects = new Object[3];
- objects[0] = name;
- objects[1] = value;
- objects[2] = "foo";
-
- validateGoodData(name, value, objects);
- }
-
-
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
deleted file mode 100644
index 1bd9d83c5094..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
+++ /dev/null
@@ -1,90 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-public class HistogramParserTest extends ParserTest {
-
- public HistogramParserTest() {
- mParser = new HistogramParser();
- }
-
- public void testGoodData() throws Throwable {
- String name = "foo";
- int bucket = 5;
- Object[] objects = new Object[2];
- objects[0] = name;
- objects[1] = bucket;
-
- validateGoodData(name, bucket, objects);
- }
-
- private void validateGoodData(String name, int bucket, Object[] objects) {
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, times(1))
- .incrementIntHistogram(mNameCaptor.capture(), mCountCaptor.capture());
-
- assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
- assertEquals(bucket, mCountCaptor.getValue().intValue());
- }
-
- public void testMissingName() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testWrongTypes() throws Throwable {
- String name = "foo";
- int value = 5;
- Object[] objects = new Object[2];
- objects[0] = value;
- objects[1] = name;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreMissingInput() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- String name = "foo";
- int bucket = 5;
- Object[] objects = new Object[3];
- objects[0] = name;
- objects[1] = bucket;
- objects[2] = "foo";
-
- validateGoodData(name, bucket, objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
deleted file mode 100644
index c023b572493f..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
+++ /dev/null
@@ -1,100 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class LockscreenGestureParserTest extends ParserTest {
-
- public LockscreenGestureParserTest() {
- mParser = new LockscreenGestureParser();
- }
-
- public void testSwipeUpUnlock() throws Throwable {
- validate(MetricsEvent.ACTION_LS_UNLOCK, 1, 359, 6382);
- }
-
- public void testSwipeToShade() throws Throwable {
- validate(MetricsEvent.ACTION_LS_SHADE, 2, 324, 0);
- }
-
- public void testTapLockHint() throws Throwable {
- validate(MetricsEvent.ACTION_LS_HINT, 3, 0, 0);
- }
-
- public void testCamera() throws Throwable {
- validate(MetricsEvent.ACTION_LS_CAMERA, 4, 223, 1756);
- }
-
- public void testDialer() throws Throwable {
- validate(MetricsEvent.ACTION_LS_DIALER, 5, 163, 861);
- }
-
- public void testTapToLock() throws Throwable {
- validate(MetricsEvent.ACTION_LS_LOCK, 6, 0, 0);
- }
-
- public void testTapOnNotification() throws Throwable {
- validate(MetricsEvent.ACTION_LS_NOTE, 7, 0, 0);
- }
-
- public void testLockscreenQuickSettings() throws Throwable {
- validate(MetricsEvent.ACTION_LS_QS, 8, 284, 3824);
- }
-
- public void testShadePullQuickSettings() throws Throwable {
- validate(MetricsEvent.ACTION_SHADE_QS_PULL, 9, 175, 3444);
- }
-
- public void testShadeTapQuickSettings() throws Throwable {
- validate(MetricsEvent.ACTION_SHADE_QS_TAP, 10, 0, 0);
- }
-
- private void validate(int view, int type, int len, int vel) {
- int t = 1000;
- Object[] objects = new Object[3];
- objects[0] = type;
- objects[1] = len;
- objects[2] = vel;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[4];
- objects[0] = 1;
- objects[1] = 0;
- objects[2] = 0;
- objects[3] = "foo";
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent((LogMaker) anyObject());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
deleted file mode 100644
index f05205d8d1ee..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
+++ /dev/null
@@ -1,123 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationActionClickedParserTest extends ParserTest {
-
- public NotificationActionClickedParserTest() {
- mParser = new NotificationActionClickedParser();
- }
-
- public void testGoodData() throws Throwable {
- int t = 1000;
- int index = 1;
- Object[] objects = new Object[2];
- objects[0] = mKey;
- objects[1] = index;
-
- validateGoodData(t, "", index, objects);
- }
-
- public void testTagged() throws Throwable {
- int t = 1000;
- int index = 1;
- Object[] objects = new Object[2];
- objects[0] = mTaggedKey;
- objects[1] = index;
-
- validateGoodData(t, mTag, index, objects);
- }
-
- private LogMaker validateGoodData(int t, String tag, int index, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ITEM_ACTION, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, tag);
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- assertEquals(index, proto.getSubtype());
- return proto;
- }
-
- public void testMissingData() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testWrongType() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = 2;
- objects[1] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testBadKey() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = "foo";
- objects[1] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testMncTimestamps() throws Throwable {
- int t = 1000;
- int index = 1;
- Object[] objects = new Object[5];
- objects[0] = mKey;
- objects[1] = index;
- objects[2] = mSinceCreationMillis;
- objects[3] = mSinceUpdateMillis;
- objects[4] = mSinceVisibleMillis;
-
- LogMaker proto = validateGoodData(t, "", index, objects);
- validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
- mSinceVisibleMillis);
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int index = 1;
- Object[] objects = new Object[6];
- objects[0] = mKey;
- objects[1] = index;
- objects[2] = mSinceCreationMillis;
- objects[3] = mSinceUpdateMillis;
- objects[4] = mSinceVisibleMillis;
- objects[5] = "foo";
-
- validateGoodData(t, "", index, objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
deleted file mode 100644
index 7771e84f3cbd..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
+++ /dev/null
@@ -1,135 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import org.mockito.ArgumentCaptor;
-
-public class NotificationAlertParserTest extends ParserTest {
- protected ArgumentCaptor<Boolean> mConfigCaptor;
-
- private final int mTime = 1000;
-
- public NotificationAlertParserTest() {
- mParser = new NotificationAlertParser();
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mConfigCaptor = ArgumentCaptor.forClass(Boolean.class);
- when(mLogger.getConfig(anyString())).thenReturn(false);
- }
-
- public void testBuzzOnly() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 1;
- objects[2] = 0;
- objects[3] = 0;
-
- validateInteraction(true, false, false, objects);
- }
-
- public void testBeepOnly() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 0;
- objects[2] = 1;
- objects[3] = 0;
-
- validateInteraction(false, true, false, objects);
- }
-
- public void testBlinkOnly() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 0;
- objects[2] = 0;
- objects[3] = 1;
-
- validateInteraction(false, false, true, objects);
- }
-
- public void testBuzzBlink() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 1;
- objects[2] = 0;
- objects[3] = 1;
-
- validateInteraction(true, false, true, objects);
- }
-
- public void testBeepBlink() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 0;
- objects[2] = 1;
- objects[3] = 1;
-
- validateInteraction(false, true, true, objects);
- }
-
- public void testIgnoreExtraArgs() throws Throwable {
- Object[] objects = new Object[5];
- objects[0] = mTaggedKey;
- objects[1] = 0;
- objects[2] = 1;
- objects[3] = 1;
- objects[4] = "foo";
-
- validateInteraction(false, true, true, objects);
- }
-
- private void validateInteraction(boolean buzz, boolean beep, boolean blink, Object[] objects) {
- int flags = 0;
- int counts = 0;
- if (buzz) {
- counts++;
- flags |= NotificationAlertParser.BUZZ;
- }
- if (beep) {
- counts++;
- flags |= NotificationAlertParser.BEEP;
- }
- if (blink) {
- counts++;
- flags |= NotificationAlertParser.BLINK;
- }
-
- mParser.parseEvent(mLogger, mTime, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(mTime, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ALERT, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, mTag);
- assertEquals(flags, proto.getSubtype());
- assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
-
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
deleted file mode 100644
index 77b2ed6924c5..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
+++ /dev/null
@@ -1,198 +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.internal.logging.legacy;
-
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationCanceledParserTest extends ParserTest {
-
- public NotificationCanceledParserTest() {
- mParser = new NotificationCanceledParser();
- }
-
- public void testGoodProto() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[2];
- objects[0] = mKey;
- objects[1] = reason;
-
- validateGoodData(t, "", reason, objects);
- }
-
- public void testTagged() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[2];
- objects[0] = mTaggedKey;
- objects[1] = reason;
-
- validateGoodData(t, mTag, reason, objects);
- }
-
- private void validateGoodData(int t, String tag, int reason, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, tag);
- assertEquals(MetricsEvent.TYPE_DISMISS, proto.getType());
- assertEquals(reason, proto.getSubtype());
- }
-
- public void testLifetime() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = reason;
- objects[2] = mSinceCreationMillis;
-
- validateTimers(t, objects, mSinceCreationMillis, 0, 0);
- }
-
- public void testExposure() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[4];
- objects[0] = mKey;
- objects[1] = reason;
- objects[2] = mSinceCreationMillis;
- objects[3] = mSinceVisibleMillis;
-
-
- validateTimers(t, objects, mSinceCreationMillis, 0, mSinceVisibleMillis);
- }
-
- public void testFreshness() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[5];
- objects[0] = mKey;
- objects[1] = reason;
- objects[2] = mSinceCreationMillis;
- objects[3] = mSinceUpdateMillis;
- objects[4] = mSinceVisibleMillis;
-
- validateTimers(t, objects, mSinceCreationMillis, mSinceUpdateMillis, mSinceVisibleMillis);
- }
-
- private void validateTimers(int t, Object[] objects, int life, int freshness, int exposure) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- validateNotificationTimes(proto, life, freshness, exposure);
- }
-
- public void verifyReason(int reason, boolean intentional, boolean important, String counter)
- throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = mKey;
- objects[1] = reason;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- if (intentional) {
- verify(mLogger, times(1)).addEvent((LogMaker) anyObject());
- }
- }
-
- public void testDelegateCancel() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL,
- true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
- }
-
- public void testDelegateCancelAll() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL_ALL,
- true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
- }
-
- public void testListenerCancel() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL,
- false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
- }
-
- public void testListenerCancelAll() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL_ALL,
- false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
- }
-
- public void testDelegateClick() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_DELEGATE_CLICK,
- true, true, TronCounters.TRON_NOTE_DISMISS_BY_CLICK);
- }
-
- public void testBanned() throws Throwable {
- verifyReason(NotificationCanceledParser.REASON_PACKAGE_BANNED,
- false, true, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
- }
-
- public void testUnknownReason() throws Throwable {
- verifyReason(1001010, false, false, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
- }
-
- public void testMissingData() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testWrongType() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = 2;
- objects[1] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testBadKey() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = "foo";
- objects[1] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = reason;
- objects[2] = "foo";
-
- validateGoodData(t, "", reason, objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java
deleted file mode 100644
index cc6513233fe2..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java
+++ /dev/null
@@ -1,114 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationClickedParserTest extends ParserTest {
-
- public NotificationClickedParserTest() {
- mParser = new NotificationClickedParser();
- }
-
- public void testGoodData() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[1];
- objects[0] = mKey;
-
- validateGoodData(t, "", objects);
- }
-
- public void testTagged() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[1];
- objects[0] = mTaggedKey;
-
- validateGoodData(t, mTag, objects);
- }
-
- private LogMaker validateGoodData(int t, String tag, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, tag);
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- assertEquals(0, proto.getSubtype());
- return proto;
- }
-
- public void testMissingKey() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testWrongType() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = 5;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testBadKey() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = "foo";
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testMncTimestamps() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[4];
- objects[0] = mKey;
- objects[1] = mSinceCreationMillis;
- objects[2] = mSinceUpdateMillis;
- objects[3] = mSinceVisibleMillis;
-
- LogMaker proto = validateGoodData(t, "", objects);
- validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
- mSinceVisibleMillis);
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[5];
- objects[0] = mKey;
- objects[1] = mSinceCreationMillis;
- objects[2] = mSinceUpdateMillis;
- objects[3] = mSinceVisibleMillis;
- objects[4] = "foo";
-
- validateGoodData(t, "", objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
deleted file mode 100644
index f337f914ba58..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
+++ /dev/null
@@ -1,175 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationExpansionParserTest extends ParserTest {
-
- public NotificationExpansionParserTest() {
- mParser = new NotificationExpansionParser();
- }
-
- public void testExpandedByUser() throws Throwable {
- int t = 1000;
- int byUser = 1;
- int expanded = 1;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
-
- validateGoodData(t, "", objects);
- }
-
- public void testTagged() throws Throwable {
- int t = 1000;
- int byUser = 1;
- int expanded = 1;
- Object[] objects = new Object[3];
- objects[0] = mTaggedKey;
- objects[1] = byUser;
- objects[2] = expanded;
-
- validateGoodData(t, mTag, objects);
- }
-
- private LogMaker validateGoodData(int t, String tag, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, tag);
- assertEquals(MetricsEvent.TYPE_DETAIL, proto.getType());
- return proto;
- }
-
- public void testAutoExpand() throws Throwable {
- int t = 1000;
- int byUser = 0;
- int expanded = 1;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testCollapsedByUser() throws Throwable {
- int t = 1000;
- int byUser = 1;
- int expanded = 0;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testAutoCollapsed() throws Throwable {
- int t = 1000;
- int byUser = 0;
- int expanded = 0;
- Object[] objects = new Object[3];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testMissingData() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testWrongType() throws Throwable {
- Object[] objects = new Object[3];
- objects[0] = 2;
- objects[1] = 5;
- objects[2] = 7;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testBadKey() throws Throwable {
- Object[] objects = new Object[3];
- objects[0] = "foo";
- objects[1] = 5;
- objects[2] = 2;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- }
-
- public void testMncTimestamps() throws Throwable {
- int t = 1000;
- int byUser = 1;
- int expanded = 1;
- Object[] objects = new Object[6];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
- objects[3] = mSinceCreationMillis;
- objects[4] = mSinceUpdateMillis;
- objects[5] = mSinceVisibleMillis;
-
- LogMaker proto = validateGoodData(t, "", objects);
- validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
- mSinceVisibleMillis);
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int byUser = 1;
- int expanded = 1;
- Object[] objects = new Object[7];
- objects[0] = mKey;
- objects[1] = byUser;
- objects[2] = expanded;
- objects[3] = mSinceCreationMillis;
- objects[4] = mSinceUpdateMillis;
- objects[5] = mSinceVisibleMillis;
- objects[6] = "foo";
-
- validateGoodData(t, "", objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java
deleted file mode 100644
index b50970044b2c..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java
+++ /dev/null
@@ -1,65 +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.internal.logging.legacy;
-
-import android.test.InstrumentationTestCase;
-
-public class NotificationKeyTest extends InstrumentationTestCase {
-
- private final NotificationKey mKey;
-
- public NotificationKeyTest() {
- mKey = new NotificationKey();
- }
-
- public void testGoodKey() throws Throwable {
- assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|null|10090"));
-
- assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
- assertEquals("", mKey.mTag);
- assertEquals(31338, mKey.mId);
- assertEquals(1, mKey.mUser);
- assertEquals(10090, mKey.mUid);
- }
-
- public void testTaggedKey() throws Throwable {
- assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|foo|10090"));
-
- assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
- assertEquals("foo", mKey.mTag);
- assertEquals(31338, mKey.mId);
- assertEquals(1, mKey.mUser);
- assertEquals(10090, mKey.mUid);
- }
-
- public void testEmptyTag() throws Throwable {
- assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338||10090"));
-
- assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
- assertEquals("", mKey.mTag);
- assertEquals(31338, mKey.mId);
- assertEquals(1, mKey.mUser);
- assertEquals(10090, mKey.mUid);
- }
-
- public void testBadKeys() throws Throwable {
- assertFalse(mKey.parse(null));
- assertFalse(mKey.parse(""));
- assertFalse(mKey.parse("foo")); // not a key
- assertFalse(mKey.parse("1|com.android.example.notificationshowcase|31338|null"));
- assertFalse(mKey.parse("bar|com.android.example.notificationshowcase|31338|null|10090"));
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
deleted file mode 100644
index ce6f1f4bd531..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
+++ /dev/null
@@ -1,56 +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.internal.logging.legacy;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationPanelHiddenParserTest extends ParserTest {
-
- public NotificationPanelHiddenParserTest() {
- mParser = new NotificationPanelHiddenParser();
- }
-
- public void testNoInput() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[0];
-
- validateGoodData(t, objects);
-
- }
-
- public void testIgnoreExtraneousInput() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = "nothing to see here";
-
- validateGoodData(0, objects);
- }
-
- private void validateGoodData(int t, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
deleted file mode 100644
index 9e15812edb10..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
+++ /dev/null
@@ -1,84 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationPanelRevealedParserTest extends ParserTest {
-
- public NotificationPanelRevealedParserTest() {
- mParser = new NotificationPanelRevealedParser();
- }
-
- public void testLollipopInput() throws Throwable {
- int t = 1000;
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
- }
-
- public void testMncData() throws Throwable {
- int t = 1000;
- int n = 5;
- Object[] objects = new Object[1];
- objects[0] = Integer.valueOf(n);
-
- validateMncData(t, n, objects);
- }
-
- private void validateMncData(int t, int n, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
- }
-
- public void testBadInput() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = "This is not the integer you're looking for.";
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, times(1)).addEvent((LogMaker) anyObject());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int n = 5;
- Object[] objects = new Object[2];
- objects[0] = Integer.valueOf(n);
- objects[1] = "foo";
-
- validateMncData(t, n, objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
deleted file mode 100644
index 7fef929e6765..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
+++ /dev/null
@@ -1,92 +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.internal.logging.legacy;
-
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class NotificationVisibilityParserTest extends ParserTest {
- private final int mCreationTime = 23124;
- private final int mUpdateTime = 3412;
- private final int mTime = 1000;
-
- public NotificationVisibilityParserTest() {
- mParser = new NotificationVisibilityParser();
- }
-
- public void testReveal() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 1;
- objects[2] = mCreationTime;
- objects[3] = mUpdateTime;
-
- validateInteraction(true, mUpdateTime, 0, objects);
- }
-
- public void testHide() throws Throwable {
- Object[] objects = new Object[4];
- objects[0] = mTaggedKey;
- objects[1] = 0;
- objects[2] = mCreationTime;
- objects[3] = mUpdateTime;
-
- validateInteraction(false, mUpdateTime, 0, objects);
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- Object[] objects = new Object[5];
- objects[0] = mTaggedKey;
- objects[1] = 1;
- objects[2] = mCreationTime;
- objects[3] = mUpdateTime;
- objects[4] = "foo";
-
- validateInteraction(true, mUpdateTime, 0, objects);
- }
-
- public void testMarshmallowIndexData() throws Throwable {
- Object[] objects = new Object[6];
- objects[0] = mTaggedKey;
- objects[1] = 1;
- objects[2] = mCreationTime;
- objects[3] = mUpdateTime;
- objects[4] = 0;
- objects[5] = 3;
-
- validateInteraction(true, mUpdateTime, 3, objects);
- }
-
- private void validateInteraction(boolean visible, int freshness, int index, Object[] objects) {
- mParser.parseEvent(mLogger, mTime, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(mTime, proto.getTimestamp());
- assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
- assertEquals(mKeyPackage, proto.getPackageName());
- validateNotificationIdAndTag(proto, mId, mTag);
- validateNotificationTimes(proto, mCreationTime, mUpdateTime);
- assertEquals(index, proto.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
- assertEquals(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE, proto.getType());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
deleted file mode 100644
index def9628e7fbd..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
+++ /dev/null
@@ -1,73 +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.internal.logging.legacy;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class StatusBarStateParserTest extends ParserTest {
-
- public StatusBarStateParserTest() {
- mParser = new StatusBarStateParser();
- }
-
- public void testLockScreen() throws Throwable {
- validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 1, "1,1,0,0,1,0");
- }
-
- public void testBounce() throws Throwable {
- validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "1,1,0,1,1,0");
- }
-
- public void testUnlock() throws Throwable {
- validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_CLOSE, 1, "0,0,0,0,1,0");
- }
-
- public void testSecure() throws Throwable {
- validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "2,1,0,1,1,0");
- }
-
- public void testInsecure() throws Throwable {
- validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0");
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0,5");
- }
-
- private void validate(int view, int type, int subType, String log) {
- String[] parts = log.split(",");
- int t = 1000;
- Object[] objects = new Object[parts.length];
- for (int i = 0; i < parts.length; i++) {
- objects[i] = Integer.valueOf(parts[i]);
- }
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(type, proto.getType());
- assertEquals(subType, proto.getSubtype());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
deleted file mode 100644
index 2ad76c13e76b..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
+++ /dev/null
@@ -1,167 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class SysuiActionParserTest extends ParserTest {
-
- public SysuiActionParserTest() {
- mParser = new SysuiActionParser();
- }
-
- public void testGoodDatal() throws Throwable {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[1];
- objects[0] = view;
-
- validateGoodData(t, view, objects);
- }
-
- private void validateGoodData(int t, int view, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- }
-
- public void testGoodDataWithPackage() throws Throwable {
- int t = 1000;
- int view = 10;
- String packageName = "com.foo";
- Object[] objects = new Object[2];
- objects[0] = view;
- objects[1] = packageName;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(packageName, proto.getPackageName());
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- }
-
- public void testGoodDataWithTrue() throws Throwable {
- validateSubType(Boolean.toString(true), 1);
- }
-
- public void testGoodDataWithFalse() throws Throwable {
- validateSubType(Boolean.toString(false), 0);
- }
-
- public void testGoodDataWithIntZero() throws Throwable {
- validateSubType(Integer.toString(0), 0);
- }
-
- public void testGoodDataWithIntONe() throws Throwable {
- validateSubType(Integer.toString(1), 1);
- }
-
- public void testGoodDataWithIntTwo() throws Throwable {
- validateSubType(Integer.toString(2), 2);
- }
-
- public void testGoodDataWithNegativeInt() throws Throwable {
- validateSubType(Integer.toString(-1), -1);
- }
-
- public void testGoodDataWithIntLarge() throws Throwable {
- validateSubType(Integer.toString(120312), 120312);
- }
-
- public void testGoodDataWithNegativeIntLarge() throws Throwable {
- validateSubType(Integer.toString(-120312), -120312);
- }
-
- private void validateSubType(String arg, int expectedValue) {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[2];
- objects[0] = view;
- objects[1] = arg;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(expectedValue, proto.getSubtype());
- assertNull(proto.getPackageName());
- assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
- }
-
- public void testIgnoreMissingInput() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreWrongInputs() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = "nothing to see here";
- objects[1] = 10;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreStringViewInput() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = "this is not the input you are looking for";
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[2];
- objects[0] = view;
- objects[1] = "foo";
-
- validateGoodData(t, view, objects);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java
deleted file mode 100644
index 64d69a499901..000000000000
--- a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java
+++ /dev/null
@@ -1,122 +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.internal.logging.legacy;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class SysuiViewVisibilityParserTest extends ParserTest {
-
- public SysuiViewVisibilityParserTest() {
- mParser = new SysuiViewVisibilityParser();
- }
-
- public void testViewReveal() throws Throwable {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[2];
- objects[0] = view;
- objects[1] = 100;
-
- validateViewReveal(t, view, objects);
- }
-
- private void validateViewReveal(int t, int view, Object[] objects) {
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(t, proto.getTimestamp());
- assertEquals(view, proto.getCategory());
- assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
- }
-
- public void testViewHidden() throws Throwable {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[2];
- objects[0] = view;
- objects[1] = 0;
-
- mParser.parseEvent(mLogger, t, objects);
-
- verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
-
- LogMaker proto = mProtoCaptor.getValue();
- assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
- }
-
- public void testIgnoreMissingInput() throws Throwable {
- Object[] objects = new Object[0];
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreStringInARgOne() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = "nothing to see here";
- objects[1] = 100;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreStringInArgTwo() throws Throwable {
- Object[] objects = new Object[2];
- objects[0] = 100;
- objects[1] = "nothing to see here";
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testOneInput() throws Throwable {
- Object[] objects = new Object[1];
- objects[0] = 100;
-
- mParser.parseEvent(mLogger, 0, objects);
-
- verify(mLogger, never()).addEvent((LogMaker) anyObject());
- verify(mLogger, never()).incrementBy(anyString(), anyInt());
- }
-
- public void testIgnoreUnexpectedData() throws Throwable {
- int t = 1000;
- int view = 10;
- Object[] objects = new Object[3];
- objects[0] = view;
- objects[1] = 100;
- objects[2] = "foo";
-
- validateViewReveal(t, view, objects);
- }
-}
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index 2f18de0b1797..62ef25b1af0d 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -21,5 +21,6 @@
delivery restrictions. -->
<allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" />
<allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
+ <allow-implicit-broadcast action="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
</config>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index e46f1666282e..9cdc66047662 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -155,6 +155,7 @@
<assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
+ <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c5961abc1523..039ab1f5e24b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -132,6 +132,7 @@ applications that come with the platform
<permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/>
<permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
+ <permission name="android.permission.BIND_IMS_SERVICE"/>
<permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/>
<permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
@@ -339,4 +340,4 @@ applications that come with the platform
<permission name="android.permission.CONTROL_VPN"/>
</privapp-permissions>
-</permissions> \ No newline at end of file
+</permissions>
diff --git a/data/keyboards/qwerty.kl b/data/keyboards/qwerty.kl
index 41860076e0e4..2fd99abbb9fe 100644
--- a/data/keyboards/qwerty.kl
+++ b/data/keyboards/qwerty.kl
@@ -123,3 +123,9 @@ key 165 MEDIA_PREVIOUS
key 166 MEDIA_STOP
key 167 MEDIA_RECORD
key 168 MEDIA_REWIND
+
+key 142 SLEEP
+key 581 STEM_PRIMARY
+key 582 STEM_1
+key 583 STEM_2
+key 584 STEM_3
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index 48afcd48164f..421019c9b602 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -309,7 +309,7 @@ EffectContext.createWithCurrentGlContext()} from your OpenGL ES 2.0 context.</li
android.media.effect.EffectContext#getFactory EffectContext.getFactory()}, which returns an instance
of {@link android.media.effect.EffectFactory}.</li>
<li>Call {@link android.media.effect.EffectFactory#createEffect createEffect()}, passing it an
-effect name from @link android.media.effect.EffectFactory}, such as {@link
+effect name from {@link android.media.effect.EffectFactory}, such as {@link
android.media.effect.EffectFactory#EFFECT_FISHEYE} or {@link
android.media.effect.EffectFactory#EFFECT_VIGNETTE}.</li>
</ol>
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 8673e0bb6a9c..2c93c325f5fc 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -19,6 +19,7 @@ package android.graphics;
import android.content.res.AssetManager;
import android.text.FontConfig;
import android.util.Log;
+import dalvik.annotation.optimization.CriticalNative;
import java.io.FileInputStream;
import java.io.IOException;
@@ -40,11 +41,11 @@ public class FontFamily {
*/
public long mNativePtr;
+ // Points native font family builder. Must be zero after freezing this family.
+ private long mBuilderPtr;
+
public FontFamily() {
- mNativePtr = nCreateFamily(null, 0);
- if (mNativePtr == 0) {
- throw new IllegalStateException("error creating native FontFamily");
- }
+ mBuilderPtr = nInitBuilder(null, 0);
}
public FontFamily(String lang, String variant) {
@@ -54,27 +55,48 @@ public class FontFamily {
} else if ("elegant".equals(variant)) {
varEnum = 2;
}
- mNativePtr = nCreateFamily(lang, varEnum);
- if (mNativePtr == 0) {
- throw new IllegalStateException("error creating native FontFamily");
+ mBuilderPtr = nInitBuilder(lang, varEnum);
+ }
+
+ public void freeze() {
+ if (mBuilderPtr == 0) {
+ throw new IllegalStateException("This FontFamily is already frozen");
+ }
+ mNativePtr = nCreateFamily(mBuilderPtr);
+ mBuilderPtr = 0;
+ }
+
+ public void abortCreation() {
+ if (mBuilderPtr == 0) {
+ throw new IllegalStateException("This FontFamily is already frozen or abandoned");
}
+ nAbort(mBuilderPtr);
+ mBuilderPtr = 0;
}
@Override
protected void finalize() throws Throwable {
try {
- nUnrefFamily(mNativePtr);
+ if (mNativePtr != 0) {
+ nUnrefFamily(mNativePtr);
+ }
+ if (mBuilderPtr != 0) {
+ nAbort(mBuilderPtr);
+ }
} finally {
super.finalize();
}
}
public boolean addFont(String path, int ttcIndex) {
+ if (mBuilderPtr == 0) {
+ throw new IllegalStateException("Unable to call addFont after freezing.");
+ }
try (FileInputStream file = new FileInputStream(path)) {
FileChannel fileChannel = file.getChannel();
long fontSize = fileChannel.size();
ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
- return nAddFont(mNativePtr, fontBuffer, ttcIndex);
+ return nAddFont(mBuilderPtr, fontBuffer, ttcIndex);
} catch (IOException e) {
Log.e(TAG, "Error mapping font file " + path);
return false;
@@ -83,20 +105,34 @@ public class FontFamily {
public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontConfig.Axis> axes,
int weight, boolean style) {
- return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
+ if (mBuilderPtr == 0) {
+ throw new IllegalStateException("Unable to call addFontWeightStyle after freezing.");
+ }
+ return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, axes, weight, style);
}
public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
boolean isAsset) {
- return nAddFontFromAssetManager(mNativePtr, mgr, path, cookie, isAsset);
+ if (mBuilderPtr == 0) {
+ throw new IllegalStateException("Unable to call addFontFromAsset after freezing.");
+ }
+ return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset);
}
- private static native long nCreateFamily(String lang, int variant);
+ private static native long nInitBuilder(String lang, int variant);
+
+ @CriticalNative
+ private static native long nCreateFamily(long mBuilderPtr);
+
+ @CriticalNative
+ private static native void nAbort(long mBuilderPtr);
+
+ @CriticalNative
private static native void nUnrefFamily(long nativePtr);
- private static native boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex);
- private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex);
+ private static native boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
int ttcIndex, List<FontConfig.Axis> listOfAxis,
int weight, boolean isItalic);
- private static native boolean nAddFontFromAssetManager(long nativeFamily, AssetManager mgr,
+ private static native boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr,
String path, int cookie, boolean isAsset);
}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 4ec564ac5809..b757842c4f3f 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -22,6 +22,7 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
@@ -52,9 +53,12 @@ public class FontListParser {
// Note that a well-formed variation contains a four-character tag and a float as styleValue,
// with spacers in between. The tag is enclosd either by double quotes or single quotes.
@VisibleForTesting
- public static FontConfig.Axis[] parseFontVariationSettings(String settings) {
- String[] settingList = settings.split(",");
+ public static ArrayList<FontConfig.Axis> parseFontVariationSettings(@Nullable String settings) {
ArrayList<FontConfig.Axis> axisList = new ArrayList<>();
+ if (settings == null) {
+ return axisList;
+ }
+ String[] settingList = settings.split(",");
settingLoop:
for (String setting : settingList) {
int pos = 0;
@@ -98,7 +102,7 @@ public class FontListParser {
tagString.charAt(3));
axisList.add(new FontConfig.Axis(tag, styleValue));
}
- return axisList.toArray(new FontConfig.Axis[axisList.size()]);
+ return axisList;
}
@VisibleForTesting
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3e59f34f6bc7..1c85df0de590 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -119,7 +119,7 @@ public final class Outline {
* Currently, only Outlines that can be represented as a rectangle, circle,
* or round rect support clipping.
*
- * @see {@link android.view.View#setClipToOutline(boolean)}
+ * @see android.view.View#setClipToOutline(boolean)
*/
public boolean canClip() {
return mMode != MODE_CONVEX_PATH;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7815ae16e7e2..4ee0c3413968 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -71,6 +71,7 @@ public class Paint {
private LocaleList mLocales;
private String mFontFeatureSettings;
+ private String mFontVariationSettings;
private static final Object sCacheLock = new Object();
@@ -1494,6 +1495,37 @@ public class Paint {
}
/**
+ * Returns the font variation settings.
+ *
+ * @return the paint's currently set font variation settings. Default is null.
+ *
+ * @see #setFontVariationSettings(String)
+ */
+ public String getFontVariationSettings() {
+ return mFontVariationSettings;
+ }
+
+ /**
+ * Set font variation settings.
+ *
+ * @param settings font variation settings, e.g. "'wdth' 300, 'wght' 1.8"
+ *
+ * @see #getFontVariationSettings()
+ *
+ * @param settings the font variation settings. You can pass null or empty string as no
+ * variation settings.
+ */
+ public void setFontVariationSettings(String settings) {
+ settings = TextUtils.nullIfEmpty(settings);
+ if (settings == mFontVariationSettings
+ || (settings != null && settings.equals(mFontVariationSettings))) {
+ return;
+ }
+ mFontVariationSettings = settings;
+ setTypeface(Typeface.createFromTypefaceWithVariation(mTypeface, settings));
+ }
+
+ /**
* Get the current value of hyphen edit.
*
* @return the current hyphen edit value
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index f5cedfa26083..b49054550956 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -583,4 +583,17 @@ public class RectF implements Parcelable {
right = in.readFloat();
bottom = in.readFloat();
}
+
+ /**
+ * Scales up the rect by the given scale.
+ * @hide
+ */
+ public void scale(float scale) {
+ if (scale != 1.0f) {
+ left = left * scale;
+ top = top * scale ;
+ right = right * scale;
+ bottom = bottom * scale;
+ }
+ }
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 4e863e37f363..750ef3fa05f6 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -18,6 +18,7 @@ package android.graphics;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.AssetManager;
import android.graphics.fonts.FontRequest;
import android.graphics.fonts.FontResult;
@@ -31,6 +32,7 @@ import android.util.Log;
import android.util.LongSparseArray;
import android.util.LruCache;
import android.util.SparseArray;
+import android.graphics.FontListParser;
import com.android.internal.annotations.GuardedBy;
@@ -131,9 +133,9 @@ public class Typeface {
/**
* @hide
- * Used by Resources.
+ * Used by Resources to load a font resource of type font file.
*/
- @NonNull
+ @Nullable
public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
if (sFallbackFonts != null) {
synchronized (sDynamicTypefaceCache) {
@@ -143,6 +145,7 @@ public class Typeface {
FontFamily fontFamily = new FontFamily();
if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) {
+ fontFamily.freeze();
FontFamily[] families = {fontFamily};
typeface = createFromFamiliesWithDefault(families);
sDynamicTypefaceCache.put(key, typeface);
@@ -150,7 +153,63 @@ public class Typeface {
}
}
}
- throw new RuntimeException("Font resource not found " + path);
+ return null;
+ }
+
+ /**
+ * @hide
+ * Used by Resources to load a font resource of type xml.
+ */
+ @Nullable
+ public static Typeface createFromResources(FontConfig config, AssetManager mgr, String path) {
+ if (sFallbackFonts != null) {
+ synchronized (sDynamicTypefaceCache) {
+ final String key = createAssetUid(mgr, path);
+ Typeface typeface = sDynamicTypefaceCache.get(key);
+ if (typeface != null) return typeface;
+
+ List<FontConfig.Family> families = config.getFamilies();
+ if (families == null || families.isEmpty()) {
+ throw new RuntimeException("Font resource contained no fonts.");
+ }
+ if (families.size() > 1) {
+ throw new RuntimeException("Font resource contained more than one family.");
+ }
+ FontConfig.Family family = families.get(0);
+
+ FontFamily fontFamily = new FontFamily();
+ List<FontConfig.Font> fonts = family.getFonts();
+ for (int i = 0; i < fonts.size(); i++) {
+ FontConfig.Font font = fonts.get(i);
+ // TODO: Use style and weight info
+ if (!fontFamily.addFontFromAssetManager(mgr, font.getFontName(),
+ 0 /* resourceCookie */, false /* isAsset */)) {
+ return null;
+ }
+ }
+ fontFamily.freeze();
+ FontFamily[] familyChain = { fontFamily };
+ typeface = createFromFamiliesWithDefault(familyChain);
+ sDynamicTypefaceCache.put(key, typeface);
+ return typeface;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Used by resources for cached loading if the font is available.
+ * @hide
+ */
+ public static Typeface findFromCache(AssetManager mgr, String path) {
+ synchronized (sDynamicTypefaceCache) {
+ final String key = createAssetUid(mgr, path);
+ Typeface typeface = sDynamicTypefaceCache.get(key);
+ if (typeface != null) {
+ return typeface;
+ }
+ }
+ return null;
}
/**
@@ -163,6 +222,15 @@ public class Typeface {
* @param callback A callback that will be triggered when results are obtained. May not be null.
*/
public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
+ // Check the cache first
+ // TODO: would the developer want to avoid a cache hit and always ask for the freshest
+ // result?
+ Typeface cachedTypeface = findFromCache(
+ request.getProviderAuthority(), request.getQuery());
+ if (cachedTypeface != null) {
+ mHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
+ return;
+ }
synchronized (sLock) {
if (sFontsContract == null) {
sFontsContract = new FontsContract();
@@ -171,20 +239,34 @@ public class Typeface {
final ResultReceiver receiver = new ResultReceiver(null) {
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- receiveResult(request, callback, resultCode, resultData);
- }
- });
+ mHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
}
};
sFontsContract.getFont(request, receiver);
}
}
+ private static Typeface findFromCache(String providerAuthority, String query) {
+ synchronized (sDynamicTypefaceCache) {
+ final String key = createProviderUid(providerAuthority, query);
+ Typeface typeface = sDynamicTypefaceCache.get(key);
+ if (typeface != null) {
+ return typeface;
+ }
+ }
+ return null;
+ }
+
private static void receiveResult(FontRequest request, FontRequestCallback callback,
int resultCode, Bundle resultData) {
+ Typeface cachedTypeface = findFromCache(
+ request.getProviderAuthority(), request.getQuery());
+ if (cachedTypeface != null) {
+ // We already know the result.
+ // Probably the requester requests the same font again in a short interval.
+ callback.onTypefaceRetrieved(cachedTypeface);
+ return;
+ }
if (resultCode == FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND) {
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
@@ -237,8 +319,13 @@ public class Typeface {
IoUtils.closeQuietly(fd);
}
}
- callback.onTypefaceRetrieved(Typeface.createFromFamiliesWithDefault(
- new FontFamily[] {fontFamily}));
+ fontFamily.freeze();
+ Typeface typeface = Typeface.createFromFamiliesWithDefault(new FontFamily[] { fontFamily });
+ synchronized (sDynamicTypefaceCache) {
+ String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
+ sDynamicTypefaceCache.put(key, typeface);
+ }
+ callback.onTypefaceRetrieved(typeface);
}
/**
@@ -348,6 +435,15 @@ public class Typeface {
return typeface;
}
+ /** @hide */
+ public static Typeface createFromTypefaceWithVariation(Typeface family,
+ String fontVariationSettings) {
+ final long ni = family == null ? 0 : family.native_instance;
+ ArrayList<FontConfig.Axis> axes =
+ FontListParser.parseFontVariationSettings(fontVariationSettings);
+ return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes));
+ }
+
/**
* Returns one of the default typeface objects, based on the specified style
*
@@ -373,10 +469,13 @@ public class Typeface {
FontFamily fontFamily = new FontFamily();
if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) {
+ fontFamily.freeze();
FontFamily[] families = { fontFamily };
typeface = createFromFamiliesWithDefault(families);
sDynamicTypefaceCache.put(key, typeface);
return typeface;
+ } else {
+ fontFamily.abortCreation();
}
}
}
@@ -393,6 +492,7 @@ public class Typeface {
private static String createAssetUid(final AssetManager mgr, String path) {
final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
final StringBuilder builder = new StringBuilder();
+ builder.append("asset:");
final int size = pkgs.size();
for (int i = 0; i < size; i++) {
builder.append(pkgs.valueAt(i));
@@ -403,6 +503,18 @@ public class Typeface {
}
/**
+ * Creates a unique id for a given font provider and query.
+ */
+ private static String createProviderUid(String authority, String query) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("provider:");
+ builder.append(authority);
+ builder.append("-");
+ builder.append(query);
+ return builder.toString();
+ }
+
+ /**
* Create a new typeface from the specified font file.
*
* @param path The path to the font data.
@@ -422,8 +534,11 @@ public class Typeface {
if (sFallbackFonts != null) {
FontFamily fontFamily = new FontFamily();
if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
+ fontFamily.freeze();
FontFamily[] families = { fontFamily };
return createFromFamiliesWithDefault(families);
+ } else {
+ fontFamily.abortCreation();
}
}
throw new RuntimeException("Font not found " + path);
@@ -492,6 +607,7 @@ public class Typeface {
Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
}
}
+ fontFamily.freeze();
return fontFamily;
}
@@ -617,6 +733,8 @@ public class Typeface {
}
private static native long nativeCreateFromTypeface(long native_instance, int style);
+ private static native long nativeCreateFromTypefaceWithVariation(
+ long native_instance, List<FontConfig.Axis> axes);
private static native long nativeCreateWeightAlias(long native_instance, int weight);
private static native void nativeUnref(long native_instance);
private static native int nativeGetStyle(long native_instance);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 6ddc2d7e192f..850f40ec3eb6 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1320,7 +1320,7 @@ public abstract class Drawable {
* provide an appropriate Resources object.
*
* @return a new drawable object based on this constant state
- * @see {@link #newDrawable(Resources)}
+ * @see #newDrawable(Resources)
*/
public abstract @NonNull Drawable newDrawable();
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index 348af70d5568..6d0bbdf549f2 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -147,6 +147,8 @@ public final class DrawableInflater {
return new TransitionDrawable();
case "ripple":
return new RippleDrawable();
+ case "maskable-icon":
+ return new MaskableIconDrawable();
case "color":
return new ColorDrawable();
case "shape":
diff --git a/graphics/java/android/graphics/drawable/MaskableIconDrawable.java b/graphics/java/android/graphics/drawable/MaskableIconDrawable.java
new file mode 100644
index 000000000000..043f0926bdb7
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/MaskableIconDrawable.java
@@ -0,0 +1,1007 @@
+/*
+ * 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.graphics.drawable;
+
+import static android.graphics.drawable.Drawable.obtainAttributes;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.Shader.TileMode;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.PathParser;
+
+import com.android.internal.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * This drawable supports two layers: foreground and background.
+ *
+ * <p>The layers are clipped when rendering using the mask path defined in the device configuration.
+ *
+ * <p>This class can also be created via XML inflation using <code>&lt;maskable-icon></code> tag
+ * in addition to dynamic creation.
+ */
+public class MaskableIconDrawable extends Drawable implements Drawable.Callback {
+
+ /**
+ * Mask path is defined inside device configuration in following dimension: [100 x 100]
+ */
+ public static final float MASK_SIZE = 100f;
+
+ /**
+ * The view port of the layers is smaller than their intrinsic width and height by this factor.
+ *
+ * It is part of the API contract that all four sides of the layers are padded so as to provide
+ * extra content to reveal within the clip path when performing affine transformations on the
+ * layers.
+ */
+ public static final float DEFAULT_VIEW_PORT_SCALE = 2f / 3f;
+
+ /**
+ * Clip path defined in {@link com.android.internal.R.string.config_icon_mask}.
+ */
+ private static Path sMask;
+
+ /**
+ * Scaled mask based on the view bounds.
+ */
+ private final Path mMask;
+ private final Matrix mMaskMatrix;
+ private final Region mTransparentRegion;
+
+ private Bitmap mMaskBitmap;
+
+ /**
+ * Indices used to access {@link #mLayerState.mChildDrawable} array for foreground and
+ * background layer.
+ */
+ private static final int BACKGROUND_ID = 0;
+ private static final int FOREGROUND_ID = 1;
+
+ /**
+ * State variable that maintains the {@link ChildDrawable} array.
+ */
+ LayerState mLayerState;
+
+ private Shader mLayersShader;
+ private Bitmap mLayersBitmap;
+
+ private final Rect mTmpOutRect = new Rect();
+ private Rect mHotspotBounds;
+ private boolean mMutated;
+
+ private boolean mSuspendChildInvalidation;
+ private boolean mChildRequestedInvalidation;
+ private final Canvas mCanvas;
+ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
+ Paint.FILTER_BITMAP_FLAG);
+
+ /**
+ * Constructor used for xml inflation.
+ */
+ MaskableIconDrawable() {
+ this((LayerState) null, null);
+ }
+
+ /**
+ * The one constructor to rule them all. This is called by all public
+ * constructors to set the state and initialize local properties.
+ */
+ MaskableIconDrawable(@Nullable LayerState state, @Nullable Resources res) {
+ mLayerState = createConstantState(state, res);
+
+ if (sMask == null) {
+ sMask = PathParser.createPathFromPathData(
+ Resources.getSystem().getString(com.android.internal.R.string.config_icon_mask));
+ }
+ mMask = new Path();
+ mMaskMatrix = new Matrix();
+ mCanvas = new Canvas();
+ mTransparentRegion = new Region();
+ }
+
+ private ChildDrawable createChildDrawable(Drawable drawable) {
+ final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity);
+ layer.mDrawable = drawable;
+ layer.mDrawable.setCallback(this);
+ mLayerState.mChildrenChangingConfigurations |=
+ layer.mDrawable.getChangingConfigurations();
+ return layer;
+ }
+
+ LayerState createConstantState(@Nullable LayerState state, @Nullable Resources res) {
+ return new LayerState(state, this, res);
+ }
+
+ /**
+ * Constructor used to dynamically create this drawable.
+ *
+ * @param backgroundDrawable drawable that should be rendered in the background
+ * @param foregroundDrawable drawable that should be rendered in the foreground
+ */
+ public MaskableIconDrawable(Drawable backgroundDrawable,
+ Drawable foregroundDrawable) {
+ this((LayerState)null, null);
+ addLayer(BACKGROUND_ID, createChildDrawable(backgroundDrawable));
+ addLayer(FOREGROUND_ID, createChildDrawable(foregroundDrawable));
+ }
+
+ /**
+ * Sets the layer to the {@param index} and invalidates cache.
+ *
+ * @param index The index of the layer.
+ * @param layer The layer to add.
+ */
+ private void addLayer(int index, @NonNull ChildDrawable layer) {
+ mLayerState.mChildren[index] = layer;
+ mLayerState.invalidateCache();
+ }
+
+ @Override
+ public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs, theme);
+
+ final LayerState state = mLayerState;
+ if (state == null) {
+ return;
+ }
+
+ // The density may have changed since the last update. This will
+ // apply scaling to any existing constant state properties.
+ final int density = Drawable.resolveDensity(r, 0);
+ state.setDensity(density);
+
+ final ChildDrawable[] array = state.mChildren;
+ for (int i = 0; i < state.mChildren.length; i++) {
+ final ChildDrawable layer = array[i];
+ layer.setDensity(density);
+ }
+ inflateLayers(r, parser, attrs, theme);
+ }
+
+ /**
+ * @return the mask path object used to clip the drawable
+ */
+ public Path getIconMask() {
+ return mMask;
+ }
+
+ /**
+ * @return the foreground drawable managed by this drawable
+ */
+ public Drawable getForeground() {
+ return mLayerState.mChildren[FOREGROUND_ID].mDrawable;
+ }
+
+ /**
+ * @return the background drawable managed by this drawable
+ */
+ public Drawable getBackground() {
+ return mLayerState.mChildren[BACKGROUND_ID].mDrawable;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ if (bounds.isEmpty()) {
+ return;
+ }
+ updateLayerBounds(bounds);
+ }
+
+ private void updateLayerBounds(Rect bounds) {
+ try {
+ suspendChildInvalidation();
+ updateLayerBoundsInternal(bounds);
+ updateMaskBoundsInternal(bounds);
+ } finally {
+ resumeChildInvalidation();
+ }
+ }
+
+ private void updateLayerBoundsInternal(Rect bounds) {
+ int cX = bounds.centerX();
+ int cY = bounds.centerY();
+
+ for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
+ int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ final Rect outRect = mTmpOutRect;
+ outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
+
+ final ChildDrawable r = mLayerState.mChildren[i];
+ final Drawable d = r.mDrawable;
+ d.setBounds(outRect);
+ }
+ }
+
+ private void updateMaskBoundsInternal(Rect b) {
+ mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
+ sMask.transform(mMaskMatrix, mMask);
+
+ mMaskBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ALPHA_8);
+ mCanvas.setBitmap(mMaskBitmap);
+ mPaint.setShader(null);
+ mCanvas.drawPath(mMask, mPaint);
+
+ // reset everything that depends on the view bounds
+ mTransparentRegion.setEmpty();
+ mLayersShader = null;
+ mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mLayersShader == null) {
+ mCanvas.setBitmap(mLayersBitmap);
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = mLayerState.mChildren[i].mDrawable;
+ if (dr != null) {
+ dr.draw(mCanvas);
+ }
+ }
+ mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
+ mPaint.setShader(mLayersShader);
+ }
+ canvas.drawBitmap(mMaskBitmap, 0.0f, 0.0f, mPaint);
+ }
+
+ @Override
+ public void invalidateSelf() {
+ mLayersShader = null;
+ super.invalidateSelf();
+ }
+
+ @Override
+ public void getOutline(@NonNull Outline outline) {
+ outline.setConvexPath(mMask);
+ }
+
+ @Override
+ public @Nullable Region getTransparentRegion() {
+ if (mTransparentRegion.isEmpty()) {
+ mMask.toggleInverseFillType();
+ mTransparentRegion.set(getBounds());
+ mTransparentRegion.setPath(mMask, mTransparentRegion);
+ mMask.toggleInverseFillType();
+ }
+ return mTransparentRegion;
+ }
+
+ @Override
+ public void applyTheme(@NonNull Theme t) {
+ super.applyTheme(t);
+
+ final LayerState state = mLayerState;
+ if (state == null) {
+ return;
+ }
+
+ final int density = Drawable.resolveDensity(t.getResources(), 0);
+ state.setDensity(density);
+
+ final ChildDrawable[] array = state.mChildren;
+ for (int i = 0; i < state.N_CHILDREN; i++) {
+ final ChildDrawable layer = array[i];
+ layer.setDensity(density);
+
+ if (layer.mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(
+ layer.mThemeAttrs, R.styleable.MaskableIconDrawableLayer);
+ updateLayerFromTypedArray(layer, a);
+ a.recycle();
+ }
+
+ final Drawable d = layer.mDrawable;
+ if (d != null && d.canApplyTheme()) {
+ d.applyTheme(t);
+
+ // Update cached mask of child changing configurations.
+ state.mChildrenChangingConfigurations |= d.getChangingConfigurations();
+ }
+ }
+ }
+
+ /**
+ * Inflates child layers using the specified parser.
+ */
+ void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final LayerState state = mLayerState;
+
+ final int innerDepth = parser.getDepth() + 1;
+ int type;
+ int depth;
+ int childIndex = 0;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals("background")) {
+ childIndex = BACKGROUND_ID;
+ } else if (tagName.equals("foreground")) {
+ childIndex = FOREGROUND_ID;
+ } else {
+ continue;
+ }
+
+ final ChildDrawable layer = new ChildDrawable(state.mDensity);
+ final TypedArray a = obtainAttributes(r, theme, attrs,
+ R.styleable.MaskableIconDrawableLayer);
+ updateLayerFromTypedArray(layer, a);
+ a.recycle();
+
+ // If the layer doesn't have a drawable or unresolved theme
+ // attribute for a drawable, attempt to parse one from the child
+ // element. If multiple child elements exist, we'll only use the
+ // first one.
+ if (layer.mDrawable == null && (layer.mThemeAttrs == null)) {
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(parser.getPositionDescription()
+ + ": <foreground> or <background> tag requires a 'color' or 'drawable'"
+ + "attribute or child tag defining a drawable");
+ }
+
+ // We found a child drawable. Take ownership.
+ layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
+ layer.mDrawable.setCallback(this);
+ state.mChildrenChangingConfigurations |=
+ layer.mDrawable.getChangingConfigurations();
+ }
+ addLayer(childIndex, layer);
+ }
+ }
+
+ private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) {
+ final LayerState state = mLayerState;
+
+ // Account for any configuration changes.
+ state.mChildrenChangingConfigurations |= a.getChangingConfigurations();
+
+ // Extract the theme attributes, if any.
+ layer.mThemeAttrs = a.extractThemeAttrs();
+
+ Drawable dr = a.getDrawable(R.styleable.MaskableIconDrawableLayer_drawable);
+ if (dr == null) {
+ int color = a.getColor(R.styleable.MaskableIconDrawableLayer_color, Color.TRANSPARENT);
+ if (color != Color.TRANSPARENT) {
+ dr = new ColorDrawable(color);
+ }
+ }
+ if (dr != null) {
+ if (layer.mDrawable != null) {
+ // It's possible that a drawable was already set, in which case
+ // we should clear the callback. We may have also integrated the
+ // drawable's changing configurations, but we don't have enough
+ // information to revert that change.
+ layer.mDrawable.setCallback(null);
+ }
+
+ // Take ownership of the new drawable.
+ layer.mDrawable = dr;
+ layer.mDrawable.setCallback(this);
+ state.mChildrenChangingConfigurations |=
+ layer.mDrawable.getChangingConfigurations();
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isProjected() {
+ if (super.isProjected()) {
+ return true;
+ }
+
+ final ChildDrawable[] layers = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ if (layers[i].mDrawable.isProjected()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Temporarily suspends child invalidation.
+ *
+ * @see #resumeChildInvalidation()
+ */
+ private void suspendChildInvalidation() {
+ mSuspendChildInvalidation = true;
+ }
+
+ /**
+ * Resumes child invalidation after suspension, immediately performing an
+ * invalidation if one was requested by a child during suspension.
+ *
+ * @see #suspendChildInvalidation()
+ */
+ private void resumeChildInvalidation() {
+ mSuspendChildInvalidation = false;
+
+ if (mChildRequestedInvalidation) {
+ mChildRequestedInvalidation = false;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ if (mSuspendChildInvalidation) {
+ mChildRequestedInvalidation = true;
+ } else {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+ unscheduleSelf(what);
+ }
+
+ @Override
+ public @Config int getChangingConfigurations() {
+ return super.getChangingConfigurations() | mLayerState.getChangingConfigurations();
+ }
+
+ @Override
+ public void setHotspot(float x, float y) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setHotspot(x, y);
+ }
+ }
+ }
+
+ @Override
+ public void setHotspotBounds(int left, int top, int right, int bottom) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setHotspotBounds(left, top, right, bottom);
+ }
+ }
+
+ if (mHotspotBounds == null) {
+ mHotspotBounds = new Rect(left, top, right, bottom);
+ } else {
+ mHotspotBounds.set(left, top, right, bottom);
+ }
+ }
+
+ @Override
+ public void getHotspotBounds(Rect outRect) {
+ if (mHotspotBounds != null) {
+ outRect.set(mHotspotBounds);
+ } else {
+ super.getHotspotBounds(outRect);
+ }
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ final boolean changed = super.setVisible(visible, restart);
+ final ChildDrawable[] array = mLayerState.mChildren;
+
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setVisible(visible, restart);
+ }
+ }
+
+ return changed;
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setDither(dither);
+ }
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setAlpha(alpha);
+ }
+ }
+ }
+
+ @Override
+ public int getAlpha() {
+ final Drawable dr = getFirstNonNullDrawable();
+ if (dr != null) {
+ return dr.getAlpha();
+ } else {
+ return super.getAlpha();
+ }
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setColorFilter(colorFilter);
+ }
+ }
+ }
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.N_CHILDREN;
+ for (int i = 0; i < N; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setTintList(tint);
+ }
+ }
+ }
+
+ @Override
+ public void setTintMode(Mode tintMode) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.N_CHILDREN;
+ for (int i = 0; i < N; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setTintMode(tintMode);
+ }
+ }
+ }
+
+ private Drawable getFirstNonNullDrawable() {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ return dr;
+ }
+ }
+ return null;
+ }
+
+ public void setOpacity(int opacity) {
+ mLayerState.mOpacityOverride = opacity;
+ }
+
+ @Override
+ public int getOpacity() {
+ if (mLayerState.mOpacityOverride != PixelFormat.UNKNOWN) {
+ return mLayerState.mOpacityOverride;
+ }
+ return mLayerState.getOpacity();
+ }
+
+ @Override
+ public void setAutoMirrored(boolean mirrored) {
+ mLayerState.mAutoMirrored = mirrored;
+
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.setAutoMirrored(mirrored);
+ }
+ }
+ }
+
+ @Override
+ public boolean isAutoMirrored() {
+ return mLayerState.mAutoMirrored;
+ }
+
+ @Override
+ public void jumpToCurrentState() {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.jumpToCurrentState();
+ }
+ }
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mLayerState.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean changed = false;
+
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.isStateful() && dr.setState(state)) {
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ updateLayerBounds(getBounds());
+ }
+
+ return changed;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ boolean changed = false;
+
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.setLevel(level)) {
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ updateLayerBounds(getBounds());
+ }
+
+ return changed;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return (int)(getMaxIntrinsicWidth() * DEFAULT_VIEW_PORT_SCALE);
+ }
+
+ private int getMaxIntrinsicWidth() {
+ int width = -1;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final ChildDrawable r = mLayerState.mChildren[i];
+ if (r.mDrawable == null) {
+ continue;
+ }
+ final int w = r.mDrawable.getIntrinsicWidth();
+ if (w > width) {
+ width = w;
+ }
+ }
+ return width;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return (int)(getMaxIntrinsicHeight() * DEFAULT_VIEW_PORT_SCALE);
+ }
+
+ private int getMaxIntrinsicHeight() {
+ int height = -1;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final ChildDrawable r = mLayerState.mChildren[i];
+ if (r.mDrawable == null) {
+ continue;
+ }
+ final int h = r.mDrawable.getIntrinsicHeight();
+ if (h > height) {
+ height = h;
+ }
+ }
+ return height;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mLayerState.canConstantState()) {
+ mLayerState.mChangingConfigurations = getChangingConfigurations();
+ return mLayerState;
+ }
+ return null;
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mLayerState = createConstantState(mLayerState, null);
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = mLayerState.mChildren[i].mDrawable;
+ if (dr != null) {
+ dr.mutate();
+ }
+ }
+ mMutated = true;
+ }
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public void clearMutated() {
+ super.clearMutated();
+ final ChildDrawable[] array = mLayerState.mChildren;
+ for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ dr.clearMutated();
+ }
+ }
+ mMutated = false;
+ }
+
+ static class ChildDrawable {
+ public Drawable mDrawable;
+ public int[] mThemeAttrs;
+ public int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+
+ ChildDrawable(int density) {
+ mDensity = density;
+ }
+
+ ChildDrawable(@NonNull ChildDrawable orig, @NonNull MaskableIconDrawable owner,
+ @Nullable Resources res) {
+
+ final Drawable dr = orig.mDrawable;
+ final Drawable clone;
+ if (dr != null) {
+ final ConstantState cs = dr.getConstantState();
+ if (cs == null) {
+ clone = dr;
+ } else if (res != null) {
+ clone = cs.newDrawable(res);
+ } else {
+ clone = cs.newDrawable();
+ }
+ clone.setCallback(owner);
+ clone.setBounds(dr.getBounds());
+ clone.setLevel(dr.getLevel());
+ } else {
+ clone = null;
+ }
+
+ mDrawable = clone;
+ mThemeAttrs = orig.mThemeAttrs;
+
+ mDensity = Drawable.resolveDensity(res, orig.mDensity);
+ }
+
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null
+ || (mDrawable != null && mDrawable.canApplyTheme());
+ }
+
+ public final void setDensity(int targetDensity) {
+ if (mDensity != targetDensity) {
+ mDensity = targetDensity;
+ }
+ }
+ }
+
+ static class LayerState extends ConstantState {
+ private int[] mThemeAttrs;
+
+ final static int N_CHILDREN = 2;
+ ChildDrawable[] mChildren;
+
+ int mDensity;
+ int mOpacityOverride = PixelFormat.UNKNOWN;
+
+ @Config int mChangingConfigurations;
+ @Config int mChildrenChangingConfigurations;
+
+ private boolean mCheckedOpacity;
+ private int mOpacity;
+
+ private boolean mCheckedStateful;
+ private boolean mIsStateful;
+ private boolean mAutoMirrored = false;
+
+ LayerState(@Nullable LayerState orig, @NonNull MaskableIconDrawable owner,
+ @Nullable Resources res) {
+ mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0);
+ mChildren = new ChildDrawable[N_CHILDREN];
+ if (orig != null) {
+ final ChildDrawable[] origChildDrawable = orig.mChildren;
+
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
+
+ for (int i = 0; i < N_CHILDREN; i++) {
+ final ChildDrawable or = origChildDrawable[i];
+ mChildren[i] = new ChildDrawable(or, owner, res);
+ }
+
+ mCheckedOpacity = orig.mCheckedOpacity;
+ mOpacity = orig.mOpacity;
+ mCheckedStateful = orig.mCheckedStateful;
+ mIsStateful = orig.mIsStateful;
+ mAutoMirrored = orig.mAutoMirrored;
+ mThemeAttrs = orig.mThemeAttrs;
+ mOpacityOverride = orig.mOpacityOverride;
+ } else {
+ for (int i = 0; i < N_CHILDREN; i++) {
+ mChildren[i] = new ChildDrawable(mDensity);
+ }
+ }
+ }
+
+ public final void setDensity(int targetDensity) {
+ if (mDensity != targetDensity) {
+ mDensity = targetDensity;
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ if (mThemeAttrs != null || super.canApplyTheme()) {
+ return true;
+ }
+
+ final ChildDrawable[] array = mChildren;
+ for (int i = 0; i < N_CHILDREN; i++) {
+ final ChildDrawable layer = array[i];
+ if (layer.canApplyTheme()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new MaskableIconDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(@Nullable Resources res) {
+ return new MaskableIconDrawable(this, res);
+ }
+
+ @Override
+ public @Config int getChangingConfigurations() {
+ return mChangingConfigurations
+ | mChildrenChangingConfigurations;
+ }
+
+ public final int getOpacity() {
+ if (mCheckedOpacity) {
+ return mOpacity;
+ }
+
+ final ChildDrawable[] array = mChildren;
+
+ // Seek to the first non-null drawable.
+ int firstIndex = -1;
+ for (int i = 0; i < N_CHILDREN; i++) {
+ if (array[i].mDrawable != null) {
+ firstIndex = i;
+ break;
+ }
+ }
+
+ int op;
+ if (firstIndex >= 0) {
+ op = array[firstIndex].mDrawable.getOpacity();
+ } else {
+ op = PixelFormat.TRANSPARENT;
+ }
+
+ // Merge all remaining non-null drawables.
+ for (int i = firstIndex + 1; i < N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null) {
+ op = Drawable.resolveOpacity(op, dr.getOpacity());
+ }
+ }
+
+ mOpacity = op;
+ mCheckedOpacity = true;
+ return op;
+ }
+
+ public final boolean isStateful() {
+ if (mCheckedStateful) {
+ return mIsStateful;
+ }
+
+ final ChildDrawable[] array = mChildren;
+ boolean isStateful = false;
+ for (int i = 0; i < N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.isStateful()) {
+ isStateful = true;
+ break;
+ }
+ }
+
+ mIsStateful = isStateful;
+ mCheckedStateful = true;
+ return isStateful;
+ }
+
+ public final boolean canConstantState() {
+ final ChildDrawable[] array = mChildren;
+ for (int i = 0; i < N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.getConstantState() == null) {
+ return false;
+ }
+ }
+
+ // Don't cache the result, this method is not called very often.
+ return true;
+ }
+
+ public void invalidateCache() {
+ mCheckedOpacity = false;
+ mCheckedStateful = false;
+ }
+ }
+} \ No newline at end of file
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
index 2b4e6c27f193..c7a46a369772 100644
--- a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
@@ -18,9 +18,8 @@ package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.FontConfig;
-import junit.framework.TestCase;
-
import java.util.List;
+import junit.framework.TestCase;
public class VariationParserTest extends TestCase {
@@ -28,92 +27,92 @@ public class VariationParserTest extends TestCase {
@SmallTest
public void testParseFontVariationSetting() {
int tag = FontListParser.makeTag('w', 'd', 't', 'h');
- FontConfig.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ List<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings("'wdth' 1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
- assertEquals(tag, axis[0].getTag());
- assertEquals(100.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("\"wdth\" 100");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(100.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings(" 'wdth' 100");
- assertEquals(tag, axis[0].getTag());
- assertEquals(100.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings(" 'wdth' 100");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(100.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
- assertEquals(tag, axis[0].getTag());
- assertEquals(0.5f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(0.5f, axes.get(0).getStyleValue());
tag = FontListParser.makeTag('A', 'X', ' ', ' ');
- axis = FontListParser.parseFontVariationSettings("'AX ' 1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("'AX ' 1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("'AX '\t1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("'AX '\t1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("'AX '\n1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("'AX '\n1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("'AX '\r1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("'AX '\r1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
- axis = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1");
- assertEquals(tag, axis[0].getTag());
- assertEquals(1.0f, axis[0].getStyleValue());
+ axes = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1");
+ assertEquals(tag, axes.get(0).getTag());
+ assertEquals(1.0f, axes.get(0).getStyleValue());
// Test for invalid input
- axis = FontListParser.parseFontVariationSettings("");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("invalid_form");
- assertEquals(0, axis.length);
+ axes = FontListParser.parseFontVariationSettings("");
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("invalid_form");
+ assertEquals(0, axes.size());
// Test with invalid tag
- axis = FontListParser.parseFontVariationSettings("'' 1");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("'invalid' 1");
- assertEquals(0, axis.length);
+ axes = FontListParser.parseFontVariationSettings("'' 1");
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("'invalid' 1");
+ assertEquals(0, axes.size());
// Test with invalid styleValue
- axis = FontListParser.parseFontVariationSettings("'wdth' ");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("'wdth' x");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("'wdth' \t");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("'wdth' \n\r");
- assertEquals(0, axis.length);
+ axes = FontListParser.parseFontVariationSettings("'wdth' ");
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("'wdth' x");
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("'wdth' \t");
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("'wdth' \n\r");
+ assertEquals(0, axes.size());
}
@SmallTest
public void testParseFontVariationStyleSettings() {
- FontConfig.Axis[] axis =
+ List<FontConfig.Axis> axes =
FontListParser.parseFontVariationSettings("'wdth' 10,'AX '\r1");
int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
- assertEquals(tag1, axis[0].getTag());
- assertEquals(10.0f, axis[0].getStyleValue());
- assertEquals(tag2, axis[1].getTag());
- assertEquals(1.0f, axis[1].getStyleValue());
+ assertEquals(tag1, axes.get(0).getTag());
+ assertEquals(10.0f, axes.get(0).getStyleValue());
+ assertEquals(tag2, axes.get(1).getTag());
+ assertEquals(1.0f, axes.get(1).getStyleValue());
// Test only spacers are allowed before tag
- axis = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1");
+ axes = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1");
tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
- assertEquals(tag1, axis[0].getTag());
- assertEquals(10.0f, axis[0].getStyleValue());
- assertEquals(1, axis.length);
+ assertEquals(tag1, axes.get(0).getTag());
+ assertEquals(10.0f, axes.get(0).getStyleValue());
+ assertEquals(1, axes.size());
}
@SmallTest
public void testInvalidTagCharacters() {
- FontConfig.Axis[] axis =
+ List<FontConfig.Axis> axes =
FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10");
- assertEquals(0, axis.length);
- axis = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
- assertEquals(0, axis.length);
+ assertEquals(0, axes.size());
+ axes = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
+ assertEquals(0, axes.size());
}
@SmallTest
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index 7a2cbd06eb92..03df5de9b484 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -29,6 +29,8 @@ import android.service.gatekeeper.IGateKeeperService;
*/
public abstract class GateKeeper {
+ public static final long INVALID_SECURE_USER_ID = 0;
+
private GateKeeper() {}
public static IGateKeeperService getService() {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index b234d0f81a89..9701b0ea9308 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import android.security.Credentials;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -235,7 +236,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -275,7 +277,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 1818f52c4fda..dba3949ba98f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,6 +18,7 @@ package android.security.keystore;
import android.annotation.Nullable;
import android.security.Credentials;
+import android.security.GateKeeper;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
@@ -346,7 +347,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment());
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -533,7 +535,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment());
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index fcbb553c7214..64b10ab6eacb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -500,7 +500,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ spec.getBoundToSpecificSecureUserId());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -696,7 +697,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds(),
params.isUserAuthenticationValidWhileOnBody(),
- params.isInvalidatedByBiometricEnrollment());
+ params.isInvalidatedByBiometricEnrollment(),
+ params.getBoundToSpecificSecureUserId());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
new file mode 100644
index 000000000000..e36632a591eb
--- /dev/null
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -0,0 +1,228 @@
+/*
+ * 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.security.keystore;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.Build;
+import android.os.Process;
+import android.security.KeyStore;
+import android.security.KeyStoreException;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterCertificateChain;
+import android.security.keymaster.KeymasterDefs;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Utilities for attesting the device's hardware identifiers.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public abstract class AttestationUtils {
+ private static AtomicInteger sSequenceNumber = new AtomicInteger(0);
+
+ private AttestationUtils() {
+ }
+
+ /**
+ * Specifies that the device should attest its serial number. For use with
+ * {@link #attestDeviceIds}.
+ *
+ * @see #attestDeviceIds
+ */
+ public static final int ID_TYPE_SERIAL = 1;
+
+ /**
+ * Specifies that the device should attest its IMEIs. For use with {@link #attestDeviceIds}.
+ *
+ * @see #attestDeviceIds
+ */
+ public static final int ID_TYPE_IMEI = 2;
+
+ /**
+ * Specifies that the device should attest its MEIDs. For use with {@link #attestDeviceIds}.
+ *
+ * @see #attestDeviceIds
+ */
+ public static final int ID_TYPE_MEID = 3;
+
+ /**
+ * Performs attestation of the device's identifiers. This method returns a certificate chain
+ * whose first element contains the requested device identifiers in an extension. The device's
+ * brand, device and product are always also included in the attestation. If the device supports
+ * attestation in secure hardware, the chain will be rooted at a trustworthy CA key. Otherwise,
+ * the chain will be rooted at an untrusted certificate. See
+ * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
+ * Key Attestation</a> for the format of the certificate extension.
+ * <p>
+ * Attestation will only be successful when all of the following are true:
+ * 1) The device has been set up to support device identifier attestation at the factory.
+ * 2) The user has not permanently disabled device identifier attestation.
+ * 3) You have permission to access the device identifiers you are requesting attestation for.
+ * <p>
+ * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
+ * unsuccessful, the device may not support it in general or the user may have permanently
+ * disabled it.
+ * <p>
+ * The caller must hold {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ * permission.
+ *
+ * @param context the context to use for retrieving device identifiers.
+ * @param idTypes the types of device identifiers to attest.
+ * @param attestationChallenge a blob to include in the certificate alongside the device
+ * identifiers.
+ *
+ * @return a certificate chain containing the requested device identifiers in the first element
+ *
+ * @exception SecurityException if you are not permitted to obtain an attestation of the
+ * device's identifiers.
+ * @exception DeviceIdAttestationException if the attestation operation fails.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @NonNull public static X509Certificate[] attestDeviceIds(Context context,
+ @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ // Check method arguments, retrieve requested device IDs and prepare attestation arguments.
+ if (idTypes == null) {
+ throw new NullPointerException("Missing id types");
+ }
+ if (attestationChallenge == null) {
+ throw new NullPointerException("Missing attestation challenge");
+ }
+ final KeymasterArguments attestArgs = new KeymasterArguments();
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge);
+ final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
+ for (int idType : idTypes) {
+ idTypesSet.add(idType);
+ }
+ TelephonyManager telephonyService = null;
+ if (idTypesSet.contains(ID_TYPE_IMEI) || idTypesSet.contains(ID_TYPE_MEID)) {
+ telephonyService = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ if (telephonyService == null) {
+ throw new DeviceIdAttestationException("Unable to access telephony service");
+ }
+ }
+ for (final Integer idType : idTypesSet) {
+ switch (idType) {
+ case ID_TYPE_SERIAL:
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
+ Build.getSerial().getBytes(StandardCharsets.UTF_8));
+ break;
+ case ID_TYPE_IMEI: {
+ final String imei = telephonyService.getImei(0);
+ if (imei == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve IMEI");
+ }
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
+ imei.getBytes(StandardCharsets.UTF_8));
+ break;
+ }
+ case ID_TYPE_MEID: {
+ final String meid = telephonyService.getDeviceId();
+ if (meid == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve MEID");
+ }
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
+ meid.getBytes(StandardCharsets.UTF_8));
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unknown device ID type " + idType);
+ }
+ }
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
+ Build.BRAND.getBytes(StandardCharsets.UTF_8));
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
+ Build.DEVICE.getBytes(StandardCharsets.UTF_8));
+ attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
+ Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
+
+ final KeyStore keyStore = KeyStore.getInstance();
+ final String keyAlias = "android_internal_device_id_attestation-"
+ + Process.myPid() + "-" + sSequenceNumber.incrementAndGet();
+ // Clear any leftover temporary key.
+ if (!keyStore.delete(keyAlias)) {
+ throw new DeviceIdAttestationException("Unable to remove temporary key");
+ }
+ try {
+ // Generate a temporary key.
+ final KeymasterArguments generateArgs = new KeymasterArguments();
+ generateArgs.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
+ generateArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
+ generateArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+ generateArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
+ generateArgs.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+ generateArgs.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
+ generateArgs.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+ RSAKeyGenParameterSpec.F4);
+ int errorCode = keyStore.generateKey(keyAlias, generateArgs, null, 0,
+ new KeyCharacteristics());
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new DeviceIdAttestationException("Unable to create temporary key",
+ KeyStore.getKeyStoreException(errorCode));
+ }
+
+ // Perform attestation.
+ final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
+ errorCode = keyStore.attestKey(keyAlias, attestArgs, outChain);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new DeviceIdAttestationException("Unable to perform attestation",
+ KeyStore.getKeyStoreException(errorCode));
+ }
+
+ // Extract certificate chain.
+ final Collection<byte[]> rawChain = outChain.getCertificates();
+ if (rawChain.size() < 2) {
+ throw new DeviceIdAttestationException("Attestation certificate chain contained "
+ + rawChain.size() + " entries. At least two are required.");
+ }
+ final ByteArrayOutputStream concatenatedRawChain = new ByteArrayOutputStream();
+ try {
+ for (final byte[] cert : rawChain) {
+ concatenatedRawChain.write(cert);
+ }
+ return CertificateFactory.getInstance("X.509").generateCertificates(
+ new ByteArrayInputStream(concatenatedRawChain.toByteArray()))
+ .toArray(new X509Certificate[0]);
+ } catch (Exception e) {
+ throw new DeviceIdAttestationException("Unable to construct certificate chain", e);
+ }
+ } finally {
+ // Remove temporary key.
+ keyStore.delete(keyAlias);
+ }
+ }
+}
diff --git a/keystore/java/android/security/keystore/DeviceIdAttestationException.java b/keystore/java/android/security/keystore/DeviceIdAttestationException.java
new file mode 100644
index 000000000000..e18d193b043b
--- /dev/null
+++ b/keystore/java/android/security/keystore/DeviceIdAttestationException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.security.keystore;
+
+/**
+ * Thrown when {@link AttestationUtils} is unable to attest the given device ids.
+ *
+ * @hide
+ */
+public class DeviceIdAttestationException extends Exception {
+ /**
+ * Constructs a new {@code DeviceIdAttestationException} with the current stack trace and the
+ * specified detail message.
+ *
+ * @param detailMessage the detail message for this exception.
+ */
+ public DeviceIdAttestationException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ /**
+ * Constructs a new {@code DeviceIdAttestationException} with the current stack trace, the
+ * specified detail message and the specified cause.
+ *
+ * @param message the detail message for this exception.
+ * @param cause the cause of this exception, may be {@code null}.
+ */
+ public DeviceIdAttestationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index e70d33a3385c..2592a97468d3 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
import java.security.Key;
import java.security.Signature;
@@ -225,6 +226,7 @@ public final class KeyProtection implements ProtectionParameter {
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
+ private final long mBoundToSecureUserId;
private KeyProtection(
Date keyValidityStart,
@@ -239,7 +241,8 @@ public final class KeyProtection implements ProtectionParameter {
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment) {
+ boolean invalidatedByBiometricEnrollment,
+ long boundToSecureUserId) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -255,6 +258,7 @@ public final class KeyProtection implements ProtectionParameter {
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
+ mBoundToSecureUserId = boundToSecureUserId;
}
/**
@@ -436,6 +440,24 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Return the secure user id that this key should be bound to.
+ *
+ * Normally an authentication-bound key is tied to the secure user id of the current user
+ * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the authenticator
+ * id of the current fingerprint set for keys requiring explicit fingerprint authorization).
+ * If this parameter is set (this method returning non-zero value), the key should be tied to
+ * the specified secure user id, overriding the logic above.
+ *
+ * This is only applicable when {@link #isUserAuthenticationRequired} is {@code true}
+ *
+ * @see KeymasterUtils#addUserAuthArgs
+ * @hide
+ */
+ public long getBoundToSpecificSecureUserId() {
+ return mBoundToSecureUserId;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -454,6 +476,7 @@ public final class KeyProtection implements ProtectionParameter {
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
+ private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
/**
* Creates a new instance of the {@code Builder}.
*
@@ -774,6 +797,26 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Set the secure user id that this key should be bound to.
+ *
+ * Normally an authentication-bound key is tied to the secure user id of the current user
+ * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the
+ * authenticator id of the current fingerprint set for keys requiring explicit fingerprint
+ * authorization). If this parameter is set (this method returning non-zero value), the key
+ * should be tied to the specified secure user id, overriding the logic above.
+ *
+ * This is only applicable when {@link #setUserAuthenticationRequired} is set to
+ * {@code true}
+ *
+ * @see KeyProtection#getBoundToSpecificSecureUserId()
+ * @hide
+ */
+ public Builder setBoundToSpecificSecureUserId(long secureUserId) {
+ mBoundToSecureUserId = secureUserId;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -793,7 +836,8 @@ public final class KeyProtection implements ProtectionParameter {
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
mUserAuthenticationValidWhileOnBody,
- mInvalidatedByBiometricEnrollment);
+ mInvalidatedByBiometricEnrollment,
+ mBoundToSecureUserId);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index f5272aa233e9..34c8d1f75f60 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -89,7 +89,10 @@ public abstract class KeymasterUtils {
* @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user
* authentication is valid as authorization for using the key or {@code -1} if every
* use of the key needs authorization.
- *
+ * @param boundToSpecificSecureUserId if non-zero, specify which SID the key will be bound to,
+ * overriding the default logic in this method where the key is bound to either the root
+ * SID of the current user, or the fingerprint SID if explicit fingerprint authorization
+ * is requested.
* @throws IllegalStateException if user authentication is required but the system is in a wrong
* state (e.g., secure lock screen not set up) for generating or importing keys that
* require user authentication.
@@ -98,7 +101,8 @@ public abstract class KeymasterUtils {
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment) {
+ boolean invalidatedByBiometricEnrollment,
+ long boundToSpecificSecureUserId) {
if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
@@ -120,7 +124,9 @@ public abstract class KeymasterUtils {
}
long sid;
- if (invalidatedByBiometricEnrollment) {
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
+ } else if (invalidatedByBiometricEnrollment) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -138,11 +144,16 @@ public abstract class KeymasterUtils {
+ "supported for keys requiring fingerprint authentication");
}
} else {
- // The key is authorized for use for the specified amount of time after the user has
- // authenticated. Whatever unlocks the secure lock screen should authorize this key.
- long rootSid = getRootSid();
+ long sid;
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
+ } else {
+ // The key is authorized for use for the specified amount of time after the user has
+ // authenticated. Whatever unlocks the secure lock screen should authorize this key.
+ sid = getRootSid();
+ }
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(rootSid));
+ KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index fb898355db92..ecf6bd4a0cf1 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -38,6 +38,7 @@ cc_library {
"ResourceTypes.cpp",
"StreamingZipInflater.cpp",
"TypeWrappers.cpp",
+ "Util.cpp",
"ZipFileRO.cpp",
"ZipUtils.cpp",
],
@@ -82,6 +83,9 @@ cc_library {
},
windows: {
enabled: true,
+ cppflags: ["-Wno-missing-field-initializers"], // The Windows compiler warns
+ // incorrectly for value
+ // initialization with {}.
},
},
}
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 55f4c3ce6e76..fe68ec01e4b7 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -27,8 +27,18 @@
namespace android {
-std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
- ATRACE_NAME("ApkAssets::Load");
+std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
+ return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
+ bool system) {
+ return ApkAssets::LoadImpl(path, system, true /*load_as_shared_library*/);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system,
+ bool load_as_shared_library) {
+ ATRACE_CALL();
::ZipArchiveHandle unmanaged_handle;
int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
if (result != 0) {
@@ -61,11 +71,13 @@ std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
loaded_apk->path_ = path;
loaded_apk->loaded_arsc_ =
LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
- loaded_apk->resources_asset_->getLength());
+ loaded_apk->resources_asset_->getLength(), system, load_as_shared_library);
if (loaded_apk->loaded_arsc_ == nullptr) {
return {};
}
- return loaded_apk;
+
+ // Need to force a move for mingw32.
+ return std::move(loaded_apk);
}
std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode /*mode*/) const {
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index e0689006d5dd..acacd7654cf1 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -288,22 +288,34 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk
{
AutoMutex _l(mLock);
const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) };
- ResTable tables[2];
-
- for (int i = 0; i < 2; ++i) {
- asset_path ap;
- ap.type = kFileTypeRegular;
- ap.path = paths[i];
- Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
- if (ass == NULL) {
- ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
- return false;
+ Asset* assets[2] = {NULL, NULL};
+ bool ret = false;
+ {
+ ResTable tables[2];
+
+ for (int i = 0; i < 2; ++i) {
+ asset_path ap;
+ ap.type = kFileTypeRegular;
+ ap.path = paths[i];
+ assets[i] = openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER, ap);
+ if (assets[i] == NULL) {
+ ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
+ goto exit;
+ }
+ if (tables[i].add(assets[i]) != NO_ERROR) {
+ ALOGW("failed to add %s to resource table", paths[i].string());
+ goto exit;
+ }
}
- tables[i].add(ass);
+ ret = tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
+ targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
}
- return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
- targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
+exit:
+ delete assets[0];
+ delete assets[1];
+ return ret;
}
bool AssetManager::addDefaultAssets()
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 8d65925a218e..542a125f018b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -18,6 +18,8 @@
#include "androidfw/AssetManager2.h"
+#include <set>
+
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "utils/ByteOrder.h"
@@ -36,13 +38,84 @@ AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
bool invalidate_caches) {
apk_assets_ = apk_assets;
+ BuildDynamicRefTable();
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
return true;
}
-const std::vector<const ApkAssets*> AssetManager2::GetApkAssets() const { return apk_assets_; }
+void AssetManager2::BuildDynamicRefTable() {
+ package_groups_.clear();
+ package_ids_.fill(0xff);
+
+ // 0x01 is reserved for the android package.
+ int next_package_id = 0x02;
+ const size_t apk_assets_count = apk_assets_.size();
+ for (size_t i = 0; i < apk_assets_count; i++) {
+ const ApkAssets* apk_asset = apk_assets_[i];
+ for (const std::unique_ptr<const LoadedPackage>& package :
+ apk_asset->GetLoadedArsc()->GetPackages()) {
+ // Get the package ID or assign one if a shared library.
+ int package_id;
+ if (package->IsDynamic()) {
+ package_id = next_package_id++;
+ } else {
+ package_id = package->GetPackageId();
+ }
+
+ // Add the mapping for package ID to index if not present.
+ uint8_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
+ package_groups_.push_back({});
+ package_groups_.back().dynamic_ref_table.mAssignedPackageId = package_id;
+ }
+ PackageGroup* package_group = &package_groups_[idx];
+
+ // Add the package and to the set of packages with the same ID.
+ package_group->packages_.push_back(package.get());
+ package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
+
+ // Add the package name -> build time ID mappings.
+ for (const DynamicPackageEntry& entry : package->GetDynamicPackageMap()) {
+ String16 package_name(entry.package_name.c_str(), entry.package_name.size());
+ package_group->dynamic_ref_table.mEntries.replaceValueFor(
+ package_name, static_cast<uint8_t>(entry.package_id));
+ }
+ }
+ }
+
+ // Now assign the runtime IDs so that we have a build-time to runtime ID map.
+ const auto package_groups_end = package_groups_.end();
+ for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
+ const std::string& package_name = iter->packages_[0]->GetPackageName();
+ for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
+ iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
+ iter->dynamic_ref_table.mAssignedPackageId);
+ }
+ }
+}
+
+void AssetManager2::DumpToLog() const {
+ base::ScopedLogSeverity _log(base::INFO);
+
+ std::string list;
+ for (size_t i = 0; i < package_ids_.size(); i++) {
+ if (package_ids_[i] != 0xff) {
+ base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
+ }
+ }
+ LOG(INFO) << "Package ID map: " << list;
+
+ for (const auto& package_group: package_groups_) {
+ list = "";
+ for (const auto& package : package_group.packages_) {
+ base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
+ }
+ LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
+ }
+}
const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
@@ -51,6 +124,18 @@ const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cooki
return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
}
+const DynamicRefTable* AssetManager2::GetDynamicRefTableForPackage(uint32_t package_id) const {
+ if (package_id >= package_ids_.size()) {
+ return nullptr;
+ }
+
+ const size_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ return nullptr;
+ }
+ return &package_groups_[idx].dynamic_ref_table;
+}
+
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
const int diff = configuration_.diff(configuration);
configuration_ = configuration;
@@ -60,7 +145,35 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
}
}
-const ResTable_config& AssetManager2::GetConfiguration() const { return configuration_; }
+std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
+ bool exclude_mipmap) {
+ ATRACE_CALL();
+ std::set<ResTable_config> configurations;
+ for (const PackageGroup& package_group : package_groups_) {
+ for (const LoadedPackage* package : package_group.packages_) {
+ if (exclude_system && package->IsSystem()) {
+ continue;
+ }
+ package->CollectConfigurations(exclude_mipmap, &configurations);
+ }
+ }
+ return configurations;
+}
+
+std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
+ bool merge_equivalent_languages) {
+ ATRACE_CALL();
+ std::set<std::string> locales;
+ for (const PackageGroup& package_group : package_groups_) {
+ for (const LoadedPackage* package : package_group.packages_) {
+ if (exclude_system && package->IsSystem()) {
+ continue;
+ }
+ package->CollectLocales(merge_equivalent_languages, &locales);
+ }
+ }
+ return locales;
+}
std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
const std::string new_path = "assets/" + filename;
@@ -106,7 +219,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
}
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
- bool stop_at_first_match, LoadedArsc::Entry* out_entry,
+ bool stop_at_first_match, LoadedArscEntry* out_entry,
ResTable_config* out_selected_config,
uint32_t* out_flags) {
ATRACE_CALL();
@@ -122,48 +235,66 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
desired_config = &density_override_config;
}
- LoadedArsc::Entry best_entry;
- ResTable_config best_config;
- int32_t best_index = -1;
- uint32_t cumulated_flags = 0;
+ const uint32_t package_id = util::get_package_id(resid);
+ const uint8_t type_id = util::get_type_id(resid);
+ const uint16_t entry_id = util::get_entry_id(resid);
- const size_t apk_asset_count = apk_assets_.size();
- for (size_t i = 0; i < apk_asset_count; i++) {
- const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
+ if (type_id == 0) {
+ LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
+ return kInvalidCookie;
+ }
- LoadedArsc::Entry current_entry;
+ const uint8_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
+ return kInvalidCookie;
+ }
+
+ LoadedArscEntry best_entry;
+ ResTable_config best_config;
+ ApkAssetsCookie best_cookie = kInvalidCookie;
+ uint32_t cumulated_flags = 0u;
+
+ const PackageGroup& package_group = package_groups_[idx];
+ const size_t package_count = package_group.packages_.size();
+ for (size_t i = 0; i < package_count; i++) {
+ LoadedArscEntry current_entry;
ResTable_config current_config;
- uint32_t flags = 0;
- if (!loaded_arsc->FindEntry(resid, *desired_config, &current_entry, &current_config, &flags)) {
+ uint32_t current_flags = 0;
+
+ const LoadedPackage* loaded_package = package_group.packages_[i];
+ if (!loaded_package->FindEntry(type_id - 1, entry_id, *desired_config, &current_entry,
+ &current_config, &current_flags)) {
continue;
}
- cumulated_flags |= flags;
+ cumulated_flags |= current_flags;
- if (best_index == -1 || current_config.isBetterThan(best_config, desired_config)) {
+ if (best_cookie == kInvalidCookie || current_config.isBetterThan(best_config, desired_config)) {
best_entry = current_entry;
best_config = current_config;
- best_index = static_cast<int32_t>(i);
+ best_cookie = package_group.cookies_[i];
if (stop_at_first_match) {
break;
}
}
}
- if (best_index == -1) {
+ if (best_cookie == kInvalidCookie) {
return kInvalidCookie;
}
*out_entry = best_entry;
+ out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
*out_selected_config = best_config;
*out_flags = cumulated_flags;
- return best_index;
+ return best_cookie;
}
bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
ATRACE_CALL();
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config config;
uint32_t flags = 0u;
ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
@@ -172,14 +303,13 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
return false;
}
- const std::string* package_name =
- apk_assets_[cookie]->GetLoadedArsc()->GetPackageNameForId(resid);
- if (package_name == nullptr) {
+ const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
+ if (package == nullptr) {
return false;
}
- out_name->package = package_name->data();
- out_name->package_len = package_name->size();
+ out_name->package = package->GetPackageName().data();
+ out_name->package_len = package->GetPackageName().size();
out_name->type = entry.type_string_ref.string8(&out_name->type_len);
out_name->type16 = nullptr;
@@ -202,7 +332,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
}
bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config config;
ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
false /* stop_at_first_match */, &entry, &config, out_flags);
@@ -215,7 +345,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
uint32_t* out_flags) {
ATRACE_CALL();
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config config;
uint32_t flags = 0u;
ApkAssetsCookie cookie =
@@ -227,18 +357,60 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
if (!may_be_bag) {
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
+ return kInvalidCookie;
}
- return kInvalidCookie;
+
+ // 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 = config;
+ *out_flags = flags;
+ return cookie;
}
const Res_value* device_value = reinterpret_cast<const Res_value*>(
reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
out_value->copyFrom_dtoh(*device_value);
+
+ // Convert the package ID to the runtime assigned package ID.
+ entry.dynamic_ref_table->lookupResourceValue(out_value);
+
*out_selected_config = config;
*out_flags = flags;
return cookie;
}
+ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
+ ResTable_config* in_out_selected_config,
+ uint32_t* in_out_flags,
+ ResTable_ref* out_last_reference) {
+ ATRACE_CALL();
+ constexpr const int kMaxIterations = 20;
+
+ out_last_reference->ident = 0u;
+ for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
+ in_out_value->data != 0u && iteration < kMaxIterations;
+ iteration++) {
+ if (out_last_reference != nullptr) {
+ out_last_reference->ident = 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;
+ }
+ if (in_out_flags != nullptr) {
+ *in_out_flags |= new_flags;
+ }
+ if (out_last_reference->ident == in_out_value->data) {
+ // This reference can't be resolved, so exit now and let the caller deal with it.
+ return cookie;
+ }
+ }
+ return cookie;
+}
+
const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
ATRACE_CALL();
@@ -247,7 +419,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
return cached_iter->second.get();
}
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config config;
uint32_t flags = 0u;
ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
@@ -270,8 +442,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
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);
- const uint32_t parent = dtohl(map->parent.ident);
- if (parent == 0) {
+ uint32_t parent_resid = dtohl(map->parent.ident);
+ if (parent_resid == 0) {
// There is no parent, 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;
@@ -279,9 +451,18 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
ResolvedBag::Entry* new_entry = new_bag->entries;
for (; map_entry != map_entry_end; ++map_entry) {
+ uint32_t new_key = dtohl(map_entry->name.ident);
+ if (!util::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) {
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
+ return nullptr;
+ }
+ }
new_entry->cookie = cookie;
new_entry->value.copyFrom_dtoh(map_entry->value);
- new_entry->key = dtohl(map_entry->name.ident);
+ new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
++new_entry;
@@ -293,10 +474,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
return result;
}
+ // In case the parent is a dynamic reference, resolve it.
+ entry.dynamic_ref_table->lookupResourceId(&parent_resid);
+
// Get the parent and do a merge of the keys.
- const ResolvedBag* parent_bag = GetBag(parent);
+ const ResolvedBag* parent_bag = GetBag(parent_resid);
if (parent_bag == nullptr) {
// 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;
}
@@ -315,7 +500,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
// The keys are expected to be in sorted order. Merge the two bags.
while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
- const uint32_t child_key = dtohl(map_entry->name.ident);
+ uint32_t child_key = dtohl(map_entry->name.ident);
+ if (!util::is_internal_resid(child_key)) {
+ if (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;
+ }
+ }
+
if (child_key <= parent_entry->key) {
// Use the child key if it comes before the parent
// or is equal to the parent (overrides).
@@ -340,9 +532,16 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
// Finish the child entries if they exist.
while (map_entry != map_entry_end) {
+ uint32_t new_key = dtohl(map_entry->name.ident);
+ if (!util::is_internal_resid(new_key)) {
+ if (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;
+ }
+ }
new_entry->cookie = cookie;
new_entry->value.copyFrom_dtoh(map_entry->value);
- new_entry->key = dtohl(map_entry->name.ident);
+ new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
++map_entry;
@@ -372,6 +571,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
return result;
}
+uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
+ const std::string& fallback_type,
+ const std::string& fallback_package) {
+ (void)resource_name;
+ (void)fallback_type;
+ (void)fallback_package;
+ return 0u;
+}
+
void AssetManager2::InvalidateCaches(uint32_t diff) {
if (diff == 0xffffffffu) {
// Everything must go.
@@ -511,12 +719,43 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
type_spec_flags |= entry.type_spec_flags;
switch (entry.value.dataType) {
+ case Res_value::TYPE_NULL:
+ return kInvalidCookie;
+
case Res_value::TYPE_ATTRIBUTE:
resid = entry.value.data;
break;
- case Res_value::TYPE_NULL:
- return kInvalidCookie;
+ case Res_value::TYPE_DYNAMIC_ATTRIBUTE: {
+ // Resolve the dynamic attribute to a normal attribute
+ // (with the right package ID).
+ resid = entry.value.data;
+ const DynamicRefTable* ref_table =
+ asset_manager_->GetDynamicRefTableForPackage(package_idx);
+ if (ref_table == nullptr || ref_table->lookupResourceId(&resid) != NO_ERROR) {
+ LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic attribute 0x%08x", resid);
+ return kInvalidCookie;
+ }
+ } break;
+
+ case Res_value::TYPE_DYNAMIC_REFERENCE: {
+ // Resolve the dynamic reference to a normal reference
+ // (with the right package ID).
+ out_value->dataType = Res_value::TYPE_REFERENCE;
+ out_value->data = entry.value.data;
+ const DynamicRefTable* ref_table =
+ asset_manager_->GetDynamicRefTableForPackage(package_idx);
+ if (ref_table == nullptr || ref_table->lookupResourceId(&out_value->data) != NO_ERROR) {
+ LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic reference 0x%08x",
+ out_value->data);
+ return kInvalidCookie;
+ }
+
+ if (out_flags != nullptr) {
+ *out_flags = type_spec_flags;
+ }
+ return entry.cookie;
+ }
default:
*out_value = entry.value;
@@ -550,14 +789,14 @@ bool Theme::SetTo(const Theme& o) {
type_spec_flags_ = o.type_spec_flags_;
- for (size_t p = 0; p < arraysize(packages_); p++) {
+ for (size_t p = 0; p < packages_.size(); p++) {
const Package* package = o.packages_[p].get();
if (package == nullptr) {
packages_[p].reset();
continue;
}
- for (size_t t = 0; t < arraysize(package->types); t++) {
+ for (size_t t = 0; t < package->types.size(); t++) {
const Type* type = package->types[t].get();
if (type == nullptr) {
packages_[p]->types[t].reset();
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
index 747aa4ad20e6..d8adbe5ac85d 100644
--- a/libs/androidfw/ChunkIterator.cpp
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Chunk.h"
+#include "androidfw/Chunk.h"
#include "android-base/logging.h"
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 94d0d4638ba8..cb589ec41034 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -32,15 +32,15 @@
#endif
#endif
-#include "Chunk.h"
#include "androidfw/ByteBucketArray.h"
+#include "androidfw/Chunk.h"
#include "androidfw/Util.h"
using android::base::StringPrintf;
namespace android {
-namespace {
+constexpr const static int kAppPackageId = 0x7f;
// Element of a TypeSpec array. See TypeSpec.
struct Type {
@@ -76,6 +76,8 @@ struct TypeSpec {
// itself.
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+namespace {
+
// Builder that helps accumulate Type structs and then create a single
// contiguous block of memory to store both the TypeSpec struct and
// the Type structs.
@@ -110,37 +112,21 @@ class TypeSpecPtrBuilder {
} // namespace
-class LoadedPackage {
- public:
- LoadedPackage() = default;
-
- bool FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
- LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
- uint32_t* out_flags) const;
-
- ResStringPool type_string_pool_;
- ResStringPool key_string_pool_;
- std::string package_name_;
- int package_id_ = -1;
-
- ByteBucketArray<TypeSpecPtr> type_specs_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
-};
-
-bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
- LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+ LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
uint32_t* out_flags) const {
- ATRACE_NAME("LoadedPackage::FindEntry");
- const TypeSpecPtr& ptr = type_specs_[type_id];
+ ATRACE_CALL();
+
+ // If the type IDs are offset in this package, we need to take that into account when searching
+ // for a type.
+ const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
if (ptr == nullptr) {
return false;
}
// Don't bother checking if the entry ID is larger than
// the number of entries.
- if (entry_id >= dtohl(ptr->type_spec->entryCount)) {
+ if (entry_idx >= dtohl(ptr->type_spec->entryCount)) {
return false;
}
@@ -156,10 +142,10 @@ bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
size_t entry_count = dtohl(type->type->entryCount);
- if (entry_id < entry_count) {
+ if (entry_idx < entry_count) {
const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
- const uint32_t offset = dtohl(entry_offsets[entry_id]);
+ const uint32_t offset = dtohl(entry_offsets[entry_idx]);
if (offset != ResTable_type::NO_ENTRY) {
// There is an entry for this resource, record it.
best_config = &type->configuration;
@@ -175,7 +161,7 @@ bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable
}
const uint32_t* flags = reinterpret_cast<const uint32_t*>(ptr->type_spec + 1);
- *out_flags = dtohl(flags[entry_id]);
+ *out_flags = dtohl(flags[entry_idx]);
*out_selected_config = *best_config;
const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
@@ -191,9 +177,10 @@ bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable
// forward declarations and incomplete types.
LoadedArsc::~LoadedArsc() {}
-bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
- ResTable_config* out_selected_config, uint32_t* out_flags) const {
- ATRACE_NAME("LoadedArsc::FindEntry");
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
+ LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
+ uint32_t* out_flags) const {
+ ATRACE_CALL();
const uint8_t package_id = util::get_package_id(resid);
const uint8_t type_id = util::get_type_id(resid);
const uint16_t entry_id = util::get_entry_id(resid);
@@ -212,11 +199,11 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, Entry*
return false;
}
-const std::string* LoadedArsc::GetPackageNameForId(uint32_t resid) const {
+const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
const uint8_t package_id = util::get_package_id(resid);
for (const auto& loaded_package : packages_) {
if (loaded_package->package_id_ == package_id) {
- return &loaded_package->package_name_;
+ return loaded_package.get();
}
}
return nullptr;
@@ -334,15 +321,84 @@ static bool VerifyType(const Chunk& chunk) {
return true;
}
-static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
+void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
+ std::set<ResTable_config>* out_configs) const {
+ const static std::u16string kMipMap = u"mipmap";
+ const size_t type_count = type_specs_.size();
+ for (size_t i = 0; i < type_count; i++) {
+ const util::unique_cptr<TypeSpec>& 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;
+ }
+ }
+ }
+
+ for (size_t j = 0; j < type_spec->type_count; j++) {
+ out_configs->insert(type_spec->types[j].configuration);
+ }
+ }
+ }
+}
+
+void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const {
+ char temp_locale[RESTABLE_MAX_LOCALE_LEN];
+ const size_t type_count = type_specs_.size();
+ for (size_t i = 0; i < type_count; i++) {
+ const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
+ if (type_spec != nullptr) {
+ for (size_t j = 0; j < type_spec->type_count; j++) {
+ const ResTable_config& configuration = type_spec->types[j].configuration;
+ if (configuration.locale != 0) {
+ configuration.getBcp47Locale(temp_locale, canonicalize);
+ std::string locale(temp_locale);
+ out_locales->insert(std::move(locale));
+ }
+ }
+ }
+ }
+}
+
+std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
ATRACE_CALL();
+ std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};
+
const ResTable_package* header = chunk.header<ResTable_package>();
if (header == nullptr) {
LOG(ERROR) << "Chunk RES_TABLE_PACKAGE_TYPE is too small.";
- return false;
+ return {};
}
loaded_package->package_id_ = dtohl(header->id);
+ if (loaded_package->package_id_ == 0) {
+ // Package ID of 0 means this is a shared library.
+ loaded_package->dynamic_ = true;
+ }
+
+ if (header->header.headerSize >= sizeof(ResTable_package)) {
+ uint32_t type_id_offset = dtohl(header->typeIdOffset);
+ if (type_id_offset > std::numeric_limits<uint8_t>::max()) {
+ LOG(ERROR) << "Type ID offset in RES_TABLE_PACKAGE_TYPE is too large.";
+ return {};
+ }
+ loaded_package->type_id_offset_ = static_cast<int>(type_id_offset);
+ }
+
+ util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
+ &loaded_package->package_name_);
// A TypeSpec builder. We use this to accumulate the set of Types
// available for a TypeSpec, and later build a single, contiguous block
@@ -367,7 +423,7 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
child_chunk.header<ResStringPool_header>(), child_chunk.size());
if (err != NO_ERROR) {
LOG(ERROR) << "Corrupt package type string pool.";
- return false;
+ return {};
}
} else if (pool_address == header_address + dtohl(header->keyStrings)) {
// This string pool is the key string pool.
@@ -375,7 +431,7 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
child_chunk.header<ResStringPool_header>(), child_chunk.size());
if (err != NO_ERROR) {
LOG(ERROR) << "Corrupt package key string pool.";
- return false;
+ return {};
}
} else {
LOG(WARNING) << "Too many string pool chunks found in package.";
@@ -390,9 +446,8 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
TypeSpecPtr type_spec_ptr = types_builder->Build();
if (type_spec_ptr == nullptr) {
LOG(ERROR) << "Too many type configurations, overflow detected.";
- return false;
+ return {};
}
-
loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
types_builder = {};
@@ -402,12 +457,18 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
if (type_spec == nullptr) {
LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE is too small.";
- return false;
+ return {};
}
if (type_spec->id == 0) {
LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.";
- return false;
+ return {};
+ }
+
+ if (loaded_package->type_id_offset_ + static_cast<int>(type_spec->id) >
+ std::numeric_limits<uint8_t>::max()) {
+ LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has out of range ID.";
+ return {};
}
// The data portion of this chunk contains entry_count 32bit entries,
@@ -419,12 +480,12 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
// space for entries (EEEE) in the resource ID 0xPPTTEEEE.
if (entry_count > std::numeric_limits<uint16_t>::max()) {
LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_SPEC_TYPE: " << entry_count << ".";
- return false;
+ return {};
}
if (entry_count * sizeof(uint32_t) > chunk.data_size()) {
LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_TYPE_SPEC_TYPE.";
- return false;
+ return {};
}
last_type_idx = type_spec->id - 1;
@@ -435,28 +496,63 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
const ResTable_type* type = child_chunk.header<ResTable_type>();
if (type == nullptr) {
LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small.";
- return false;
+ return {};
}
if (type->id == 0) {
LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE has invalid ID 0.";
- return false;
+ return {};
}
// Type chunks must be preceded by their TypeSpec chunks.
if (!types_builder || type->id - 1 != last_type_idx) {
LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without "
"RES_TABLE_TYPE_SPEC_TYPE.";
- return false;
+ return {};
}
if (!VerifyType(child_chunk)) {
- return false;
+ return {};
}
types_builder->AddType(type);
} break;
+ case RES_TABLE_LIBRARY_TYPE: {
+ const ResTable_lib_header* lib = child_chunk.header<ResTable_lib_header>();
+ if (lib == nullptr) {
+ LOG(ERROR) << "Chunk RES_TABLE_LIBRARY_TYPE is too small.";
+ return {};
+ }
+
+ if (child_chunk.data_size() / sizeof(ResTable_lib_entry) < dtohl(lib->count)) {
+ LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_LIBRARY_TYPE.";
+ return {};
+ }
+
+ 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);
+ for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
+ std::string package_name;
+ util::ReadUtf16StringFromDevice(entry_iter->packageName,
+ arraysize(entry_iter->packageName), &package_name);
+
+ if (dtohl(entry_iter->packageId) >= std::numeric_limits<uint8_t>::max()) {
+ LOG(ERROR) << base::StringPrintf(
+ "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.",
+ dtohl(entry_iter->packageId), package_name.c_str());
+ return {};
+ }
+
+ loaded_package->dynamic_package_map_.emplace_back(std::move(package_name),
+ dtohl(entry_iter->packageId));
+ }
+
+ } break;
+
default:
LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
break;
@@ -468,19 +564,19 @@ static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
TypeSpecPtr type_spec_ptr = types_builder->Build();
if (type_spec_ptr == nullptr) {
LOG(ERROR) << "Too many type configurations, overflow detected.";
- return false;
+ return {};
}
loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
}
if (iter.HadError()) {
LOG(ERROR) << iter.GetLastError();
- return false;
+ return {};
}
- return true;
+ return loaded_package;
}
-bool LoadedArsc::LoadTable(const Chunk& chunk) {
+bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
ATRACE_CALL();
const ResTable_header* header = chunk.header<ResTable_header>();
if (header == nullptr) {
@@ -520,10 +616,16 @@ bool LoadedArsc::LoadTable(const Chunk& chunk) {
}
packages_seen++;
- std::unique_ptr<LoadedPackage> loaded_package = util::make_unique<LoadedPackage>();
- if (!LoadPackage(child_chunk, loaded_package.get())) {
+ std::unique_ptr<LoadedPackage> loaded_package = LoadedPackage::Load(child_chunk);
+ if (!loaded_package) {
return false;
}
+
+ // Mark the package as dynamic if we are forcefully loading the Apk as a shared library.
+ if (loaded_package->package_id_ == kAppPackageId) {
+ loaded_package->dynamic_ = load_as_shared_library;
+ }
+ loaded_package->system_ = system_;
packages_.push_back(std::move(loaded_package));
} break;
@@ -540,18 +642,20 @@ bool LoadedArsc::LoadTable(const Chunk& chunk) {
return true;
}
-std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len) {
+std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len, bool system,
+ bool load_as_shared_library) {
ATRACE_CALL();
// Not using make_unique because the constructor is private.
std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
+ loaded_arsc->system_ = system;
ChunkIterator iter(data, len);
while (iter.HasNext()) {
const Chunk chunk = iter.Next();
switch (chunk.type()) {
case RES_TABLE_TYPE:
- if (!loaded_arsc->LoadTable(chunk)) {
+ if (!loaded_arsc->LoadTable(chunk, load_as_shared_library)) {
return {};
}
break;
@@ -566,7 +670,9 @@ std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len) {
LOG(ERROR) << iter.GetLastError();
return {};
}
- return loaded_arsc;
+
+ // Need to force a move for mingw32.
+ return std::move(loaded_arsc);
}
} // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index a4bcc624ef31..763a178ed43b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1907,7 +1907,7 @@ int ResTable_config::compare(const ResTable_config& o) const {
if (diff != 0) return diff;
diff = (int32_t)(screenLayout2 - o.screenLayout2);
if (diff != 0) return diff;
- diff = (int32_t)(colorimetry - o.colorimetry);
+ diff = (int32_t)(colorMode - o.colorMode);
if (diff != 0) return diff;
diff = (int32_t)(uiMode - o.uiMode);
if (diff != 0) return diff;
@@ -1969,8 +1969,8 @@ int ResTable_config::compareLogical(const ResTable_config& o) const {
if (screenLayout2 != o.screenLayout2) {
return screenLayout2 < o.screenLayout2 ? -1 : 1;
}
- if (colorimetry != o.colorimetry) {
- return colorimetry < o.colorimetry ? -1 : 1;
+ if (colorMode != o.colorMode) {
+ return colorMode < o.colorMode ? -1 : 1;
}
if (uiMode != o.uiMode) {
return uiMode < o.uiMode ? -1 : 1;
@@ -1997,8 +1997,8 @@ int ResTable_config::diff(const ResTable_config& o) const {
if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
- if ((colorimetry & MASK_WIDE_COLOR_GAMUT) != (o.colorimetry & MASK_WIDE_COLOR_GAMUT)) diffs |= CONFIG_COLORIMETRY;
- if ((colorimetry & MASK_HDR) != (o.colorimetry & MASK_HDR)) diffs |= CONFIG_COLORIMETRY;
+ if ((colorMode & MASK_WIDE_COLOR_GAMUT) != (o.colorMode & MASK_WIDE_COLOR_GAMUT)) diffs |= CONFIG_COLOR_MODE;
+ if ((colorMode & MASK_HDR) != (o.colorMode & MASK_HDR)) diffs |= CONFIG_COLOR_MODE;
if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
@@ -2110,14 +2110,14 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
}
}
- if (colorimetry || o.colorimetry) {
- if (((colorimetry^o.colorimetry) & MASK_HDR) != 0) {
- if (!(colorimetry & MASK_HDR)) return false;
- if (!(o.colorimetry & MASK_HDR)) return true;
+ if (colorMode || o.colorMode) {
+ if (((colorMode^o.colorMode) & MASK_HDR) != 0) {
+ if (!(colorMode & MASK_HDR)) return false;
+ if (!(o.colorMode & MASK_HDR)) return true;
}
- if (((colorimetry^o.colorimetry) & MASK_WIDE_COLOR_GAMUT) != 0) {
- if (!(colorimetry & MASK_WIDE_COLOR_GAMUT)) return false;
- if (!(o.colorimetry & MASK_WIDE_COLOR_GAMUT)) return true;
+ if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0) {
+ if (!(colorMode & MASK_WIDE_COLOR_GAMUT)) return false;
+ if (!(o.colorMode & MASK_WIDE_COLOR_GAMUT)) return true;
}
}
@@ -2408,14 +2408,14 @@ bool ResTable_config::isBetterThan(const ResTable_config& o,
}
}
- if (colorimetry || o.colorimetry) {
- if (((colorimetry^o.colorimetry) & MASK_WIDE_COLOR_GAMUT) != 0 &&
- (requested->colorimetry & MASK_WIDE_COLOR_GAMUT)) {
- return colorimetry & MASK_WIDE_COLOR_GAMUT;
+ if (colorMode || o.colorMode) {
+ if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0 &&
+ (requested->colorMode & MASK_WIDE_COLOR_GAMUT)) {
+ return colorMode & MASK_WIDE_COLOR_GAMUT;
}
- if (((colorimetry^o.colorimetry) & MASK_HDR) != 0 &&
- (requested->colorimetry & MASK_HDR)) {
- return colorimetry & MASK_HDR;
+ if (((colorMode^o.colorMode) & MASK_HDR) != 0 &&
+ (requested->colorMode & MASK_HDR)) {
+ return colorMode & MASK_HDR;
}
}
@@ -2669,14 +2669,14 @@ bool ResTable_config::match(const ResTable_config& settings) const {
return false;
}
- const int hdr = colorimetry & MASK_HDR;
- const int setHdr = settings.colorimetry & MASK_HDR;
+ const int hdr = colorMode & MASK_HDR;
+ const int setHdr = settings.colorMode & MASK_HDR;
if (hdr != 0 && hdr != setHdr) {
return false;
}
- const int wideColorGamut = colorimetry & MASK_WIDE_COLOR_GAMUT;
- const int setWideColorGamut = settings.colorimetry & MASK_WIDE_COLOR_GAMUT;
+ const int wideColorGamut = colorMode & MASK_WIDE_COLOR_GAMUT;
+ const int setWideColorGamut = settings.colorMode & MASK_WIDE_COLOR_GAMUT;
if (wideColorGamut != 0 && wideColorGamut != setWideColorGamut) {
return false;
}
@@ -3000,9 +3000,9 @@ String8 ResTable_config::toString() const {
break;
}
}
- if ((colorimetry&MASK_HDR) != 0) {
+ if ((colorMode&MASK_HDR) != 0) {
if (res.size() > 0) res.append("-");
- switch (colorimetry&MASK_HDR) {
+ switch (colorMode&MASK_HDR) {
case ResTable_config::HDR_NO:
res.append("lowdr");
break;
@@ -3010,13 +3010,13 @@ String8 ResTable_config::toString() const {
res.append("highdr");
break;
default:
- res.appendFormat("hdr=%d", dtohs(colorimetry&MASK_HDR));
+ res.appendFormat("hdr=%d", dtohs(colorMode&MASK_HDR));
break;
}
}
- if ((colorimetry&MASK_WIDE_COLOR_GAMUT) != 0) {
+ if ((colorMode&MASK_WIDE_COLOR_GAMUT) != 0) {
if (res.size() > 0) res.append("-");
- switch (colorimetry&MASK_WIDE_COLOR_GAMUT) {
+ switch (colorMode&MASK_WIDE_COLOR_GAMUT) {
case ResTable_config::WIDE_COLOR_GAMUT_NO:
res.append("nowidecg");
break;
@@ -3024,7 +3024,7 @@ String8 ResTable_config::toString() const {
res.append("widecg");
break;
default:
- res.appendFormat("wideColorGamut=%d", dtohs(colorimetry&MASK_WIDE_COLOR_GAMUT));
+ res.appendFormat("wideColorGamut=%d", dtohs(colorMode&MASK_WIDE_COLOR_GAMUT));
break;
}
}
diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp
new file mode 100644
index 000000000000..202bc8e5743a
--- /dev/null
+++ b/libs/androidfw/Util.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/Util.h"
+
+#include <string>
+
+#include "utils/ByteOrder.h"
+#include "utils/Unicode.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+namespace android {
+namespace util {
+
+void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out) {
+ char buf[5];
+ while (*src && len != 0) {
+ char16_t c = static_cast<char16_t>(dtohs(*src));
+ utf16_to_utf8(&c, 1, buf, sizeof(buf));
+ out->append(buf, strlen(buf));
+ ++src;
+ --len;
+ }
+}
+
+} // namespace util
+} // namespace android
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index a3d67f04eb90..6d1578c2d50e 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -31,7 +31,9 @@ namespace android {
// Holds an APK.
class ApkAssets {
public:
- static std::unique_ptr<ApkAssets> Load(const std::string& path);
+ static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false);
+ static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path,
+ bool system = false);
std::unique_ptr<Asset> Open(const std::string& path,
Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
@@ -43,6 +45,9 @@ class ApkAssets {
private:
DISALLOW_COPY_AND_ASSIGN(ApkAssets);
+ static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path, bool system,
+ bool load_as_shared_library);
+
ApkAssets() = default;
struct ZipArchivePtrCloser {
@@ -54,7 +59,7 @@ class ApkAssets {
ZipArchivePtr zip_handle_;
std::string path_;
std::unique_ptr<Asset> resources_asset_;
- std::unique_ptr<LoadedArsc> loaded_arsc_;
+ std::unique_ptr<const LoadedArsc> loaded_arsc_;
};
} // namespace android
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 66d5034463a5..81cdc46be0b4 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -19,7 +19,9 @@
#include "android-base/macros.h"
+#include <array>
#include <limits>
+#include <set>
#include <unordered_map>
#include "androidfw/ApkAssets.h"
@@ -95,18 +97,39 @@ class AssetManager2 : public ::AAssetManager {
// new resource IDs.
bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
- const std::vector<const ApkAssets*> GetApkAssets() const;
+ inline const std::vector<const ApkAssets*> GetApkAssets() const { return apk_assets_; }
// Returns the string pool for the given asset cookie.
// Use the string pool returned here with a valid Res_value object of
// type Res_value::TYPE_STRING.
const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const;
+ // Returns the DynamicRefTable for the given package ID.
+ const DynamicRefTable* GetDynamicRefTableForPackage(uint32_t package_id) const;
+
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
void SetConfiguration(const ResTable_config& configuration);
- const ResTable_config& GetConfiguration() const;
+ inline const ResTable_config& GetConfiguration() const { return configuration_; }
+
+ // Returns all configurations for which there are resources defined. 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);
+
+ // Returns all the locales for which there are resources defined. This includes resource
+ // locales in all the ApkAssets set for this AssetManager.
+ // If `exclude_system` is set to true, resource locales from system APKs
+ // ('android' package, other libraries) will be excluded from the list.
+ // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
+ // and de-duped in the resulting list.
+ std::set<std::string> GetResourceLocales(bool exclude_system = false,
+ bool merge_equivalent_languages = false);
// Searches the set of APKs loaded by this AssetManager and opens the first one found located
// in the assets/ directory.
@@ -145,6 +168,14 @@ class AssetManager2 : public ::AAssetManager {
// Returns false if the resource was not found.
bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
+ // 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 = {});
+
// 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().
@@ -158,6 +189,22 @@ class AssetManager2 : public ::AAssetManager {
Res_value* out_value, ResTable_config* out_selected_config,
uint32_t* out_flags);
+ // 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.
+ // 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,
+ ResTable_ref* out_last_reference);
+
// 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:
@@ -173,6 +220,8 @@ class AssetManager2 : public ::AAssetManager {
// Creates a new Theme from this AssetManager.
std::unique_ptr<Theme> NewTheme();
+ void DumpToLog() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(AssetManager2);
@@ -189,9 +238,13 @@ class AssetManager2 : public ::AAssetManager {
// `out_flags` stores the resulting bitmask of configuration axis with which the resource
// value varies.
ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+ LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
uint32_t* out_flags);
+ // Assigns package IDs to all shared library ApkAssets.
+ // Should be called whenever the ApkAssets are changed.
+ void BuildDynamicRefTable();
+
// Purge all resources that are cached and vary by the configuration axis denoted by the
// bitmask `diff`.
void InvalidateCaches(uint32_t diff);
@@ -200,6 +253,22 @@ class AssetManager2 : public ::AAssetManager {
// have a longer lifetime.
std::vector<const ApkAssets*> apk_assets_;
+ struct PackageGroup {
+ std::vector<const LoadedPackage*> packages_;
+ std::vector<ApkAssetsCookie> cookies_;
+ DynamicRefTable dynamic_ref_table;
+ };
+
+ // DynamicRefTables for shared library package resolution.
+ // These are ordered according to apk_assets_. The mappings may change depending on what is
+ // in apk_assets_, therefore they must be stored in the AssetManager and not in the
+ // immutable ApkAssets class.
+ std::vector<PackageGroup> package_groups_;
+
+ // An array mapping package ID to index into package_groups. This keeps the lookup fast
+ // without taking too much memory.
+ std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
+
// The current configuration set for this AssetManager. When this changes, cached resources
// may need to be purged.
ResTable_config configuration_;
@@ -279,12 +348,12 @@ class Theme {
struct Package {
// Each element of Type will be a dynamically sized object
// allocated to have the entries stored contiguously with the Type.
- util::unique_cptr<Type> types[kTypeCount];
+ std::array<util::unique_cptr<Type>, kTypeCount> types;
};
AssetManager2* asset_manager_;
uint32_t type_spec_flags_ = 0u;
- std::unique_ptr<Package> packages_[kPackageCount];
+ std::array<std::unique_ptr<Package>, kPackageCount> packages_;
};
inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; }
diff --git a/libs/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index e87b94087450..e87b94087450 100644
--- a/libs/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index e2e56c88ee1d..91a7cb7f45f9 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -18,24 +18,120 @@
#define LOADEDARSC_H_
#include <memory>
+#include <set>
#include <vector>
#include "android-base/macros.h"
+#include "androidfw/ByteBucketArray.h"
+#include "androidfw/Chunk.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
namespace android {
-class Chunk;
-class LoadedPackage;
+class DynamicPackageEntry {
+ public:
+ DynamicPackageEntry() = default;
+ DynamicPackageEntry(std::string&& package_name, int package_id)
+ : package_name(std::move(package_name)), package_id(package_id) {}
+
+ std::string package_name;
+ int package_id = 0;
+};
+
+struct LoadedArscEntry {
+ // A pointer to the resource table entry for this resource.
+ // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+ // a ResTable_map_entry and processed as a bag/map.
+ const ResTable_entry* entry = nullptr;
+
+ // The dynamic package ID map for the package from which this resource came from.
+ const DynamicRefTable* dynamic_ref_table = nullptr;
+
+ // The string pool reference to the type's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef type_string_ref;
+
+ // The string pool reference to the entry's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef entry_string_ref;
+};
+
+struct TypeSpec;
+class LoadedArsc;
+
+class LoadedPackage {
+ friend class LoadedArsc;
+
+ public:
+ bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+ LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
+ uint32_t* out_flags) const;
+
+ // Returns the string pool where type names are stored.
+ inline const ResStringPool* GetTypeStringPool() const { return &type_string_pool_; }
+
+ // Returns the string pool where the names of resource entries are stored.
+ inline const ResStringPool* GetKeyStringPool() const { return &key_string_pool_; }
+
+ inline const std::string& GetPackageName() const { return package_name_; }
+
+ inline int GetPackageId() const { return package_id_; }
+
+ // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
+ inline bool IsDynamic() const { return dynamic_; }
+
+ // Returns true if this package originates from a system provided resource.
+ inline bool IsSystem() const { return system_; }
+
+ // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
+ // package could have been assigned a different package ID than what this LoadedPackage was
+ // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
+ inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
+ return dynamic_package_map_;
+ }
+
+ // 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;
+
+ // Populates a set of strings representing locales.
+ // If `canonicalize` is set to true, each locale is transformed into its canonical format
+ // before being inserted into the set. This may cause some equivalent locales to de-dupe.
+ void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
+
+ static std::unique_ptr<LoadedPackage> Load(const Chunk& chunk);
+
+ LoadedPackage() = default;
+
+ ResStringPool type_string_pool_;
+ ResStringPool key_string_pool_;
+ std::string package_name_;
+ int package_id_ = -1;
+ int type_id_offset_ = 0;
+ bool dynamic_ = false;
+ bool system_ = false;
+
+ ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
+ std::vector<DynamicPackageEntry> dynamic_package_map_;
+};
// Read-only view into a resource table. This class validates all data
// when loading, including offsets and lengths.
class LoadedArsc {
public:
- // Load the resource table from memory. The data's lifetime must out-live the
- // object returned from this method.
- static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len);
+ // Load a resource table from memory pointed to by `data` of size `len`.
+ // The lifetime of `data` must out-live the LoadedArsc returned from this method.
+ // If `system` is set to true, the LoadedArsc is considered as a system provided resource.
+ // 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 void* data, size_t len, bool system = false,
+ bool load_as_shared_library = false);
~LoadedArsc();
@@ -43,39 +139,33 @@ class LoadedArsc {
// (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
inline const ResStringPool* GetStringPool() const { return &global_string_pool_; }
- struct Entry {
- // A pointer to the resource table entry for this resource.
- // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
- // a ResTable_map_entry and processed as a bag/map.
- const ResTable_entry* entry = nullptr;
-
- // The string pool reference to the type's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef type_string_ref;
-
- // The string pool reference to the entry's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef entry_string_ref;
- };
-
// Finds the resource with ID `resid` with the best value for configuration `config`.
// The parameter `out_entry` will be filled with the resulting resource entry.
// The resource entry can be a simple entry (ResTable_entry) or a complex bag
// (ResTable_entry_map).
- bool FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
+ bool FindEntry(uint32_t resid, const ResTable_config& config, LoadedArscEntry* out_entry,
ResTable_config* selected_config, uint32_t* out_flags) const;
// Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
- const std::string* GetPackageNameForId(uint32_t resid) const;
+ const LoadedPackage* GetPackageForId(uint32_t resid) const;
+
+ // Returns true if this is a system provided resource.
+ inline bool IsSystem() const { return system_; }
+
+ // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
+ inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
+ return packages_;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
LoadedArsc() = default;
- bool LoadTable(const Chunk& chunk);
+ bool LoadTable(const Chunk& chunk, bool load_as_shared_library);
ResStringPool global_string_pool_;
- std::vector<std::unique_ptr<LoadedPackage>> packages_;
+ std::vector<std::unique_ptr<const LoadedPackage>> packages_;
+ bool system_ = false;
};
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 1e4aee9d18e7..04a5d958c614 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1147,25 +1147,25 @@ struct ResTable_config
};
enum {
- // colorimetry bits for wide-color gamut/narrow-color gamut.
+ // colorMode bits for wide-color gamut/narrow-color gamut.
MASK_WIDE_COLOR_GAMUT = 0x03,
WIDE_COLOR_GAMUT_ANY = ACONFIGURATION_WIDE_COLOR_GAMUT_ANY,
WIDE_COLOR_GAMUT_NO = ACONFIGURATION_WIDE_COLOR_GAMUT_NO,
WIDE_COLOR_GAMUT_YES = ACONFIGURATION_WIDE_COLOR_GAMUT_YES,
- // colorimetry bits for HDR/LDR.
+ // colorMode bits for HDR/LDR.
MASK_HDR = 0x0c,
- SHIFT_COLORIMETRY_HDR = 2,
- HDR_ANY = ACONFIGURATION_HDR_ANY << SHIFT_COLORIMETRY_HDR,
- HDR_NO = ACONFIGURATION_HDR_NO << SHIFT_COLORIMETRY_HDR,
- HDR_YES = ACONFIGURATION_HDR_YES << SHIFT_COLORIMETRY_HDR,
+ SHIFT_COLOR_MODE_HDR = 2,
+ HDR_ANY = ACONFIGURATION_HDR_ANY << SHIFT_COLOR_MODE_HDR,
+ HDR_NO = ACONFIGURATION_HDR_NO << SHIFT_COLOR_MODE_HDR,
+ HDR_YES = ACONFIGURATION_HDR_YES << SHIFT_COLOR_MODE_HDR,
};
// An extension of screenConfig.
union {
struct {
uint8_t screenLayout2; // Contains round/notround qualifier.
- uint8_t colorimetry; // Wide-gamut, HDR, etc.
+ uint8_t colorMode; // Wide-gamut, HDR, etc.
uint16_t screenConfigPad2; // Reserved padding.
};
uint32_t screenConfig2;
@@ -1188,6 +1188,8 @@ struct ResTable_config
int compare(const ResTable_config& o) const;
int compareLogical(const ResTable_config& o) const;
+ inline bool operator<(const ResTable_config& o) const { return compare(o) < 0; }
+
// Flags indicating a set of config values. These flag constants must
// match the corresponding ones in android.content.pm.ActivityInfo and
// attrs_manifest.xml.
@@ -1208,7 +1210,7 @@ struct ResTable_config
CONFIG_UI_MODE = ACONFIGURATION_UI_MODE,
CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR,
CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND,
- CONFIG_COLORIMETRY = ACONFIGURATION_COLORIMETRY,
+ CONFIG_COLOR_MODE = ACONFIGURATION_COLOR_MODE,
};
// Compare two configuration, returning CONFIG_* flags set for each value
@@ -1538,6 +1540,8 @@ struct ResTable_lib_entry
uint16_t packageName[128];
};
+class AssetManager2;
+
/**
* Holds the shared library ID table. Shared libraries are assigned package IDs at
* build time, but they may be loaded in a different order, so we need to maintain
@@ -1548,7 +1552,9 @@ struct ResTable_lib_entry
*/
class DynamicRefTable
{
+ friend class AssetManager2;
public:
+ DynamicRefTable() = default;
DynamicRefTable(uint8_t packageId, bool appAsLib);
// Loads an unmapped reference table from the package.
@@ -1563,18 +1569,18 @@ public:
// Performs the actual conversion of build-time resource ID to run-time
// resource ID.
- inline status_t lookupResourceId(uint32_t* resId) const;
- inline status_t lookupResourceValue(Res_value* value) const;
+ status_t lookupResourceId(uint32_t* resId) const;
+ status_t lookupResourceValue(Res_value* value) const;
inline const KeyedVector<String16, uint8_t>& entries() const {
return mEntries;
}
private:
- const uint8_t mAssignedPackageId;
+ uint8_t mAssignedPackageId = 0;
uint8_t mLookupTable[256];
KeyedVector<String16, uint8_t> mEntries;
- bool mAppAsLib;
+ bool mAppAsLib = false;
};
bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 5266d09e84e3..96b42bf45a08 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -94,14 +94,22 @@ class unique_cptr {
inline bool operator==(const unique_cptr& o) const { return ptr_ == o.ptr_; }
+ inline bool operator!=(const unique_cptr& o) const { return ptr_ != o.ptr_; }
+
inline bool operator==(std::nullptr_t) const { return ptr_ == nullptr; }
+ inline bool operator!=(std::nullptr_t) const { return ptr_ != nullptr; }
+
private:
DISALLOW_COPY_AND_ASSIGN(unique_cptr);
pointer ptr_;
};
+inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
+ return resid | (static_cast<uint32_t>(package_id) << 24);
+}
+
inline uint8_t get_package_id(uint32_t resid) {
return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
}
@@ -113,7 +121,7 @@ inline uint8_t get_type_id(uint32_t resid) {
inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
-inline bool is_internal_id(uint32_t resid) {
+inline bool is_internal_resid(uint32_t resid) {
return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
}
@@ -121,6 +129,8 @@ inline bool is_valid_resid(uint32_t resid) {
return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
}
+void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out);
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 3a1fc8fa0d3f..6b4a7199eba4 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -24,11 +24,31 @@ using com::android::basic::R;
namespace android {
TEST(ApkAssetsTest, LoadApk) {
- std::unique_ptr<ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ std::unique_ptr<const ApkAssets> loaded_apk =
+ ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
ASSERT_NE(nullptr, loaded_apk);
+ EXPECT_NE(nullptr, loaded_apk->GetLoadedArsc());
std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
ASSERT_NE(nullptr, asset);
}
+TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
+ std::unique_ptr<const ApkAssets> loaded_apk =
+ ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
+ ASSERT_NE(nullptr, loaded_apk);
+ const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
+ ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
+ EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
+
+ loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
+ ASSERT_NE(nullptr, loaded_apk);
+
+ loaded_arsc = loaded_apk->GetLoadedArsc();
+ ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
+ EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 9ff947807a1e..273290a26050 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -16,6 +16,7 @@
#include "benchmark/benchmark.h"
+#include "android-base/stringprintf.h"
#include "androidfw/ApkAssets.h"
#include "androidfw/AssetManager.h"
#include "androidfw/AssetManager2.h"
@@ -23,10 +24,12 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
+#include "data/libclient/R.h"
#include "data/styles/R.h"
-namespace basic = com::android::basic;
namespace app = com::android::app;
+namespace basic = com::android::basic;
+namespace libclient = com::android::libclient;
namespace android {
@@ -35,7 +38,7 @@ constexpr const static char* kFrameworkPath = "/system/framework/framework-res.a
static void BM_AssetManagerLoadAssets(benchmark::State& state) {
std::string path = GetTestDataPath() + "/basic/basic.apk";
while (state.KeepRunning()) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
AssetManager2 assets;
assets.SetApkAssets({apk.get()});
}
@@ -58,7 +61,7 @@ BENCHMARK(BM_AssetManagerLoadAssetsOld);
static void BM_AssetManagerLoadFrameworkAssets(benchmark::State& state) {
std::string path = kFrameworkPath;
while (state.KeepRunning()) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
AssetManager2 assets;
assets.SetApkAssets({apk.get()});
}
@@ -78,106 +81,113 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) {
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
-static void BM_AssetManagerGetResource(benchmark::State& state) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- if (apk == nullptr) {
- state.SkipWithError("Failed to load assets");
- return;
+static void GetResourceBenchmark(const std::vector<std::string>& paths,
+ const ResTable_config* config, uint32_t resid,
+ benchmark::State& state) {
+ std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
+ std::vector<const ApkAssets*> apk_assets_ptrs;
+ for (const std::string& path : paths) {
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
+ if (apk == nullptr) {
+ state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
+ return;
+ }
+ apk_assets_ptrs.push_back(apk.get());
+ apk_assets.push_back(std::move(apk));
}
- AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets(apk_assets_ptrs);
+ if (config != nullptr) {
+ assetmanager.SetConfiguration(*config);
+ }
Res_value value;
ResTable_config selected_config;
uint32_t flags;
while (state.KeepRunning()) {
- assets.GetResource(basic::R::integer::number1, false /* may_be_bag */,
- 0u /* density_override */, &value, &selected_config, &flags);
+ assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
+ &selected_config, &flags);
}
}
-BENCHMARK(BM_AssetManagerGetResource);
-static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
- AssetManager assets;
- if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
- nullptr /* cookie */, false /* appAsLib */,
- false /* isSystemAssets */)) {
- state.SkipWithError("Failed to load assets");
- return;
+static void GetResourceBenchmarkOld(const std::vector<std::string>& paths,
+ const ResTable_config* config, uint32_t resid,
+ benchmark::State& state) {
+ AssetManager assetmanager;
+ for (const std::string& path : paths) {
+ if (!assetmanager.addAssetPath(String8(path.c_str()), nullptr /* cookie */,
+ false /* appAsLib */, false /* isSystemAssets */)) {
+ state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
+ return;
+ }
}
- const ResTable& table = assets.getResources(true);
+ if (config != nullptr) {
+ assetmanager.setConfiguration(*config);
+ }
+
+ const ResTable& table = assetmanager.getResources(true);
Res_value value;
ResTable_config selected_config;
uint32_t flags;
while (state.KeepRunning()) {
- table.getResource(basic::R::integer::number1, &value, false /* may_be_bag */,
- 0u /* density_override */, &flags, &selected_config);
+ table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
+ &selected_config);
}
}
+
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+ GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+ basic::R::integer::number1, state);
+}
+BENCHMARK(BM_AssetManagerGetResource);
+
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+ GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+ basic::R::integer::number1, state);
+}
BENCHMARK(BM_AssetManagerGetResourceOld);
-constexpr static const uint32_t kStringOkId = 0x0104000au;
+static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
+ GetResourceBenchmark(
+ {GetTestDataPath() + "/lib_two/lib_two.apk", GetTestDataPath() + "/lib_one/lib_one.apk",
+ GetTestDataPath() + "/libclient/libclient.apk"},
+ nullptr /*config*/, libclient::R::string::foo_one, state);
+}
+BENCHMARK(BM_AssetManagerGetLibraryResource);
-static void BM_AssetManagerGetResourceFrameworkLocale(benchmark::State& state) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
- if (apk == nullptr) {
- state.SkipWithError("Failed to load assets");
- return;
- }
+static void BM_AssetManagerGetLibraryResourceOld(benchmark::State& state) {
+ GetResourceBenchmarkOld(
+ {GetTestDataPath() + "/lib_two/lib_two.apk", GetTestDataPath() + "/lib_one/lib_one.apk",
+ GetTestDataPath() + "/libclient/libclient.apk"},
+ nullptr /*config*/, libclient::R::string::foo_one, state);
+}
+BENCHMARK(BM_AssetManagerGetLibraryResourceOld);
- AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
+constexpr static const uint32_t kStringOkId = 0x0104000au;
+static void BM_AssetManagerGetResourceFrameworkLocale(benchmark::State& state) {
ResTable_config config;
memset(&config, 0, sizeof(config));
memcpy(config.language, "fr", 2);
- assets.SetConfiguration(config);
-
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- while (state.KeepRunning()) {
- assets.GetResource(kStringOkId, false /* may_be_bag */, 0u /* density_override */, &value,
- &selected_config, &flags);
- }
+ GetResourceBenchmark({kFrameworkPath}, &config, kStringOkId, state);
}
BENCHMARK(BM_AssetManagerGetResourceFrameworkLocale);
static void BM_AssetManagerGetResourceFrameworkLocaleOld(benchmark::State& state) {
- AssetManager assets;
- if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
- nullptr /* cookie */, false /* appAsLib */,
- false /* isSystemAssets */)) {
- state.SkipWithError("Failed to load assets");
- return;
- }
-
ResTable_config config;
memset(&config, 0, sizeof(config));
memcpy(config.language, "fr", 2);
- assets.setConfiguration(config, nullptr);
-
- const ResTable& table = assets.getResources(true);
-
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- while (state.KeepRunning()) {
- table.getResource(kStringOkId, &value, false /* may_be_bag */, 0u /* density_override */,
- &flags, &selected_config);
- }
+ GetResourceBenchmarkOld({kFrameworkPath}, &config, kStringOkId, state);
}
BENCHMARK(BM_AssetManagerGetResourceFrameworkLocaleOld);
static void BM_AssetManagerGetBag(benchmark::State& state) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
@@ -202,8 +212,7 @@ BENCHMARK(BM_AssetManagerGetBag);
static void BM_AssetManagerGetBagOld(benchmark::State& state) {
AssetManager assets;
if (!assets.addAssetPath(String8((GetTestDataPath() + "/styles/styles.apk").data()),
- nullptr /* cookie */, false /* appAsLib */,
- false /* isSystemAssets */)) {
+ nullptr /*cookie*/, false /*appAsLib*/, false /*isSystemAssets*/)) {
state.SkipWithError("Failed to load assets");
return;
}
@@ -225,4 +234,40 @@ static void BM_AssetManagerGetBagOld(benchmark::State& state) {
}
BENCHMARK(BM_AssetManagerGetBagOld);
+static void BM_AssetManagerGetResourceLocales(benchmark::State& state) {
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ if (apk == nullptr) {
+ state.SkipWithError("Failed to load assets");
+ return;
+ }
+
+ AssetManager2 assets;
+ assets.SetApkAssets({apk.get()});
+
+ while (state.KeepRunning()) {
+ std::set<std::string> locales =
+ assets.GetResourceLocales(false /*exclude_system*/, true /*merge_equivalent_languages*/);
+ benchmark::DoNotOptimize(locales);
+ }
+}
+BENCHMARK(BM_AssetManagerGetResourceLocales);
+
+static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
+ AssetManager assets;
+ if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
+ false /*isSystemAssets*/)) {
+ state.SkipWithError("Failed to load assets");
+ return;
+ }
+
+ const ResTable& table = assets.getResources(true);
+
+ while (state.KeepRunning()) {
+ Vector<String8> locales;
+ table.getLocales(&locales, true /*includeSystemLocales*/, true /*mergeEquivalentLangs*/);
+ benchmark::DoNotOptimize(locales);
+ }
+}
+BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
+
} // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 39c5381feb04..557d8d40dfc2 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -20,11 +20,20 @@
#include "android-base/logging.h"
#include "TestHelpers.h"
+#include "data/appaslib/R.h"
#include "data/basic/R.h"
+#include "data/lib_one/R.h"
+#include "data/lib_two/R.h"
+#include "data/libclient/R.h"
#include "data/styles/R.h"
+#include "data/system/R.h"
-namespace basic = com::android::basic;
namespace app = com::android::app;
+namespace appaslib = com::android::appaslib::app;
+namespace basic = com::android::basic;
+namespace lib_one = com::android::lib_one;
+namespace lib_two = com::android::lib_two;
+namespace libclient = com::android::libclient;
namespace android {
@@ -39,15 +48,35 @@ class AssetManager2Test : public ::testing::Test {
style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
ASSERT_NE(nullptr, style_assets_);
+
+ lib_one_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_one/lib_one.apk");
+ ASSERT_NE(nullptr, lib_one_assets_);
+
+ lib_two_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_two/lib_two.apk");
+ ASSERT_NE(nullptr, lib_two_assets_);
+
+ libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
+ ASSERT_NE(nullptr, libclient_assets_);
+
+ appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
+ ASSERT_NE(nullptr, appaslib_assets_);
+
+ system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
+ ASSERT_NE(nullptr, system_assets_);
}
protected:
- std::unique_ptr<ApkAssets> basic_assets_;
- std::unique_ptr<ApkAssets> basic_de_fr_assets_;
- std::unique_ptr<ApkAssets> style_assets_;
+ std::unique_ptr<const ApkAssets> basic_assets_;
+ std::unique_ptr<const ApkAssets> basic_de_fr_assets_;
+ std::unique_ptr<const ApkAssets> style_assets_;
+ std::unique_ptr<const ApkAssets> lib_one_assets_;
+ std::unique_ptr<const ApkAssets> lib_two_assets_;
+ std::unique_ptr<const ApkAssets> libclient_assets_;
+ std::unique_ptr<const ApkAssets> appaslib_assets_;
+ std::unique_ptr<const ApkAssets> system_assets_;
};
-TEST_F(AssetManager2Test, FindsResourcesFromSingleApkAssets) {
+TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
ResTable_config desired_config;
memset(&desired_config, 0, sizeof(desired_config));
desired_config.language[0] = 'd';
@@ -77,7 +106,7 @@ TEST_F(AssetManager2Test, FindsResourcesFromSingleApkAssets) {
EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
}
-TEST_F(AssetManager2Test, FindsResourcesFromMultipleApkAssets) {
+TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
ResTable_config desired_config;
memset(&desired_config, 0, sizeof(desired_config));
desired_config.language[0] = 'd';
@@ -99,7 +128,7 @@ TEST_F(AssetManager2Test, FindsResourcesFromMultipleApkAssets) {
// Came from our de_fr ApkAssets.
EXPECT_EQ(1, cookie);
- // The configuration is german.
+ // The configuration is German.
EXPECT_EQ('d', selected_config.language[0]);
EXPECT_EQ('e', selected_config.language[1]);
@@ -107,7 +136,72 @@ TEST_F(AssetManager2Test, FindsResourcesFromMultipleApkAssets) {
EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
}
-TEST_F(AssetManager2Test, FindsBagResourcesFromSingleApkAssets) {
+TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
+ AssetManager2 assetmanager;
+
+ // libclient is built with lib_one and then lib_two in order.
+ // Reverse the order to test that proper package ID re-assignment is happening.
+ 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);
+
+ // Reference comes from libclient.
+ EXPECT_EQ(2, cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+
+ // 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);
+ EXPECT_EQ(std::string("Foo from lib_one"),
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(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);
+
+ // Reference comes from libclient.
+ EXPECT_EQ(2, cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+
+ // 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);
+ EXPECT_EQ(std::string("Foo from lib_two"),
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(cookie), value.data));
+}
+
+TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
+ AssetManager2 assetmanager;
+ 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(
+ util::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(util::fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
+}
+
+TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
@@ -128,6 +222,27 @@ TEST_F(AssetManager2Test, FindsBagResourcesFromSingleApkAssets) {
EXPECT_EQ(0, bag->entries[2].cookie);
}
+TEST_F(AssetManager2Test, FindsBagResourceFromMultipleApkAssets) {}
+
+TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) {
+ AssetManager2 assetmanager;
+
+ // libclient is built with lib_one and then lib_two in order.
+ // Reverse the order to test that proper package ID re-assignment is happening.
+ 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);
+
+ // First two attributes come from lib_one.
+ EXPECT_EQ(1, bag->entries[0].cookie);
+ EXPECT_EQ(0x03, util::get_package_id(bag->entries[0].key));
+ EXPECT_EQ(1, bag->entries[1].cookie);
+ EXPECT_EQ(0x03, util::get_package_id(bag->entries[1].key));
+}
+
TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({style_assets_.get()});
@@ -181,7 +296,130 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
EXPECT_EQ(0, bag_two->entries[4].cookie);
}
-TEST_F(AssetManager2Test, FindsBagResourcesFromMultipleApkAssets) {}
+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);
+
+ ResTable_ref last_ref;
+ 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.ident);
+}
+
+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);
+
+ ResTable_ref last_ref;
+ 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.ident);
+}
+
+static bool IsConfigurationPresent(const std::set<ResTable_config>& configurations,
+ const ResTable_config& configuration) {
+ return configurations.count(configuration) > 0;
+}
+
+TEST_F(AssetManager2Test, GetResourceConfigurations) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
+
+ std::set<ResTable_config> configurations = assetmanager.GetResourceConfigurations();
+
+ // 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());
+
+ 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));
+
+ expected_config.language[0] = 'd';
+ expected_config.language[1] = 'e';
+ EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+
+ expected_config.language[0] = 'f';
+ expected_config.language[1] = 'r';
+ EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+
+ // Take out the system assets.
+ configurations = assetmanager.GetResourceConfigurations(true /* exclude_system */);
+
+ // We expect de and fr from basic_de_fr assets.
+ EXPECT_EQ(2u, configurations.size());
+
+ expected_config.language[0] = 's';
+ expected_config.language[1] = 'v';
+ EXPECT_FALSE(IsConfigurationPresent(configurations, expected_config));
+
+ expected_config.language[0] = 'd';
+ expected_config.language[1] = 'e';
+ EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+
+ expected_config.language[0] = 'f';
+ expected_config.language[1] = 'r';
+ EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+}
+
+TEST_F(AssetManager2Test, GetResourceLocales) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
+
+ std::set<std::string> locales = assetmanager.GetResourceLocales();
+
+ // We expect the locale sv from the system assets, and de and fr from basic_de_fr assets.
+ EXPECT_EQ(3u, locales.size());
+ EXPECT_GT(locales.count("sv"), 0u);
+ EXPECT_GT(locales.count("de"), 0u);
+ EXPECT_GT(locales.count("fr"), 0u);
+
+ locales = assetmanager.GetResourceLocales(true /*exclude_system*/);
+ // We expect the de and fr locales from basic_de_fr assets.
+ EXPECT_EQ(2u, locales.size());
+ EXPECT_GT(locales.count("de"), 0u);
+ EXPECT_GT(locales.count("fr"), 0u);
+}
+
+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"));
+}
TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp
index 3e5aca7ab655..b54915f03c29 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -187,9 +187,9 @@ TEST(ConfigTest, ScreenIsWideGamut) {
memset(&defaultConfig, 0, sizeof(defaultConfig));
ResTable_config wideGamutConfig = defaultConfig;
- wideGamutConfig.colorimetry = ResTable_config::WIDE_COLOR_GAMUT_YES;
+ wideGamutConfig.colorMode = ResTable_config::WIDE_COLOR_GAMUT_YES;
- EXPECT_EQ(defaultConfig.diff(wideGamutConfig), ResTable_config::CONFIG_COLORIMETRY);
+ EXPECT_EQ(defaultConfig.diff(wideGamutConfig), ResTable_config::CONFIG_COLOR_MODE);
}
TEST(ConfigTest, ScreenIsHdr) {
@@ -197,9 +197,9 @@ TEST(ConfigTest, ScreenIsHdr) {
memset(&defaultConfig, 0, sizeof(defaultConfig));
ResTable_config hdrConfig = defaultConfig;
- hdrConfig.colorimetry = ResTable_config::HDR_YES;
+ hdrConfig.colorMode = ResTable_config::HDR_YES;
- EXPECT_EQ(defaultConfig.diff(hdrConfig), ResTable_config::CONFIG_COLORIMETRY);
+ EXPECT_EQ(defaultConfig.diff(hdrConfig), ResTable_config::CONFIG_COLOR_MODE);
}
} // namespace android.
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 47b3894f0398..756869f6377d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,33 +16,36 @@
#include "androidfw/LoadedArsc.h"
-#include "android-base/file.h"
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-
#include "TestHelpers.h"
#include "data/basic/R.h"
+#include "data/libclient/R.h"
#include "data/styles/R.h"
namespace app = com::android::app;
namespace basic = com::android::basic;
+namespace libclient = com::android::libclient;
namespace android {
TEST(LoadedArscTest, LoadSinglePackageArsc) {
- base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
&contents));
- std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(contents.data(), contents.size());
ASSERT_NE(nullptr, loaded_arsc);
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName());
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 24;
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config selected_config;
uint32_t flags;
@@ -52,12 +55,12 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
}
TEST(LoadedArscTest, FindDefaultEntry) {
- base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
std::string contents;
ASSERT_TRUE(
ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
- std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(contents.data(), contents.size());
ASSERT_NE(nullptr, loaded_arsc);
ResTable_config desired_config;
@@ -65,7 +68,7 @@ TEST(LoadedArscTest, FindDefaultEntry) {
desired_config.language[0] = 'd';
desired_config.language[1] = 'e';
- LoadedArsc::Entry entry;
+ LoadedArscEntry entry;
ResTable_config selected_config;
uint32_t flags;
@@ -74,6 +77,103 @@ TEST(LoadedArscTest, FindDefaultEntry) {
ASSERT_NE(nullptr, entry.entry);
}
+TEST(LoadedArscTest, LoadSharedLibrary) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
+ &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(contents.data(), contents.size());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const auto& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+
+ EXPECT_TRUE(packages[0]->IsDynamic());
+ EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName());
+ EXPECT_EQ(0, packages[0]->GetPackageId());
+
+ const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
+
+ // The library has no dependencies.
+ ASSERT_TRUE(dynamic_pkg_map.empty());
+}
+
+TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(contents.data(), contents.size());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const auto& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+
+ EXPECT_FALSE(packages[0]->IsDynamic());
+ EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName());
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+
+ const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
+
+ // The library has two dependencies.
+ ASSERT_EQ(2u, dynamic_pkg_map.size());
+
+ EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name);
+ EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id);
+
+ EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name);
+ EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id);
+}
+
+TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(
+ contents.data(), contents.size(), false /*system*/, true /*load_as_shared_library*/);
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const auto& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+
+ EXPECT_TRUE(packages[0]->IsDynamic());
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+}
+
+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(contents.data(), contents.size());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+
+ LoadedArscEntry entry;
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry,
+ &selected_config, &flags));
+
+ size_t len;
+ const char16_t* type_name16 = entry.type_string_ref.string16(&len);
+ ASSERT_NE(nullptr, type_name16);
+ ASSERT_NE(0u, len);
+
+ size_t utf8_len = utf16_to_utf8_length(type_name16, len);
+ std::string type_name;
+ type_name.resize(utf8_len);
+ utf16_to_utf8(type_name16, len, &*type_name.begin(), utf8_len + 1);
+
+ EXPECT_EQ(std::string("string"), type_name);
+}
+
// structs with size fields (like Res_value, ResTable_entry) should be
// backwards and forwards compatible (aka checking the size field against
// sizeof(Res_value) might not be backwards compatible.
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index b151f3f96496..ad1cd2b289d6 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -25,10 +25,10 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
-#include "data/lib/R.h"
+#include "data/lib_one/R.h"
namespace basic = com::android::basic;
-namespace lib = com::android::lib;
+namespace lib = com::android::lib_one;
namespace android {
@@ -119,7 +119,7 @@ TEST(ResTableTest, ParentThemeIsAppliedCorrectly) {
TEST(ResTableTest, LibraryThemeIsAppliedCorrectly) {
std::string contents;
- ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib/lib.apk",
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk",
"resources.arsc", &contents));
ResTable table;
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
index c471be6cd09d..594c39eb682f 100644
--- a/libs/androidfw/tests/Theme_bench.cpp
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -28,7 +28,7 @@ constexpr const static uint32_t kStyleId = 0x01030237u; // android:style/Theme.
constexpr const static uint32_t kAttrId = 0x01010030u; // android:attr/colorForeground
static void BM_ThemeApplyStyleFramework(benchmark::State& state) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
if (apk == nullptr) {
state.SkipWithError("Failed to load assets");
return;
@@ -62,7 +62,7 @@ static void BM_ThemeApplyStyleFrameworkOld(benchmark::State& state) {
BENCHMARK(BM_ThemeApplyStyleFrameworkOld);
static void BM_ThemeGetAttribute(benchmark::State& state) {
- std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
AssetManager2 assets;
assets.SetApkAssets({apk.get()});
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index c0011b6d6e89..daed28b01a4f 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -19,9 +19,13 @@
#include "android-base/logging.h"
#include "TestHelpers.h"
+#include "data/lib_one/R.h"
+#include "data/libclient/R.h"
#include "data/styles/R.h"
namespace app = com::android::app;
+namespace lib_one = com::android::lib_one;
+namespace libclient = com::android::libclient;
namespace android {
@@ -30,10 +34,22 @@ class ThemeTest : public ::testing::Test {
void SetUp() override {
style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
ASSERT_NE(nullptr, style_assets_);
+
+ libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
+ ASSERT_NE(nullptr, libclient_assets_);
+
+ lib_one_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_one/lib_one.apk");
+ ASSERT_NE(nullptr, lib_one_assets_);
+
+ lib_two_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_two/lib_two.apk");
+ ASSERT_NE(nullptr, lib_two_assets_);
}
protected:
- std::unique_ptr<ApkAssets> style_assets_;
+ std::unique_ptr<const ApkAssets> style_assets_;
+ std::unique_ptr<const ApkAssets> libclient_assets_;
+ std::unique_ptr<const ApkAssets> lib_one_assets_;
+ std::unique_ptr<const ApkAssets> lib_two_assets_;
};
TEST_F(ThemeTest, EmptyTheme) {
@@ -174,6 +190,36 @@ TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
}
+TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets(
+ {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;
+
+ // 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);
+
+ // 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);
+
+ // lib_one is assigned package ID 0x03.
+ EXPECT_EQ(3u, util::get_package_id(value.data));
+ EXPECT_EQ(util::get_type_id(lib_one::R::string::foo), util::get_type_id(value.data));
+ EXPECT_EQ(util::get_entry_id(lib_one::R::string::foo), util::get_entry_id(value.data));
+}
+
TEST_F(ThemeTest, CopyThemeSameAssetManager) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({style_assets_.get()});
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index 9352b5c6629e..8e9741efd2a3 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -53,6 +53,8 @@ struct R {
enum : uint32_t {
number1 = 0x7f040000,
number2 = 0x7f040001,
+ ref1 = 0x7f040002,
+ ref2 = 0x7f040003,
// From feature
number3 = 0x7f090000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 2c9771b18934..7ee6734e0d6a 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_de_fr.apk b/libs/androidfw/tests/data/basic/basic_de_fr.apk
index 04814440e0f8..e45258c6a005 100644
--- a/libs/androidfw/tests/data/basic/basic_de_fr.apk
+++ b/libs/androidfw/tests/data/basic/basic_de_fr.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
index a8d06e7f3c19..4ae1a7c87a70 100644
--- a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
index d1dfb143f91b..a240d4c06c1d 100644
--- a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
index dca6f2fbc0ca..fd3d9b233084 100644
--- a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index 11f6b8adbdba..638c9832ab4c 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -37,6 +37,12 @@
<public type="integer" name="number2" id="0x7f040001" />
<integer name="number2">@array/integerArray1</integer>
+ <public type="integer" name="ref1" id="0x7f040002" />
+ <integer name="ref1">@integer/ref2</integer>
+
+ <public type="integer" name="ref2" id="0x7f040003" />
+ <integer name="ref2">12000</integer>
+
<public type="style" name="Theme1" id="0x7f050000" />
<style name="Theme1">
<item name="com.android.basic:attr1">100</item>
diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk
index 04940fb9bce2..767fed697034 100644
--- a/libs/androidfw/tests/data/feature/feature.apk
+++ b/libs/androidfw/tests/data/feature/feature.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib/lib.apk b/libs/androidfw/tests/data/lib/lib.apk
deleted file mode 100644
index 44c27c79ae7c..000000000000
--- a/libs/androidfw/tests/data/lib/lib.apk
+++ /dev/null
Binary files differ
diff --git a/libs/androidfw/tests/data/lib/AndroidManifest.xml b/libs/androidfw/tests/data/lib_one/AndroidManifest.xml
index 02f5d3efabea..860adf758f92 100644
--- a/libs/androidfw/tests/data/lib/AndroidManifest.xml
+++ b/libs/androidfw/tests/data/lib_one/AndroidManifest.xml
@@ -15,6 +15,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.lib">
+ package="com.android.lib_one">
<application />
</manifest>
diff --git a/libs/androidfw/tests/data/lib/R.h b/libs/androidfw/tests/data/lib_one/R.h
index bb22d22f90e1..fcaeb8dceffb 100644
--- a/libs/androidfw/tests/data/lib/R.h
+++ b/libs/androidfw/tests/data/lib_one/R.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef TEST_DATA_LIB_R_H_
-#define TEST_DATA_LIB_R_H_
+#ifndef TEST_DATA_LIB_ONE_R_H_
+#define TEST_DATA_LIB_ONE_R_H_
#include <cstdint>
namespace com {
namespace android {
-namespace lib {
+namespace lib_one {
struct R {
struct attr {
@@ -36,10 +36,16 @@ struct R {
Theme = 0x02020000, // default
};
};
+
+ struct string {
+ enum : uint32_t {
+ foo = 0x02030000, // default
+ };
+ };
};
-} // namespace lib
+} // namespace lib_one
} // namespace android
} // namespace com
-#endif // TEST_DATA_R_H_
+#endif // TEST_DATA_LIB_ONE_R_H_
diff --git a/libs/androidfw/tests/data/lib/build b/libs/androidfw/tests/data/lib_one/build
index 5c3d02c850bf..c6adf0b1dda6 100755
--- a/libs/androidfw/tests/data/lib/build
+++ b/libs/androidfw/tests/data/lib_one/build
@@ -17,4 +17,4 @@
set -e
-aapt package -M AndroidManifest.xml -S res -F lib.apk -f --shared-lib
+aapt package -M AndroidManifest.xml -S res -F lib_one.apk -f --shared-lib
diff --git a/libs/androidfw/tests/data/lib_one/lib_one.apk b/libs/androidfw/tests/data/lib_one/lib_one.apk
new file mode 100644
index 000000000000..f287554d674d
--- /dev/null
+++ b/libs/androidfw/tests/data/lib_one/lib_one.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib_one/res/values/values.xml b/libs/androidfw/tests/data/lib_one/res/values/values.xml
new file mode 100644
index 000000000000..752b7e912ab6
--- /dev/null
+++ b/libs/androidfw/tests/data/lib_one/res/values/values.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <public type="attr" name="attr1" id="0x00010000" />
+ <attr name="attr1" format="integer" />
+
+ <public type="attr" name="attr2" id="0x00010001" />
+ <attr name="attr2" format="integer" />
+
+ <public type="style" name="Theme" id="0x00020000" />
+ <style name="Theme">
+ <item name="com.android.lib_one:attr1">700</item>
+ <item name="com.android.lib_one:attr2">?com.android.lib_one:attr1</item>
+ </style>
+
+ <public type="string" name="foo" id="0x00030000" />
+ <string name="foo">Foo from lib_one</string>
+</resources>
diff --git a/core/res/res/values-ldrtl/dimens.xml b/libs/androidfw/tests/data/lib_two/AndroidManifest.xml
index 807c0424235d..4b131e55a8a4 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/libs/androidfw/tests/data/lib_two/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
limitations under the License.
-->
-<resources>
- <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
- <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<manifest package="com.android.lib_two">
+ <application />
+</manifest>
diff --git a/libs/androidfw/tests/data/lib_two/R.h b/libs/androidfw/tests/data/lib_two/R.h
new file mode 100644
index 000000000000..c04a9d3b4de0
--- /dev/null
+++ b/libs/androidfw/tests/data/lib_two/R.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_DATA_LIB_TWO_R_H_
+#define TEST_DATA_LIB_TWO_R_H_
+
+#include <cstdint>
+
+namespace com {
+namespace android {
+namespace lib_two {
+
+struct R {
+ struct string {
+ enum : uint32_t {
+ LibraryString = 0x02020000, // default
+ foo = 0x02020001, // default
+ };
+ };
+};
+
+} // namespace lib_two
+} // namespace android
+} // namespace com
+
+#endif // TEST_DATA_LIB_TWO_R_H_
diff --git a/libs/androidfw/tests/data/lib_two/build b/libs/androidfw/tests/data/lib_two/build
new file mode 100755
index 000000000000..fd75e1dc7428
--- /dev/null
+++ b/libs/androidfw/tests/data/lib_two/build
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+aapt package -M AndroidManifest.xml -S res -F lib_two.apk -f --shared-lib
diff --git a/libs/androidfw/tests/data/lib_two/lib_two.apk b/libs/androidfw/tests/data/lib_two/lib_two.apk
new file mode 100644
index 000000000000..ad44f9c21e31
--- /dev/null
+++ b/libs/androidfw/tests/data/lib_two/lib_two.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib/res/values/values.xml b/libs/androidfw/tests/data/lib_two/res/values/values.xml
index 51e3a407c538..f4eea2610cab 100644
--- a/libs/androidfw/tests/data/lib/res/values/values.xml
+++ b/libs/androidfw/tests/data/lib_two/res/values/values.xml
@@ -15,11 +15,9 @@
-->
<resources>
- <attr name="attr1" format="integer" />
- <attr name="attr2" format="integer" />
+ <public type="string" name="LibraryString" id="0x00020000" />
+ <string name="LibraryString">Hi from library two</string>
- <style name="Theme">
- <item name="com.android.lib:attr1">700</item>
- <item name="com.android.lib:attr2">?com.android.lib:attr1</item>
- </style>
+ <public type="string" name="foo" id="0x00020001" />
+ <string name="foo">Foo from lib_two</string>
</resources>
diff --git a/libs/androidfw/tests/data/libclient/AndroidManifest.xml b/libs/androidfw/tests/data/libclient/AndroidManifest.xml
new file mode 100644
index 000000000000..8436383dbd81
--- /dev/null
+++ b/libs/androidfw/tests/data/libclient/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest package="com.android.libclient">
+ <application />
+</manifest>
diff --git a/libs/androidfw/tests/data/libclient/R.h b/libs/androidfw/tests/data/libclient/R.h
new file mode 100644
index 000000000000..43d1f9bb68e7
--- /dev/null
+++ b/libs/androidfw/tests/data/libclient/R.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_DATA_LIB_R_H_
+#define TEST_DATA_LIB_R_H_
+
+#include <cstdint>
+
+namespace com {
+namespace android {
+namespace libclient {
+
+struct R {
+ struct attr {
+ enum : uint32_t {
+ foo = 0x7f010000, // default
+ bar = 0x7f010001, // default
+ };
+ };
+
+ struct style {
+ enum : uint32_t {
+ Theme = 0x7f020000, // default
+ };
+ };
+
+ struct string {
+ enum : uint32_t {
+ foo_one = 0x7f030000, // default
+ foo_two = 0x7f030001, // default
+ };
+ };
+};
+
+} // namespace libclient
+} // namespace android
+} // namespace com
+
+#endif // TEST_DATA_R_H_
diff --git a/libs/androidfw/tests/data/libclient/build b/libs/androidfw/tests/data/libclient/build
new file mode 100755
index 000000000000..08310e3c6eb8
--- /dev/null
+++ b/libs/androidfw/tests/data/libclient/build
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar
+PATH_TO_LIB_ONE=../lib_one/lib_one.apk
+PATH_TO_LIB_TWO=../lib_two/lib_two.apk
+
+aapt package \
+ -M AndroidManifest.xml \
+ -S res \
+ -I $PATH_TO_FRAMEWORK_RES \
+ -I $PATH_TO_LIB_ONE \
+ -I $PATH_TO_LIB_TWO \
+ -F libclient.apk -f
diff --git a/libs/androidfw/tests/data/libclient/libclient.apk b/libs/androidfw/tests/data/libclient/libclient.apk
new file mode 100644
index 000000000000..17990248e862
--- /dev/null
+++ b/libs/androidfw/tests/data/libclient/libclient.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/libclient/res/values/values.xml b/libs/androidfw/tests/data/libclient/res/values/values.xml
new file mode 100644
index 000000000000..fead7c323767
--- /dev/null
+++ b/libs/androidfw/tests/data/libclient/res/values/values.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<resources>
+ <public type="attr" name="foo" id="0x7f010000" />
+ <attr name="foo" />
+
+ <public type="attr" name="bar" id="0x7f010001" />
+ <attr name="bar" />
+
+ <public type="style" name="Theme" id="0x7f020000" />
+ <style name="Theme" parent="com.android.lib_one:style/Theme">
+ <item name="foo">?com.android.lib_one:attr/attr2</item>
+ <item name="bar">@com.android.lib_one:string/foo</item>
+ </style>
+
+ <public type="string" name="foo_one" id="0x7f030000" />
+ <string name="foo_one">@com.android.lib_one:string/foo</string>
+
+ <public type="string" name="foo_two" id="0x7f030001" />
+ <string name="foo_two">@com.android.lib_two:string/foo</string>
+</resources>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8f7787bd5d15..692199d7af1f 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -7,7 +7,7 @@ BUGREPORT_FONT_CACHE_USAGE := false
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
# Has moderate overhead
-HWUI_ENABLE_OPENGL_VALIDATION := false
+HWUI_ENABLE_OPENGL_VALIDATION := true
hwui_src_files := \
hwui/Bitmap.cpp \
@@ -192,7 +192,7 @@ hwui_c_includes += \
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
hwui_c_includes += \
- $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
+ $(call intermediates-dir-for,STATIC_LIBRARIES,TARGET,) \
frameworks/rs/cpp \
frameworks/rs
endif
@@ -316,6 +316,7 @@ LOCAL_SRC_FILES += \
tests/unit/StringUtilsTests.cpp \
tests/unit/TestUtilsTests.cpp \
tests/unit/TextDropShadowCacheTests.cpp \
+ tests/unit/TextureCacheTests.cpp \
tests/unit/VectorDrawableTests.cpp \
include $(LOCAL_PATH)/hwui_static_deps.mk
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 6079d5def1f8..03a397c1084d 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -18,6 +18,7 @@
#include "BakedOpRenderer.h"
#include "Caches.h"
+#include "DeferredLayerUpdater.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "Patch.h"
@@ -762,15 +763,19 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
}
void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
- const bool tryToSnap = !op.layer->getForceFilter();
- float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha;
+ GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
+ if (!layer) {
+ return;
+ }
+ const bool tryToSnap = layer->getForceFilter();
+ float alpha = (layer->getAlpha() / 255.0f) * state.alpha;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
- .setFillTextureLayer(*(op.layer), alpha)
+ .setFillTextureLayer(*(layer), alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight()))
+ .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(layer->getWidth(), layer->getHeight()))
.build();
renderer.renderGlop(state, glop);
}
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 0ae50e96fc39..415e850d0fe8 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -17,6 +17,7 @@
#include "GlLayer.h"
#include "VkLayer.h"
+#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderTask.h"
#include "utils/PaintUtils.h"
@@ -24,25 +25,32 @@
namespace android {
namespace uirenderer {
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer)
- : mSurfaceTexture(nullptr)
+DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
+ Layer::Api layerApi)
+ : mRenderState(renderState)
+ , mBlend(false)
+ , mSurfaceTexture(nullptr)
, mTransform(nullptr)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
- , mLayer(layer) {
- mWidth = mLayer->getWidth();
- mHeight = mLayer->getHeight();
- mBlend = mLayer->isBlend();
- mColorFilter = SkSafeRef(mLayer->getColorFilter());
- mAlpha = mLayer->getAlpha();
- mMode = mLayer->getMode();
+ , mLayer(nullptr)
+ , mLayerApi(layerApi)
+ , mCreateLayerFn(createLayerFn) {
+ renderState.registerDeferredLayerUpdater(this);
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
SkSafeUnref(mColorFilter);
setTransform(nullptr);
- mLayer->postDecStrong();
- mLayer = nullptr;
+ mRenderState.unregisterDeferredLayerUpdater(this);
+ destroyLayer();
+}
+
+void DeferredLayerUpdater::destroyLayer() {
+ if (mLayer) {
+ mLayer->postDecStrong();
+ mLayer = nullptr;
+ }
}
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
@@ -53,6 +61,10 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
}
void DeferredLayerUpdater::apply() {
+ if (!mLayer) {
+ mLayer = mCreateLayerFn(mRenderState, mWidth, mHeight, mColorFilter, mAlpha, mMode, mBlend);
+ }
+
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
@@ -157,13 +169,15 @@ void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
void DeferredLayerUpdater::detachSurfaceTexture() {
if (mSurfaceTexture.get()) {
- if (mLayer->getApi() == Layer::Api::OpenGL) {
+ if (mLayerApi == Layer::Api::OpenGL) {
status_t err = mSurfaceTexture->detachFromContext();
if (err != 0) {
// TODO: Elevate to fatal exception
ALOGE("Failed to detach SurfaceTexture from context %d", err);
}
- static_cast<GlLayer*>(mLayer)->clearTexture();
+ if (mLayer) {
+ static_cast<GlLayer*>(mLayer)->clearTexture();
+ }
}
mSurfaceTexture = nullptr;
}
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 3814be2cbec4..064b724c5e5f 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -32,13 +32,20 @@
namespace android {
namespace uirenderer {
+class RenderState;
+
// Container to hold the properties a layer should be set to at the start
// of a render pass
class DeferredLayerUpdater : public VirtualLightRefBase {
public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
- ANDROID_API explicit DeferredLayerUpdater(Layer* layer);
+ typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
+ uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ SkBlendMode mode, bool blend)> CreateLayerFn;
+ ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState,
+ CreateLayerFn createLayerFn, Layer::Api layerApi);
+
ANDROID_API ~DeferredLayerUpdater();
ANDROID_API bool setSize(int width, int height) {
@@ -97,20 +104,30 @@ public:
void updateLayer(bool forceFilter, GLenum renderTarget, const float* textureTransform);
+ void destroyLayer();
+
+ Layer::Api getBackingLayerApi() {
+ return mLayerApi;
+ }
+
private:
+ RenderState& mRenderState;
+
// Generic properties
- int mWidth;
- int mHeight;
- bool mBlend;
- SkColorFilter* mColorFilter;
- int mAlpha;
- SkBlendMode mMode;
+ int mWidth = 0;
+ int mHeight = 0;
+ bool mBlend = false;
+ SkColorFilter* mColorFilter = nullptr;
+ int mAlpha = 255;
+ SkBlendMode mMode = SkBlendMode::kSrcOver;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;
bool mNeedsGLContextAttach;
bool mUpdateTexImage;
Layer* mLayer;
+ Layer::Api mLayerApi;
+ CreateLayerFn mCreateLayerFn;
void doUpdateTexImage();
void doUpdateVkTexImage();
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 5e4a7f7a8d2f..385335613952 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -104,15 +104,15 @@ void DisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
}
}
-bool DisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
- std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
+bool DisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
for (auto&& op : children) {
RenderNode* childNode = op->renderNode;
info.damageAccumulator->pushTransform(&op->localMatrix);
bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
- childFn(childNode, info, childFunctorsNeedLayer);
+ childFn(childNode, observer, info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index cab092ffc34c..ef0fd31fdfdf 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -125,8 +125,8 @@ public:
virtual void syncContents();
virtual void updateChildren(std::function<void(RenderNode*)> updateFn);
- virtual bool prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
- std::function<void(RenderNode*, TreeInfo&, bool)> childFn);
+ virtual bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
protected:
// allocator into which all ops and LsaVector arrays allocated
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 1d8b021274fe..35ff635930ab 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -16,6 +16,7 @@
#include "FrameBuilder.h"
+#include "DeferredLayerUpdater.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
@@ -784,14 +785,15 @@ void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
}
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
- if (CC_UNLIKELY(!op.layer->isRenderable())) return;
+ GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
+ if (CC_UNLIKELY(!layer || !layer->isRenderable())) return;
const TextureLayerOp* textureLayerOp = &op;
// Now safe to access transform (which was potentially unready at record time)
- if (!op.layer->getTransform().isIdentity()) {
+ if (!layer->getTransform().isIdentity()) {
// non-identity transform present, so 'inject it' into op by copying + replacing matrix
Matrix4 combinedMatrix(op.localMatrix);
- combinedMatrix.multiply(op.layer->getTransform());
+ combinedMatrix.multiply(layer->getTransform());
textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix);
}
BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index c0ab895260ab..8174bcc35d97 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,12 +32,14 @@
namespace android {
namespace uirenderer {
-GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
- : Layer(renderState, Api::OpenGL)
+GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
texture.mWidth = layerWidth;
texture.mHeight = layerHeight;
+ texture.blend = blend;
}
GlLayer::~GlLayer() {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 54bf5adc3ace..23dfd9dfc0c1 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -31,7 +31,8 @@ class Caches;
*/
class GlLayer : public Layer {
public:
- GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight);
+ GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
uint32_t getWidth() const override {
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 8a6e038d8e0d..5cf52c69f0fd 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -605,6 +605,7 @@ void GlopBuilder::build() {
} else {
mDescription.hasExternalTexture = true;
}
+ mDescription.hasLinearTexture = mOutGlop->fill.texture.texture->isLinear();
}
mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 1dad58fd64b9..71bee93fc4c7 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -205,6 +205,10 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
*d++ = a * (start.g * oppAmount + end.g * amount);
*d++ = a * (start.b * oppAmount + end.b * amount);
#else
+ // What we're doing to the alpha channel here is technically incorrect
+ // but reproduces Android's old behavior when the alpha was pre-multiplied
+ // with gamma-encoded colors
+ a = EOCF_sRGB(a);
*d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
*d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
*d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 331bb81208b1..b58dfce787ef 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -23,10 +23,14 @@
namespace android {
namespace uirenderer {
-Layer::Layer(RenderState& renderState, Api api)
+Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+ SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
- , mApi(api) {
+ , mApi(api)
+ , colorFilter(nullptr)
+ , alpha(alpha)
+ , mode(mode) {
// TODO: This is a violation of Android's typical ref counting, but it
// preserves the old inc/dec ref locations. This should be changed...
incStrong(nullptr);
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 3b639ee49334..e5520ea0e811 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -105,7 +105,8 @@ public:
void postDecStrong();
protected:
- Layer(RenderState& renderState, Api api);
+ Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+ SkBlendMode mode);
RenderState& mRenderState;
@@ -115,7 +116,7 @@ private:
/**
* Color filter used to draw this layer. Optional.
*/
- SkColorFilter* colorFilter = nullptr;
+ SkColorFilter* colorFilter;
/**
* Indicates raster data backing the layer is scaled, requiring filtration.
@@ -125,12 +126,12 @@ private:
/**
* Opacity of the layer.
*/
- int alpha = 255;
+ int alpha;
/**
* Blending mode of the layer.
*/
- SkBlendMode mode = SkBlendMode::kSrcOver;
+ SkBlendMode mode;
/**
* Optional texture coordinates transform.
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e70982f5444a..5c8f8e93fa3d 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -87,6 +87,7 @@ namespace uirenderer {
#define PROGRAM_HAS_ROUND_RECT_CLIP 43
#define PROGRAM_HAS_GAMMA_CORRECTION 44
+#define PROGRAM_HAS_LINEAR_TEXTURE 45
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -162,7 +163,10 @@ struct ProgramDescription {
bool hasDebugHighlight;
bool hasRoundRectClip;
+ // Extra gamma correction used for text
bool hasGammaCorrection;
+ // Set when sampling an image in linear space
+ bool hasLinearTexture;
/**
* Resets this description. All fields are reset back to the default
@@ -205,6 +209,7 @@ struct ProgramDescription {
hasRoundRectClip = false;
hasGammaCorrection = false;
+ hasLinearTexture = false;
}
/**
@@ -275,6 +280,7 @@ struct ProgramDescription {
if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
+ if (hasLinearTexture) key |= programid(0x1) << PROGRAM_HAS_LINEAR_TEXTURE;
return key;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 71076791cf7f..00de9924ace1 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -161,27 +161,54 @@ const char* gFS_Uniforms_HasRoundRectClip =
"uniform vec4 roundRectInnerRectLTRB;\n"
"uniform float roundRectRadius;\n";
+const char* gFS_OETF[2] = {
+ "\nvec4 OETF(const vec4 linear) {\n"
+ " return linear;\n"
+ "}\n",
+ // We expect linear data to be scRGB so we mirror the gamma function
+ "\nvec4 OETF(const vec4 linear) {"
+ " return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);\n"
+ "}\n",
+};
+
+const char* gFS_Transfer_Functions = R"__SHADER__(
+ float OETF_sRGB(const float linear) {
+ // IEC 61966-2-1:1999
+ return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+ }
+
+ vec3 OETF_sRGB(const vec3 linear) {
+ return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ float EOTF_sRGB(float srgb) {
+ // IEC 61966-2-1:1999
+ return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+ }
+)__SHADER__";
+
// Dithering must be done in the quantization space
// When we are writing to an sRGB framebuffer, we must do the following:
-// EOCF(OECF(color) + dither)
-// We approximate the transfer functions with gamma 2.0 to avoid branches and pow()
+// EOTF(OETF(color) + dither)
// The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0]
// TODO: Handle linear fp16 render targets
-const char* gFS_Gradient_Functions =
- "\nfloat triangleNoise(const highp vec2 n) {\n"
- " highp vec2 p = fract(n * vec2(5.3987, 5.4421));\n"
- " p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));\n"
- " highp float xy = p.x * p.y;\n"
- " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n"
- "}\n";
+const char* gFS_Gradient_Functions = R"__SHADER__(
+ float triangleNoise(const highp vec2 n) {
+ highp vec2 p = fract(n * vec2(5.3987, 5.4421));
+ p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
+ highp float xy = p.x * p.y;
+ return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
+ }
+)__SHADER__";
const char* gFS_Gradient_Preamble[2] = {
// Linear framebuffer
"\nvec4 dither(const vec4 color) {\n"
" return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n"
"}\n"
"\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
- " vec4 c = pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));\n"
- " return vec4(c.rgb * c.a, c.a);\n"
+ " vec4 c = mix(a, b, v);\n"
+ " c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility
+ " return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n"
"}\n",
// sRGB framebuffer
"\nvec4 dither(const vec4 color) {\n"
@@ -200,13 +227,15 @@ const char* gFS_Gradient_Preamble[2] = {
// The gamma coefficient is chosen to thicken or thin the text accordingly
// The dot product used to compute the luminance could be approximated with
// a simple max(color.r, color.g, color.b)
-const char* gFS_Gamma_Preamble =
- "\n#define GAMMA (%.2f)\n"
- "#define GAMMA_INV (%.2f)\n"
- "\nfloat gamma(float a, const vec3 color) {\n"
- " float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));\n"
- " return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);\n"
- "}\n";
+const char* gFS_Gamma_Preamble = R"__SHADER__(
+ #define GAMMA (%.2f)
+ #define GAMMA_INV (%.2f)
+
+ float gamma(float a, const vec3 color) {
+ float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
+ return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);
+ }
+)__SHADER__";
const char* gFS_Main =
"\nvoid main(void) {\n"
@@ -215,52 +244,6 @@ const char* gFS_Main =
const char* gFS_Main_AddDither =
" fragColor = dither(fragColor);\n";
-// Fast cases
-const char* gFS_Fast_SingleColor =
- "\nvoid main(void) {\n"
- " gl_FragColor = color;\n"
- "}\n\n";
-const char* gFS_Fast_SingleTexture =
- "\nvoid main(void) {\n"
- " gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
- "}\n\n";
-const char* gFS_Fast_SingleModulateTexture =
- "\nvoid main(void) {\n"
- " gl_FragColor = color.a * texture2D(baseSampler, outTexCoords);\n"
- "}\n\n";
-const char* gFS_Fast_SingleA8Texture =
- "\nvoid main(void) {\n"
- " gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
- "}\n\n";
-const char* gFS_Fast_SingleA8Texture_ApplyGamma =
- "\nvoid main(void) {\n"
- " gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, GAMMA));\n"
- "}\n\n";
-const char* gFS_Fast_SingleModulateA8Texture =
- "\nvoid main(void) {\n"
- " gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
- "}\n\n";
-const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
- "\nvoid main(void) {\n"
- " gl_FragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n"
- "}\n\n";
-const char* gFS_Fast_SingleGradient[2] = {
- "\nvoid main(void) {\n"
- " gl_FragColor = dither(texture2D(gradientSampler, linear));\n"
- "}\n\n",
- "\nvoid main(void) {\n"
- " gl_FragColor = dither(gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
- "}\n\n",
-};
-const char* gFS_Fast_SingleModulateGradient[2] = {
- "\nvoid main(void) {\n"
- " gl_FragColor = dither(color.a * texture2D(gradientSampler, linear));\n"
- "}\n\n",
- "\nvoid main(void) {\n"
- " gl_FragColor = dither(color.a * gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
- "}\n\n"
-};
-
// General case
const char* gFS_Main_FetchColor =
" fragColor = color;\n";
@@ -273,7 +256,7 @@ const char* gFS_Main_ApplyVertexAlphaShadowInterp =
" fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
const char* gFS_Main_FetchTexture[2] = {
// Don't modulate
- " fragColor = texture2D(baseSampler, outTexCoords);\n",
+ " fragColor = OETF(texture2D(baseSampler, outTexCoords));\n",
// Modulate
" fragColor = color * texture2D(baseSampler, outTexCoords);\n"
};
@@ -304,9 +287,9 @@ const char* gFS_Main_FetchGradient[6] = {
" vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
- " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
+ " vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
const char* gFS_Main_FetchBitmapNpot =
- " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
+ " vec4 bitmapColor = OETF(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
const char* gFS_Main_BlendShadersBG =
" fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShadersGB =
@@ -632,71 +615,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
}
- // Optimization for common cases
- if (!description.hasVertexAlpha
- && !blendFramebuffer
- && !description.hasColors
- && description.colorOp == ProgramDescription::ColorFilterMode::None
- && !description.hasDebugHighlight
- && !description.hasRoundRectClip) {
- bool fast = false;
-
- const bool noShader = !description.hasGradient && !description.hasBitmap;
- const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
- !description.hasAlpha8Texture && noShader;
- const bool singleA8Texture = description.hasTexture &&
- description.hasAlpha8Texture && noShader;
- const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
- description.hasGradient && !description.hasBitmap &&
- description.gradientType == ProgramDescription::kGradientLinear;
-
- if (singleColor) {
- shader.append(gFS_Fast_SingleColor);
- fast = true;
- } else if (singleTexture) {
- if (!description.modulate) {
- shader.append(gFS_Fast_SingleTexture);
- } else {
- shader.append(gFS_Fast_SingleModulateTexture);
- }
- fast = true;
- } else if (singleA8Texture) {
- if (!description.modulate) {
- if (description.hasGammaCorrection) {
- shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
- } else {
- shader.append(gFS_Fast_SingleA8Texture);
- }
- } else {
- if (description.hasGammaCorrection) {
- shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
- } else {
- shader.append(gFS_Fast_SingleModulateA8Texture);
- }
- }
- fast = true;
- } else if (singleGradient) {
- shader.append(gFS_Gradient_Functions);
- shader.append(gFS_Gradient_Preamble[mHasSRGB]);
- if (!description.modulate) {
- shader.append(gFS_Fast_SingleGradient[description.isSimpleGradient]);
- } else {
- shader.append(gFS_Fast_SingleModulateGradient[description.isSimpleGradient]);
- }
- fast = true;
- }
-
- if (fast) {
-#if DEBUG_PROGRAMS
- PROGRAM_LOGD("*** Fast case:\n");
- PROGRAM_LOGD("*** Generated fragment shader:\n\n");
- printLongString(shader);
-#endif
-
- return shader;
- }
- }
-
if (description.hasBitmap) {
if (description.isShaderBitmapExternal) {
shader.append(gFS_Uniforms_BitmapExternalSampler);
@@ -719,6 +637,13 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.useShaderBasedWrap) {
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
}
+ if (description.hasGradient || description.hasLinearTexture) {
+ shader.append(gFS_Transfer_Functions);
+ }
+ if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
+ !description.hasAlpha8Texture)) {
+ shader.append(gFS_OETF[description.hasLinearTexture && !mHasSRGB]);
+ }
if (description.hasGradient) {
shader.append(gFS_Gradient_Functions);
shader.append(gFS_Gradient_Preamble[mHasSRGB]);
@@ -810,10 +735,10 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
// End the shader
shader.append(gFS_Footer);
-#if DEBUG_PROGRAMS
+//#if DEBUG_PROGRAMS
PROGRAM_LOGD("*** Generated fragment shader:\n\n");
printLongString(shader);
-#endif
+//#endif
return shader;
}
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index dea2be68c8db..3b87aef942b6 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -37,6 +37,8 @@ namespace uirenderer {
struct ClipBase;
class OffscreenBuffer;
class RenderNode;
+class DeferredLayerUpdater;
+
struct Vertex;
namespace VectorDrawable {
@@ -414,18 +416,18 @@ struct TextOnPathOp : RecordedOp {
};
struct TextureLayerOp : RecordedOp {
- TextureLayerOp(BASE_PARAMS_PAINTLESS, GlLayer* layer)
+ TextureLayerOp(BASE_PARAMS_PAINTLESS, DeferredLayerUpdater* layer)
: SUPER_PAINTLESS(TextureLayerOp)
- , layer(layer) {}
+ , layerHandle(layer) {}
// Copy an existing TextureLayerOp, replacing the underlying matrix
TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
: RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
op.localClip, op.paint)
- , layer(op.layer) {
+ , layerHandle(op.layerHandle) {
}
- GlLayer* layer;
+ DeferredLayerUpdater* layerHandle;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b5e5d6801f99..2e33609665b0 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -606,14 +606,13 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
mDisplayList->ref(layerHandle);
- LOG_ALWAYS_FATAL_IF(layerHandle->backingLayer()->getApi() != Layer::Api::OpenGL);
+ LOG_ALWAYS_FATAL_IF(layerHandle->getBackingLayerApi() != Layer::Api::OpenGL);
// Note that the backing layer has *not* yet been updated, so don't trust
// its width, height, transform, etc...!
addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layerHandle->getWidth(), layerHandle->getHeight()),
*(mState.currentSnapshot()->transform),
- getRecordedClip(),
- static_cast<GlLayer*>(layerHandle->backingLayer())));
+ getRecordedClip(), layerHandle));
}
void RecordingCanvas::callDrawGLFunction(Functor* functor,
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index a5443d9ff6f1..f1c8232760e1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -22,6 +22,7 @@
#include "OpDumper.h"
#include "RecordedOp.h"
#include "TreeInfo.h"
+#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
@@ -39,6 +40,20 @@
namespace android {
namespace uirenderer {
+// Used for tree mutations that are purely destructive.
+// Generic tree mutations should use MarkAndSweepObserver instead
+class ImmediateRemoved : public TreeObserver {
+public:
+ explicit ImmediateRemoved(TreeInfo* info) : mTreeInfo(info) {}
+
+ void onMaybeRemovedFromTree(RenderNode* node) override {
+ node->onRemovedFromTree(mTreeInfo);
+ }
+
+private:
+ TreeInfo* mTreeInfo;
+};
+
RenderNode::RenderNode()
: mDirtyPropertyFields(0)
, mNeedsDisplayListSync(false)
@@ -49,20 +64,17 @@ RenderNode::RenderNode()
}
RenderNode::~RenderNode() {
- deleteDisplayList(nullptr);
+ ImmediateRemoved observer(nullptr);
+ deleteDisplayList(observer);
delete mStagingDisplayList;
LOG_ALWAYS_FATAL_IF(hasLayer(), "layer missed detachment!");
}
-void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* observer) {
+void RenderNode::setStagingDisplayList(DisplayList* displayList) {
+ mValid = (displayList != nullptr);
mNeedsDisplayListSync = true;
delete mStagingDisplayList;
mStagingDisplayList = displayList;
- // If mParentCount == 0 we are the sole reference to this RenderNode,
- // so immediately free the old display list
- if (!mParentCount && !mStagingDisplayList) {
- deleteDisplayList(observer);
- }
}
/**
@@ -187,12 +199,13 @@ int RenderNode::getDebugSize() {
void RenderNode::prepareTree(TreeInfo& info) {
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
+ MarkAndSweepRemoved observer(&info);
// The OpenGL renderer reserves the stencil buffer for overdraw debugging. Functors
// will need to be drawn in a layer.
bool functorsNeedLayer = Properties::debugOverdraw && !Properties::isSkiaEnabled();
- prepareTreeImpl(info, functorsNeedLayer);
+ prepareTreeImpl(observer, info, functorsNeedLayer);
}
void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
@@ -283,7 +296,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
* While traversing down the tree, functorsNeedLayer flag is set to true if anything that uses the
* stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer.
*/
-void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
+void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
@@ -309,14 +322,14 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
- pushStagingDisplayListChanges(info);
+ pushStagingDisplayListChanges(observer, info);
}
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList->hasFunctor();
- bool isDirty = mDisplayList->prepareListAndChildren(info, childFunctorsNeedLayer,
- [](RenderNode* child, TreeInfo& info, bool functorsNeedLayer) {
- child->prepareTreeImpl(info, functorsNeedLayer);
+ bool isDirty = mDisplayList->prepareListAndChildren(observer, info, childFunctorsNeedLayer,
+ [](RenderNode* child, TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
+ child->prepareTreeImpl(observer, info, functorsNeedLayer);
});
if (isDirty) {
damageSelf(info);
@@ -353,7 +366,7 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
}
}
-void RenderNode::syncDisplayList(TreeInfo* info) {
+void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
@@ -361,7 +374,7 @@ void RenderNode::syncDisplayList(TreeInfo* info) {
child->incParentRefCount();
});
}
- deleteDisplayList(info ? info->observer : nullptr, info);
+ deleteDisplayList(observer, info);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
@@ -369,20 +382,20 @@ void RenderNode::syncDisplayList(TreeInfo* info) {
}
}
-void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
+void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info) {
if (mNeedsDisplayListSync) {
mNeedsDisplayListSync = false;
// Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds
damageSelf(info);
- syncDisplayList(&info);
+ syncDisplayList(observer, &info);
damageSelf(info);
}
}
-void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
+void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
if (mDisplayList) {
- mDisplayList->updateChildren([observer, info](RenderNode* child) {
+ mDisplayList->updateChildren([&observer, info](RenderNode* child) {
child->decParentRefCount(observer, info);
});
if (!mDisplayList->reuseDisplayList(this, info ? &info->canvasContext : nullptr)) {
@@ -392,40 +405,47 @@ void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
mDisplayList = nullptr;
}
-void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
+void RenderNode::destroyHardwareResources(TreeInfo* info) {
+ if (hasLayer()) {
+ renderthread::CanvasContext::destroyLayer(this);
+ }
+ setStagingDisplayList(nullptr);
+
+ ImmediateRemoved observer(info);
+ deleteDisplayList(observer, info);
+}
+
+void RenderNode::destroyLayers() {
if (hasLayer()) {
renderthread::CanvasContext::destroyLayer(this);
}
if (mDisplayList) {
- mDisplayList->updateChildren([observer, info](RenderNode* child) {
- child->destroyHardwareResources(observer, info);
+ mDisplayList->updateChildren([](RenderNode* child) {
+ child->destroyLayers();
});
- if (mNeedsDisplayListSync) {
- // Next prepare tree we are going to push a new display list, so we can
- // drop our current one now
- deleteDisplayList(observer, info);
- }
}
}
-void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) {
+void RenderNode::decParentRefCount(TreeObserver& observer, TreeInfo* info) {
LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--;
if (!mParentCount) {
- if (observer) {
- observer->onMaybeRemovedFromTree(this);
- }
+ observer.onMaybeRemovedFromTree(this);
if (CC_UNLIKELY(mPositionListener.get())) {
mPositionListener->onPositionLost(*this, info);
}
- // If a child of ours is being attached to our parent then this will incorrectly
- // destroy its hardware resources. However, this situation is highly unlikely
- // and the failure is "just" that the layer is re-created, so this should
- // be safe enough
- destroyHardwareResources(observer, info);
}
}
+void RenderNode::onRemovedFromTree(TreeInfo* info) {
+ destroyHardwareResources(info);
+}
+
+void RenderNode::clearRoot() {
+ ImmediateRemoved observer(nullptr);
+ decParentRefCount(observer);
+}
+
/**
* Apply property-based transformations to input matrix
*
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index b8964f0f16a0..a971e835e604 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -34,6 +34,7 @@
#include "RenderProperties.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
+#include "utils/FatVector.h"
#include <vector>
@@ -101,7 +102,7 @@ public:
kReplayFlag_ClipChildren = 0x1
};
- ANDROID_API void setStagingDisplayList(DisplayList* newData, TreeObserver* observer);
+ ANDROID_API void setStagingDisplayList(DisplayList* newData);
void computeOrdering();
@@ -164,6 +165,10 @@ public:
return mStagingProperties;
}
+ bool isValid() {
+ return mValid;
+ }
+
int getWidth() const {
return properties().getWidth();
}
@@ -173,7 +178,8 @@ public:
}
ANDROID_API virtual void prepareTree(TreeInfo& info);
- void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr);
+ void destroyHardwareResources(TreeInfo* info = nullptr);
+ void destroyLayers();
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -232,24 +238,34 @@ public:
return mParentCount;
}
+ void onRemovedFromTree(TreeInfo* info);
+
+ // Called by CanvasContext to promote a RenderNode to be a root node
+ void makeRoot() {
+ incParentRefCount();
+ }
+
+ // Called by CanvasContext when it drops a RenderNode from being a root node
+ void clearRoot();
+
private:
void computeOrderingImpl(RenderNodeOp* opState,
std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface);
void syncProperties();
- void syncDisplayList(TreeInfo* info);
+ void syncDisplayList(TreeObserver& observer, TreeInfo* info);
- void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
+ void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
- void pushStagingDisplayListChanges(TreeInfo& info);
+ void pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info);
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
- void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
+ void deleteDisplayList(TreeObserver& observer, TreeInfo* info = nullptr);
void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
- void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr);
+ void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr);
void output(std::ostream& output, uint32_t level);
String8 mName;
@@ -259,6 +275,10 @@ private:
RenderProperties mProperties;
RenderProperties mStagingProperties;
+ // Owned by UI. Set when DL is set, cleared when DL cleared or when node detached
+ // (likely by parent re-record/removal)
+ bool mValid = false;
+
bool mNeedsDisplayListSync;
// WARNING: Do not delete this directly, you must go through deleteDisplayList()!
DisplayList* mDisplayList;
@@ -361,5 +381,28 @@ private:
std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
}; // class RenderNode
+class MarkAndSweepRemoved : public TreeObserver {
+PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
+
+public:
+ explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
+
+ void onMaybeRemovedFromTree(RenderNode* node) override {
+ mMarked.emplace_back(node);
+ }
+
+ ~MarkAndSweepRemoved() {
+ for (auto& node : mMarked) {
+ if (!node->hasParents()) {
+ node->onRemovedFromTree(mTreeInfo);
+ }
+ }
+ }
+
+private:
+ FatVector<sp<RenderNode>, 10> mMarked;
+ TreeInfo* mTreeInfo;
+};
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 89e2a01a5ebe..e54bc36fb0a4 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -367,7 +367,7 @@ void SkiaCanvas::translate(float dx, float dy) {
// (see https://code.google.com/p/skia/issues/detail?id=1303)
bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
SkIRect ibounds;
- if (!mCanvas->getClipDeviceBounds(&ibounds)) {
+ if (!mCanvas->getDeviceClipBounds(&ibounds)) {
return false;
}
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 705395e1e2b7..50af9c8cd711 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -44,10 +44,14 @@ static int bytesPerPixel(GLint glFormat) {
case GL_RGBA16F:
return 8;
default:
- LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
+ LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
}
}
+bool Texture::isLinear() const {
+ return mInternalFormat == GL_RGBA16F;
+}
+
void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force) {
if (force || wrapS != mWrapS || wrapT != mWrapT) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index b8397ccade9c..ce9d4dc234a8 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -128,6 +128,11 @@ public:
}
/**
+ * Returns true if this texture uses a linear encoding format.
+ */
+ bool isLinear() const;
+
+ /**
* Generation of the backing bitmap,
*/
uint32_t generation = 0;
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 14ffc85a4f68..63a6a2c8c89c 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -46,7 +46,7 @@ TextureCache::TextureCache()
}
TextureCache::~TextureCache() {
- mCache.clear();
+ this->clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -101,9 +101,31 @@ bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
return true;
}
+Texture* TextureCache::createTexture(Bitmap* bitmap) {
+ Texture* texture = new Texture(Caches::getInstance());
+ texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
+ texture->generation = bitmap->getGenerationID();
+ texture->upload(*bitmap);
+ return texture;
+}
+
// Returns a prepared Texture* that either is already in the cache or can fit
// in the cache (and is thus added to the cache)
Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
+ if (bitmap->isHardware()) {
+ auto textureIterator = mHardwareTextures.find(bitmap->getStableID());
+ if (textureIterator == mHardwareTextures.end()) {
+ Texture* texture = createTexture(bitmap);
+ mHardwareTextures.insert(std::make_pair(bitmap->getStableID(),
+ std::unique_ptr<Texture>(texture)));
+ if (mDebugEnabled) {
+ ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize);
+ }
+ return texture;
+ }
+ return textureIterator->second.get();
+ }
+
Texture* texture = mCache.get(bitmap->getStableID());
if (!texture) {
@@ -124,11 +146,7 @@ Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
}
if (canCache) {
- texture = new Texture(Caches::getInstance());
- texture->bitmapSize = size;
- texture->generation = bitmap->getGenerationID();
- texture->upload(*bitmap);
-
+ texture = createTexture(bitmap);
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
bitmap, texture->id, size, mSize);
@@ -166,12 +184,7 @@ Texture* TextureCache::get(Bitmap* bitmap) {
if (!canMakeTextureFromBitmap(bitmap)) {
return nullptr;
}
-
- const uint32_t size = bitmap->rowBytes() * bitmap->height();
- texture = new Texture(Caches::getInstance());
- texture->bitmapSize = size;
- texture->upload(*bitmap);
- texture->generation = bitmap->getGenerationID();
+ texture = createTexture(bitmap);
texture->cleanup = true;
}
@@ -188,13 +201,23 @@ void TextureCache::clearGarbage() {
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
uint32_t pixelRefId = mGarbage[i];
- mCache.remove(pixelRefId);
+ auto hardwareIter = mHardwareTextures.find(pixelRefId);
+ if (hardwareIter == mHardwareTextures.end()) {
+ mCache.remove(pixelRefId);
+ } else {
+ hardwareIter->second->deleteTexture();
+ mHardwareTextures.erase(hardwareIter);
+ }
}
mGarbage.clear();
}
void TextureCache::clear() {
mCache.clear();
+ for(auto& iter: mHardwareTextures) {
+ iter.second->deleteTexture();
+ }
+ mHardwareTextures.clear();
TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
}
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 68a548bdb1ff..a55b061818a3 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -125,6 +125,7 @@ private:
bool canMakeTextureFromBitmap(Bitmap* bitmap);
Texture* getCachedTexture(Bitmap* bitmap);
+ Texture* createTexture(Bitmap* bitmap);
LruCache<uint32_t, Texture*> mCache;
@@ -137,6 +138,7 @@ private:
bool mDebugEnabled;
std::vector<uint32_t> mGarbage;
+ std::unordered_map<uint32_t, std::unique_ptr<Texture>> mHardwareTextures;
mutable Mutex mLock;
}; // class TextureCache
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 749efdd26927..c6fbe2bd55de 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -47,9 +47,9 @@ public:
// Due to the unordered nature of tree pushes, once prepareTree
// is finished it is possible that the node was "resurrected" and has
// a non-zero parent count.
- virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+ virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
protected:
- ~TreeObserver() {}
+ virtual ~TreeObserver() {}
};
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
@@ -91,10 +91,6 @@ public:
LayerUpdateQueue* layerUpdateQueue = nullptr;
ErrorHandler* errorHandler = nullptr;
- // Optional, may be nullptr. Used to allow things to observe interesting
- // tree state changes
- TreeObserver* observer = nullptr;
-
int32_t windowInsetLeft = 0;
int32_t windowInsetTop = 0;
bool updateWindowPositions = false;
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index 39522b3c0dda..7e41ad1d0e9c 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -27,8 +27,12 @@ namespace uirenderer {
*/
class VkLayer : public Layer {
public:
- VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
- : Layer(renderState, Api::Vulkan) {}
+ VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
+ , mWidth(layerWidth)
+ , mHeight(layerHeight)
+ , mBlend(blend) {}
virtual ~VkLayer() {}
diff --git a/libs/hwui/debug/nullegl.cpp b/libs/hwui/debug/nullegl.cpp
index 1ce180dd7543..2ae71df5c22c 100644
--- a/libs/hwui/debug/nullegl.cpp
+++ b/libs/hwui/debug/nullegl.cpp
@@ -22,6 +22,7 @@
#include <string.h>
static EGLDisplay gDisplay = (EGLDisplay) 1;
+static EGLSyncKHR gFence = (EGLSyncKHR) 1;
typedef struct {
EGLSurface surface;
@@ -159,6 +160,18 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EG
return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
}
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) {
+ return gFence;
+}
+
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) {
+ return EGL_TRUE;
+}
+
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) {
+ return EGL_CONDITION_SATISFIED_KHR;
+}
+
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
free(image);
return EGL_TRUE;
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index a34b61b56334..3e10b36d921d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -152,6 +152,23 @@ private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
+class AutoGlTexture {
+public:
+ AutoGlTexture(uirenderer::Caches& caches)
+ : mCaches(caches) {
+ glGenTextures(1, &mTexture);
+ caches.textureState().bindTexture(mTexture);
+ }
+
+ ~AutoGlTexture() {
+ mCaches.textureState().deleteTexture(mTexture);
+ }
+
+private:
+ uirenderer::Caches& mCaches;
+ GLuint mTexture = 0;
+};
+
static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
GraphicBuffer& buffer, GLint format, GLint type) {
SkAutoLockPixels alp(bitmap);
@@ -159,10 +176,6 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi
LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
"Failed to get EGL_DEFAULT_DISPLAY! err=%s",
uirenderer::renderthread::EglManager::eglErrorString());
- // These objects are initialized below but the default "null"
- // values are used to cleanup properly at any point in the
- // initialization sequenc
- GLuint texture = 0;
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
@@ -172,8 +185,7 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi
uirenderer::renderthread::EglManager::eglErrorString());
return false;
}
- glGenTextures(1, &texture);
- caches.textureState().bindTexture(texture);
+ AutoGlTexture glTexture(caches);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
GL_CHECKPOINT(MODERATE);
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 956f66ed22cb..6a003794fb28 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -17,7 +17,8 @@
#include "MinikinSkia.h"
#include <log/log.h>
-
+#include <SkFontDescriptor.h>
+#include <SkFontMgr.h>
#include <SkPaint.h>
#include <SkTypeface.h>
@@ -86,6 +87,28 @@ int MinikinFontSkia::GetFontIndex() const {
return mTtcIndex;
}
+minikin::MinikinFont* MinikinFontSkia::createFontWithVariation(
+ const std::vector<minikin::FontVariation>& variations) const {
+ SkFontMgr::FontParameters params;
+
+ int ttcIndex;
+ SkStreamAsset* stream = mTypeface->openStream(&ttcIndex);
+ LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed");
+
+ params.setCollectionIndex(ttcIndex);
+ std::vector<SkFontMgr::FontParameters::Axis> skAxes;
+ skAxes.resize(variations.size());
+ for (size_t i = 0; i < variations.size(); i++) {
+ skAxes[i].fTag = variations[i].axisTag;
+ skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value);
+ }
+ params.setAxes(skAxes.data(), skAxes.size());
+ sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+ sk_sp<SkTypeface> face(fm->createFromStream(stream, params));
+
+ return new MinikinFontSkia(std::move(face), mFontData, mFontSize, ttcIndex);
+}
+
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
uint32_t flags = paint->getFlags();
SkPaint::Hinting hinting = paint->getHinting();
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index 3ee916c6e8b1..249b0cbe44de 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -44,6 +44,8 @@ public:
const void* GetFontData() const;
size_t GetFontSize() const;
int GetFontIndex() const;
+ minikin::MinikinFont* createFontWithVariation(
+ const std::vector<minikin::FontVariation>&) const;
static uint32_t packPaintFlags(const SkPaint* paint);
static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index ca43156e88a1..b69b0cb29efe 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -62,7 +62,7 @@ Typeface* Typeface::resolveDefault(Typeface* src) {
Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface;
- if (result != 0) {
+ if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
result->fFontCollection->Ref();
result->fSkiaStyle = style;
@@ -72,10 +72,30 @@ Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
return result;
}
+Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
+ const std::vector<minikin::FontVariation>& variations) {
+ Typeface* resolvedFace = Typeface::resolveDefault(src);
+ Typeface* result = new Typeface();
+ if (result != nullptr) {
+ result->fFontCollection =
+ resolvedFace->fFontCollection->createCollectionWithVariation(variations);
+ if (result->fFontCollection == nullptr) {
+ // None of passed axes are supported by this collection.
+ // So we will reuse the same collection with incrementing reference count.
+ result->fFontCollection = resolvedFace->fFontCollection;
+ result->fFontCollection->Ref();
+ }
+ result->fSkiaStyle = resolvedFace->fSkiaStyle;
+ result->fBaseWeight = resolvedFace->fBaseWeight;
+ resolveStyle(result);
+ }
+ return result;
+}
+
Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface;
- if (result != 0) {
+ if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
result->fFontCollection->Ref();
result->fSkiaStyle = resolvedFace->fSkiaStyle;
@@ -130,9 +150,9 @@ void Typeface::setRobotoTypefaceForTest() {
sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release());
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
- minikin::FontFamily* family = new minikin::FontFamily();
minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0);
- family->addFont(font);
+ minikin::FontFamily* family = new minikin::FontFamily(
+ std::vector<minikin::Font>({ minikin::Font(font, minikin::FontStyle()) }));
font->Unref();
std::vector<minikin::FontFamily*> typefaces = { family };
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 1be630c1e978..4392ebc36bad 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -43,6 +43,9 @@ struct ANDROID_API Typeface {
static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
+ static Typeface* createFromTypefaceWithVariation(Typeface* src,
+ const std::vector<minikin::FontVariation>& variations);
+
static Typeface* createWeightAlias(Typeface* src, int baseweight);
static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index 37126a69f701..f69da484af43 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -29,5 +29,5 @@ LOCAL_SHARED_LIBRARIES += \
libandroidfw
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
- LOCAL_SHARED_LIBRARIES += libRS libRScpp
+ LOCAL_SHARED_LIBRARIES += libRScpp
endif
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 6ca8d8bbff8a..ea302a154616 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -59,8 +59,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
SkImageInfo canvasInfo = canvas->imageInfo();
SkMatrix44 mat4(canvas->getTotalMatrix());
- SkIRect ibounds;
- canvas->getClipDeviceBounds(&ibounds);
+ SkIRect ibounds = canvas->getDeviceClipBounds();
DrawGlInfo info;
info.clipLeft = ibounds.fLeft;
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index bf39dadbfcc5..012c948be9b3 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -37,9 +37,9 @@ class GLFunctorDrawable : public SkDrawable {
public:
GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
: mFunctor(functor)
- , mListener(listener) {
- canvas->getClipBounds(&mBounds);
- }
+ , mListener(listener)
+ , mBounds(canvas->getLocalClipBounds())
+ {}
virtual ~GLFunctorDrawable();
void syncFunctor() const;
@@ -51,7 +51,7 @@ public:
private:
Functor* mFunctor;
sp<GlFunctorLifecycleListener> mListener;
- SkRect mBounds;
+ const SkRect mBounds;
};
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index d05e7f660c72..2ead5c5897d2 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -24,6 +24,7 @@
#include <SkGaussianEdgeShader.h>
#include <SkPathOps.h>
#include <SkRRectsGaussianEdgeMaskFilter.h>
+#include <SkShadowUtils.h>
namespace android {
namespace uirenderer {
@@ -115,498 +116,6 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
}
}
-/**
- * @param canvas the destination for the shadow draws
- * @param shape the shape casting the shadow
- * @param casterZValue the Z value of the caster RRect
- * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow
- * @param draw the function used to draw 'shape'
- */
-template <typename Shape, typename F>
-static void DrawAmbientShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue,
- float ambientAlpha, F&& draw) {
- if (ambientAlpha <= 0) {
- return;
- }
-
- const float kHeightFactor = 1.f/128.f;
- const float kGeomFactor = 64;
-
- float umbraAlpha = 1 / (1 + SkMaxScalar(casterZValue*kHeightFactor, 0));
- float radius = casterZValue*kHeightFactor*kGeomFactor;
-
- sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
- SkBlurMask::ConvertRadiusToSigma(radius), SkBlurMaskFilter::kNone_BlurFlag);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setMaskFilter(std::move(mf));
- paint.setARGB(ambientAlpha*umbraAlpha, 0, 0, 0);
-
- draw(shape, paint);
-}
-
-/**
- * @param canvas the destination for the shadow draws
- * @param shape the shape casting the shadow
- * @param casterZValue the Z value of the caster RRect
- * @param lightPos the position of the light casting the shadow
- * @param lightWidth
- * @param spotAlpha the maximum alpha value to use when drawing the spot shadow
- * @param draw the function used to draw 'shape'
- */
-template <typename Shape, typename F>
-static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue,
- float spotAlpha, F&& draw) {
- if (spotAlpha <= 0) {
- return;
- }
-
- const Vector3 lightPos = SkiaPipeline::getLightCenter();
- float zRatio = casterZValue / (lightPos.z - casterZValue);
- // clamp
- if (zRatio < 0.0f) {
- zRatio = 0.0f;
- } else if (zRatio > 0.95f) {
- zRatio = 0.95f;
- }
-
- float blurRadius = SkiaPipeline::getLightRadius()*zRatio;
-
- SkAutoCanvasRestore acr(canvas, true);
-
- sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
- SkBlurMask::ConvertRadiusToSigma(blurRadius), SkBlurMaskFilter::kNone_BlurFlag);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setMaskFilter(std::move(mf));
- paint.setARGB(spotAlpha, 0, 0, 0);
-
- // approximate projection by translating and scaling projected offset of bounds center
- // TODO: compute the actual 2D projection
- SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
- canvas->scale(scale, scale);
- SkPoint center = SkPoint::Make(shape.getBounds().centerX(), shape.getBounds().centerY());
- SkMatrix ctmInverse;
- if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
- ALOGW("Matrix is degenerate. Will not render shadow!");
- return;
- }
- SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
- ctmInverse.mapPoints(&lightPos2D, 1);
- canvas->translate(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY));
-
- draw(shape, paint);
-}
-
-#define MAX_BLUR_RADIUS 16383.75f
-#define MAX_PAD 64
-
-/**
- * @param casterRect the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha the maximum alpha value to use when drawing the spot shadow
- * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range)
- * @param casterZValue the Z value of the caster RRect
- * @param scaleFactor the scale needed to map from src-space to device-space
- * @param canvas the destination for the shadow draws
- */
-static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue,
- SkScalar scaleFactor, SkCanvas* canvas) {
- SkASSERT(casterCornerRadius >= 0.0f);
-
- // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
- const SkScalar minRadius = 0.5f / scaleFactor;
-
- const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
- SkScalarHalf(casterRect.height()));
- const bool isRect = casterCornerRadius <= minRadius;
-
- sk_sp<SkShader> edgeShader(SkGaussianEdgeShader::Make());
-
- if (ambientAlpha > 0.0f) {
- static const float kHeightFactor = 1.0f / 128.0f;
- static const float kGeomFactor = 64.0f;
-
- SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor;
- // the device-space radius sent to the blur shader must fit in 14.2 fixed point
- if (srcSpaceAmbientRadius*scaleFactor > MAX_BLUR_RADIUS) {
- srcSpaceAmbientRadius = MAX_BLUR_RADIUS/scaleFactor;
- }
- const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f));
- const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
-
- // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
- // to get our stroke shape.
- SkScalar ambientPathOutset = std::max(ambientOffset - srcSpaceAmbientRadius * 0.5f,
- minRadius);
-
- SkRRect ambientRRect;
- const SkRect temp = casterRect.makeOutset(ambientPathOutset, ambientPathOutset);
- if (isOval) {
- ambientRRect = SkRRect::MakeOval(temp);
- } else if (isRect) {
- ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset);
- } else {
- ambientRRect = SkRRect::MakeRectXY(temp, casterCornerRadius + ambientPathOutset,
- casterCornerRadius + ambientPathOutset);
- }
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- // we outset the stroke a little to cover up AA on the interior edge
- float pad = 0.5f;
- paint.setStrokeWidth(srcSpaceAmbientRadius + 2.0f * pad);
- // handle scale of radius and pad due to CTM
- pad *= scaleFactor;
- const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
- SkASSERT(devSpaceAmbientRadius <= MAX_BLUR_RADIUS);
- SkASSERT(pad < MAX_PAD);
- // convert devSpaceAmbientRadius to 14.2 fixed point and place in the R & G components
- // convert pad to 6.2 fixed point and place in the B component
- uint16_t iDevSpaceAmbientRadius = (uint16_t)(4.0f * devSpaceAmbientRadius);
- paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, iDevSpaceAmbientRadius >> 8,
- iDevSpaceAmbientRadius & 0xff, (unsigned char)(4.0f * pad)));
-
- paint.setShader(edgeShader);
- canvas->drawRRect(ambientRRect, paint);
- }
-
- if (spotAlpha > 0.0f) {
- const Vector3 lightPos = SkiaPipeline::getLightCenter();
- float zRatio = casterZValue / (lightPos.z - casterZValue);
- // clamp
- if (zRatio < 0.0f) {
- zRatio = 0.0f;
- } else if (zRatio > 0.95f) {
- zRatio = 0.95f;
- }
-
- const SkScalar lightWidth = SkiaPipeline::getLightRadius();
- SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
- // the device-space radius sent to the blur shader must fit in 14.2 fixed point
- if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) {
- srcSpaceSpotRadius = MAX_BLUR_RADIUS/scaleFactor;
- }
-
- SkRRect spotRRect;
- if (isOval) {
- spotRRect = SkRRect::MakeOval(casterRect);
- } else if (isRect) {
- spotRRect = SkRRect::MakeRectXY(casterRect, minRadius, minRadius);
- } else {
- spotRRect = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius);
- }
-
- SkRRect spotShadowRRect;
- // Compute the scale and translation for the spot shadow.
- const SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
- spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect);
-
- SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(),
- spotShadowRRect.rect().centerY());
- SkMatrix ctmInverse;
- if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
- ALOGW("Matrix is degenerate. Will not render spot shadow!");
- return;
- }
- SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
- ctmInverse.mapPoints(&lightPos2D, 1);
- const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
- zRatio*(center.fY - lightPos2D.fY));
-
- SkAutoCanvasRestore acr(canvas, true);
-
- // We want to extend the stroked area in so that it meets up with the caster
- // geometry. The stroked geometry will, by definition already be inset half the
- // stroke width but we also have to account for the scaling.
- // We also add 1/2 to cover up AA on the interior edge.
- SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(casterRect.fLeft),
- SkTAbs(casterRect.fRight)), SkTMax(SkTAbs(casterRect.fTop),
- SkTAbs(casterRect.fBottom)));
- SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) +
- scaleOffset + 0.5f;
-
- // Compute area
- SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount;
- SkScalar strokedArea = 2.0f*strokeWidth * (spotShadowRRect.width()
- + spotShadowRRect.height());
- SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius)
- * (spotShadowRRect.width() + srcSpaceSpotRadius);
-
- SkPaint paint;
- paint.setAntiAlias(true);
-
- // If the area of the stroked geometry is larger than the fill geometry, just fill it.
- if (strokedArea > filledArea || casterAlpha < 1.0f || insetAmount < 0.0f) {
- paint.setStyle(SkPaint::kStrokeAndFill_Style);
- paint.setStrokeWidth(srcSpaceSpotRadius);
- } else {
- // Since we can't have unequal strokes, inset the shadow rect so the inner
- // and outer edges of the stroke will land where we want.
- SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
- SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
- minRadius);
- spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(strokeWidth);
- }
-
- // handle scale of radius and pad due to CTM
- const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
- SkASSERT(devSpaceSpotRadius <= MAX_BLUR_RADIUS);
-
- const SkScalar devSpaceSpotPad = 0;
- SkASSERT(devSpaceSpotPad < MAX_PAD);
-
- // convert devSpaceSpotRadius to 14.2 fixed point and place in the R & G
- // components convert devSpaceSpotPad to 6.2 fixed point and place in the B component
- uint16_t iDevSpaceSpotRadius = (uint16_t)(4.0f * devSpaceSpotRadius);
- paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, iDevSpaceSpotRadius >> 8,
- iDevSpaceSpotRadius & 0xff, (unsigned char)(4.0f * devSpaceSpotPad)));
- paint.setShader(edgeShader);
-
- canvas->translate(spotOffset.fX, spotOffset.fY);
- canvas->drawRRect(spotShadowRRect, paint);
- }
-}
-
-/**
- * @param casterRect the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha the maximum alpha value to use when drawing the spot shadow
- * @param casterZValue the Z value of the caster RRect
- * @param scaleFactor the scale needed to map from src-space to device-space
- * @param clipRR the oval or rect with which the drawn roundrect must be intersected
- * @param canvas the destination for the shadow draws
- */
-static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor,
- const SkRRect& clipRR, SkCanvas* canvas) {
- SkASSERT(casterCornerRadius >= 0.0f);
-
- const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
- SkScalarHalf(casterRect.height()));
-
- if (ambientAlpha > 0.0f) {
- static const float kHeightFactor = 1.0f / 128.0f;
- static const float kGeomFactor = 64.0f;
-
- const SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor;
- const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
-
- const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f));
- const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
-
- const SkRect srcSpaceAmbientRect = casterRect.makeOutset(ambientOffset, ambientOffset);
- SkRect devSpaceAmbientRect;
- canvas->getTotalMatrix().mapRect(&devSpaceAmbientRect, srcSpaceAmbientRect);
-
- SkRRect devSpaceAmbientRRect;
- if (isOval) {
- devSpaceAmbientRRect = SkRRect::MakeOval(devSpaceAmbientRect);
- } else {
- const SkScalar devSpaceCornerRadius = scaleFactor * (casterCornerRadius + ambientOffset);
- devSpaceAmbientRRect = SkRRect::MakeRectXY(devSpaceAmbientRect, devSpaceCornerRadius,
- devSpaceCornerRadius);
- }
-
- const SkRect srcSpaceAmbClipRect = clipRR.rect().makeOutset(ambientOffset, ambientOffset);
- SkRect devSpaceAmbClipRect;
- canvas->getTotalMatrix().mapRect(&devSpaceAmbClipRect, srcSpaceAmbClipRect);
- SkRRect devSpaceAmbientClipRR;
- if (clipRR.isOval()) {
- devSpaceAmbientClipRR = SkRRect::MakeOval(devSpaceAmbClipRect);
- } else {
- SkASSERT(clipRR.isRect());
- devSpaceAmbientClipRR = SkRRect::MakeRect(devSpaceAmbClipRect);
- }
-
- SkRect cover = srcSpaceAmbClipRect;
- if (!cover.intersect(srcSpaceAmbientRect)) {
- return;
- }
-
- SkPaint paint;
- paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, 0, 0, 0));
- paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceAmbientRRect,
- devSpaceAmbientClipRR, devSpaceAmbientRadius));
- canvas->drawRect(cover, paint);
- }
-
- if (spotAlpha > 0.0f) {
- const Vector3 lightPos = SkiaPipeline::getLightCenter();
- float zRatio = casterZValue / (lightPos.z - casterZValue);
- // clamp
- if (zRatio < 0.0f) {
- zRatio = 0.0f;
- } else if (zRatio > 0.95f) {
- zRatio = 0.95f;
- }
-
- const SkScalar lightWidth = SkiaPipeline::getLightRadius();
- const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
- const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
-
- // Compute the scale and translation for the spot shadow.
- const SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
- const SkMatrix spotMatrix = SkMatrix::MakeScale(scale, scale);
-
- SkRect srcSpaceScaledRect = casterRect;
- spotMatrix.mapRect(&srcSpaceScaledRect);
- srcSpaceScaledRect.outset(SkScalarHalf(srcSpaceSpotRadius),
- SkScalarHalf(srcSpaceSpotRadius));
-
- SkRRect srcSpaceSpotRRect;
- if (isOval) {
- srcSpaceSpotRRect = SkRRect::MakeOval(srcSpaceScaledRect);
- } else {
- srcSpaceSpotRRect = SkRRect::MakeRectXY(srcSpaceScaledRect, casterCornerRadius * scale,
- casterCornerRadius * scale);
- }
-
- SkPoint center = SkPoint::Make(srcSpaceSpotRRect.rect().centerX(),
- srcSpaceSpotRRect.rect().centerY());
- SkMatrix ctmInverse;
- if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
- ALOGW("Matrix is degenerate. Will not render spot shadow!");
- return;
- }
- SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
- ctmInverse.mapPoints(&lightPos2D, 1);
- const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
- zRatio*(center.fY - lightPos2D.fY));
-
- SkAutoCanvasRestore acr(canvas, true);
- canvas->translate(spotOffset.fX, spotOffset.fY);
-
- SkRect devSpaceScaledRect;
- canvas->getTotalMatrix().mapRect(&devSpaceScaledRect, srcSpaceScaledRect);
-
- SkRRect devSpaceSpotRRect;
- if (isOval) {
- devSpaceSpotRRect = SkRRect::MakeOval(devSpaceScaledRect);
- } else {
- const SkScalar devSpaceScaledCornerRadius = casterCornerRadius * scale * scaleFactor;
- devSpaceSpotRRect = SkRRect::MakeRectXY(devSpaceScaledRect, devSpaceScaledCornerRadius,
- devSpaceScaledCornerRadius);
- }
-
- SkPaint paint;
- paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, 0, 0, 0));
-
- SkRect srcSpaceScaledClipRect = clipRR.rect();
- spotMatrix.mapRect(&srcSpaceScaledClipRect);
- srcSpaceScaledClipRect.outset(SkScalarHalf(srcSpaceSpotRadius),
- SkScalarHalf(srcSpaceSpotRadius));
-
- SkRect devSpaceScaledClipRect;
- canvas->getTotalMatrix().mapRect(&devSpaceScaledClipRect, srcSpaceScaledClipRect);
- SkRRect devSpaceSpotClipRR;
- if (clipRR.isOval()) {
- devSpaceSpotClipRR = SkRRect::MakeOval(devSpaceScaledClipRect);
- } else {
- SkASSERT(clipRR.isRect());
- devSpaceSpotClipRR = SkRRect::MakeRect(devSpaceScaledClipRect);
- }
-
- paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceSpotRRect,
- devSpaceSpotClipRR, devSpaceSpotRadius));
-
- SkRect cover = srcSpaceScaledClipRect;
- if (!cover.intersect(srcSpaceSpotRRect.rect())) {
- return;
- }
-
- canvas->drawRect(cover, paint);
- }
-}
-
-/**
- * @param casterRect the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param casterClipRect a rectangular clip that must be intersected with the
- * shadow-casting RRect prior to casting the shadow
- * @param revealClip a circular clip that must be interested with the castClipRect
- * and the shadow-casting rect prior to casting the shadow
- * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha the maximum alpha value to use when drawing the spot shadow
- * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range)
- * @param casterZValue the Z value of the caster RRect
- * @param canvas the destination for the shadow draws
- *
- * We have special cases for 4 round rect shadow draws:
- * 1) a RRect clipped by a reveal animation
- * 2) a RRect clipped by a rectangle
- * 3) an unclipped RRect with non-uniform scale
- * 4) an unclipped RRect with uniform scale
- * 1,2 and 4 require that the scale is uniform.
- * 1 and 2 require that rects stay rects.
- */
-static bool DrawShadowsAsRRects(const SkRect& casterRect, SkScalar casterCornerRadius,
- const SkRect& casterClipRect, const RevealClip& revealClip, SkScalar ambientAlpha,
- SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkCanvas* canvas) {
- SkScalar scaleFactors[2];
- if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
- ALOGW("Matrix is degenerate. Will not render shadow!");
- return false;
- }
-
- // The casterClipRect will be empty when bounds clipping is disabled
- bool casterIsClippedByRect = !casterClipRect.isEmpty();
- bool uniformScale = scaleFactors[0] == scaleFactors[1];
-
- if (revealClip.willClip()) {
- if (casterIsClippedByRect || !uniformScale || !canvas->getTotalMatrix().rectStaysRect()) {
- return false; // Fall back to the slow path since PathOps are required
- }
-
- const float revealRadius = revealClip.getRadius();
- SkRect revealClipRect = SkRect::MakeLTRB(revealClip.getX()-revealRadius,
- revealClip.getY()-revealRadius, revealClip.getX()+revealRadius,
- revealClip.getY()+revealRadius);
- SkRRect revealClipRR = SkRRect::MakeOval(revealClipRect);
-
- DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha,
- casterZValue, scaleFactors[0], revealClipRR, canvas);
- return true;
- }
-
- if (casterIsClippedByRect) {
- if (!uniformScale || !canvas->getTotalMatrix().rectStaysRect()) {
- return false; // Fall back to the slow path since PathOps are required
- }
-
- SkRRect casterClipRR = SkRRect::MakeRect(casterClipRect);
-
- DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha,
- casterZValue, scaleFactors[0], casterClipRR, canvas);
- return true;
- }
-
- // The fast path needs uniform scale
- if (!uniformScale) {
- SkRRect casterRR = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius);
- DrawAmbientShadowGeneral(canvas, casterRR, casterZValue, ambientAlpha,
- [&](const SkRRect& rrect, const SkPaint& paint) {
- canvas->drawRRect(rrect, paint);
- });
- DrawSpotShadowGeneral(canvas, casterRR, casterZValue, spotAlpha,
- [&](const SkRRect& rrect, const SkPaint& paint) {
- canvas->drawRRect(rrect, paint);
- });
- return true;
- }
-
- DrawRRectShadows(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterAlpha,
- casterZValue, scaleFactors[0], canvas);
- return true;
-}
-
// copied from FrameBuilder::deferShadow
void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
const RenderProperties& casterProperties = caster->getNodeProperties();
@@ -626,8 +135,8 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
return;
}
- float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha;
- float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha;
+ float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
+ float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
const float casterZValue = casterProperties.getZ();
const RevealClip& revealClip = casterProperties.getRevealClip();
@@ -659,19 +168,7 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
hwuiMatrix.copyTo(shadowMatrix);
canvas->concat(shadowMatrix);
- const Outline& casterOutline = casterProperties.getOutline();
- Rect possibleRect;
- float radius;
- if (casterOutline.getAsRoundRect(&possibleRect, &radius)) {
- if (DrawShadowsAsRRects(possibleRect.toSkRect(), radius, casterClipRect, revealClip,
- ambientAlpha, spotAlpha, casterAlpha, casterZValue, canvas)) {
- return;
- }
- }
-
- // Hard cases and calls to general shadow code
const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
-
// holds temporary SkPath to store the result of intersections
SkPath tmpPath;
const SkPath* casterPath = casterOutlinePath;
@@ -691,16 +188,11 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
casterPath = &tmpPath;
}
-
- DrawAmbientShadowGeneral(canvas, *casterPath, casterZValue, ambientAlpha,
- [&](const SkPath& path, const SkPaint& paint) {
- canvas->drawPath(path, paint);
- });
-
- DrawSpotShadowGeneral(canvas, *casterPath, casterZValue, spotAlpha,
- [&](const SkPath& path, const SkPaint& paint) {
- canvas->drawPath(path, paint);
- });
+ const Vector3 lightPos = SkiaPipeline::getLightCenter();
+ SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
+ SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos,
+ SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
+ casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
}
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 9db8cd3fe2e2..36d02ecbc8bb 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -51,8 +51,9 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn)
}
}
-bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
- std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
+bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info,
+ bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
// If the prepare tree is triggered by the UI thread and no previous call to
// pinImages has failed then we must pin all mutable images in the GPU cache
// until the next UI thread draw.
@@ -74,7 +75,7 @@ bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLa
info.damageAccumulator->pushTransform(&mat4);
// TODO: a layer is needed if the canvas is rotated or has a non-rect clip
info.hasBackwardProjectedNodes = false;
- childFn(childNode, info, functorsNeedLayer);
+ childFn(childNode, observer, info, functorsNeedLayer);
hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
info.damageAccumulator->popTransform();
}
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index ff86fd18a9a4..2a013303cbd9 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -113,8 +113,8 @@ public:
* to subclass from DisplayList
*/
- bool prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
- std::function<void(RenderNode*, TreeInfo&, bool)> childFn) override;
+ bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) override;
/**
* Calls the provided function once for each child of this DisplayList
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 65a1dc38ab8e..de80ee3ca229 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -135,11 +135,17 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer);
}
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
+ mode, blend);
+ layer->generateTexture();
+ return layer;
+}
+
DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
mEglManager.initialize();
- GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
- layer->generateTexture();
- return new DeferredLayerUpdater(layer);
+ return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
}
void SkiaOpenGLPipeline::onStop() {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 910c339c4d1c..c63dce1035e7 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -118,11 +118,15 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi
return false;
}
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
+}
+
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
mVkManager.initialize();
- VkLayer* layer = new VkLayer(mRenderThread.renderState(), 0, 0);
- return new DeferredLayerUpdater(layer);
+ return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan);
}
void SkiaVulkanPipeline::onStop() {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 17ee390c90bd..7dfc2ee4fbe5 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "VkLayer.h"
#include <GpuMemoryTracker.h>
@@ -79,6 +80,7 @@ void RenderState::onGLContextDestroyed() {
delete mStencil;
mStencil = nullptr;
+ destroyLayersInUpdater();
GpuMemoryTracker::onGpuContextDestroyed();
}
@@ -209,6 +211,14 @@ void RenderState::debugOverdraw(bool enable, bool clear) {
}
}
+static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
+ layerUpdater->destroyLayer();
+}
+
+void RenderState::destroyLayersInUpdater() {
+ std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
+}
+
class DecStrongTask : public renderthread::RenderTask {
public:
explicit DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index d183a15f3842..f78bf7a4e088 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -42,6 +42,7 @@ namespace uirenderer {
class Caches;
class Layer;
+class DeferredLayerUpdater;
namespace renderthread {
class CanvasContext;
@@ -90,6 +91,14 @@ public:
mRegisteredContexts.erase(context);
}
+ void registerDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
+ mActiveLayerUpdaters.insert(layerUpdater);
+ }
+
+ void unregisterDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
+ mActiveLayerUpdaters.erase(layerUpdater);
+ }
+
// TODO: This system is a little clunky feeling, this could use some
// more thinking...
void postDecStrong(VirtualLightRefBase* object);
@@ -110,6 +119,7 @@ public:
private:
void interruptForFunctorInvoke();
void resumeFromFunctorInvoke();
+ void destroyLayersInUpdater();
explicit RenderState(renderthread::RenderThread& thread);
~RenderState();
@@ -126,6 +136,7 @@ private:
OffscreenBufferPool mLayerPool;
std::set<Layer*> mActiveLayers;
+ std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
std::set<renderthread::CanvasContext*> mRegisteredContexts;
GLsizei mViewportWidth;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1b3bf96998dd..a53e5e0d919a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -146,21 +146,38 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
, mProfiler(mFrames)
, mContentDrawBounds(0, 0, 0, 0)
, mRenderPipeline(std::move(renderPipeline)) {
+ rootRenderNode->makeRoot();
mRenderNodes.emplace_back(rootRenderNode);
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
CanvasContext::~CanvasContext() {
- destroy(nullptr);
+ destroy();
mRenderThread.renderState().unregisterCanvasContext(this);
+ for (auto& node : mRenderNodes) {
+ node->clearRoot();
+ }
+ mRenderNodes.clear();
+}
+
+void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
+ int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
+ node->makeRoot();
+ mRenderNodes.emplace(mRenderNodes.begin() + pos, node);
+}
+
+void CanvasContext::removeRenderNode(RenderNode* node) {
+ node->clearRoot();
+ mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
+ mRenderNodes.end());
}
-void CanvasContext::destroy(TreeObserver* observer) {
+void CanvasContext::destroy() {
stopDrawing();
setSurface(nullptr);
- freePrefetchedLayers(observer);
- destroyHardwareResources(observer);
+ freePrefetchedLayers();
+ destroyHardwareResources();
mAnimationContext->destroy();
}
@@ -320,7 +337,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
mAnimationContext->runRemainingAnimations(info);
GL_CHECKPOINT(MODERATE);
- freePrefetchedLayers(info.observer);
+ freePrefetchedLayers();
GL_CHECKPOINT(MODERATE);
mIsDirty = true;
@@ -504,19 +521,19 @@ void CanvasContext::markLayerInUse(RenderNode* node) {
}
}
-void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
+void CanvasContext::freePrefetchedLayers() {
if (mPrefetchedLayers.size()) {
for (auto& node : mPrefetchedLayers) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
node->getName());
- node->destroyHardwareResources(observer);
- node->decStrong(observer);
+ node->destroyLayers();
+ node->decStrong(nullptr);
}
mPrefetchedLayers.clear();
}
}
-void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
+void CanvasContext::buildLayer(RenderNode* node) {
ATRACE_CALL();
if (!mRenderPipeline->isContextReady()) return;
@@ -525,7 +542,6 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
TreeInfo info(TreeInfo::MODE_FULL, *this);
info.damageAccumulator = &mDamageAccumulator;
- info.observer = observer;
info.layerUpdateQueue = &mLayerUpdateQueue;
info.runAnimations = false;
node->prepareTree(info);
@@ -545,12 +561,12 @@ bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap)
return mRenderPipeline->copyLayerInto(layer, bitmap);
}
-void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
+void CanvasContext::destroyHardwareResources() {
stopDrawing();
if (mRenderPipeline->isContextReady()) {
- freePrefetchedLayers(observer);
+ freePrefetchedLayers();
for (const sp<RenderNode>& node : mRenderNodes) {
- node->destroyHardwareResources(observer);
+ node->destroyHardwareResources();
}
mRenderPipeline->onDestroyHardwareResources();
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0174b86d22d5..aa01caa8fc25 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -132,17 +132,17 @@ public:
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();
- void destroy(TreeObserver* observer);
+ void destroy();
// IFrameCallback, Choreographer-driven frame callback entry point
virtual void doFrame() override;
void prepareAndDraw(RenderNode* node);
- void buildLayer(RenderNode* node, TreeObserver* observer);
+ void buildLayer(RenderNode* node);
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
void markLayerInUse(RenderNode* node);
- void destroyHardwareResources(TreeObserver* observer);
+ void destroyHardwareResources();
static void trimMemory(RenderThread& thread, int level);
DeferredLayerUpdater* createTextureLayer();
@@ -160,15 +160,8 @@ public:
void serializeDisplayListTree();
- void addRenderNode(RenderNode* node, bool placeFront) {
- int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
- mRenderNodes.emplace(mRenderNodes.begin() + pos, node);
- }
-
- void removeRenderNode(RenderNode* node) {
- mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
- mRenderNodes.end());
- }
+ void addRenderNode(RenderNode* node, bool placeFront);
+ void removeRenderNode(RenderNode* node);
void setContentDrawBounds(int left, int top, int right, int bottom) {
mContentDrawBounds.set(left, top, right, bottom);
@@ -213,7 +206,7 @@ private:
void setSurface(Surface* window);
- void freePrefetchedLayers(TreeObserver* observer);
+ void freePrefetchedLayers();
bool isSwapChainStuffed();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 4ff54a5299f8..7d641d3ac7c7 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -65,12 +65,11 @@ void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
}
}
-int DrawFrameTask::drawFrame(TreeObserver* observer) {
+int DrawFrameTask::drawFrame() {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
mSyncResult = SyncResult::OK;
mSyncQueued = systemTime(CLOCK_MONOTONIC);
- mObserver = observer;
postAndWait();
return mSyncResult;
@@ -89,7 +88,6 @@ void DrawFrameTask::run() {
bool canDrawThisFrame;
{
TreeInfo info(TreeInfo::MODE_FULL, *mContext);
- info.observer = mObserver;
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index c02d376098a6..fb480626d421 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -65,7 +65,7 @@ public:
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
- int drawFrame(TreeObserver* observer);
+ int drawFrame();
int64_t* frameInfo() { return mFrameInfo; }
@@ -90,7 +90,6 @@ private:
int mSyncResult;
int64_t mSyncQueued;
- TreeObserver* mObserver;
int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
};
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index df40a44a16cb..8a5d9ccf759c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -125,13 +125,18 @@ bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap
static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
}
-DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
- mEglManager.initialize();
- GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
+ mode, blend);
Caches::getInstance().textureState().activateTexture(0);
layer->generateTexture();
+ return layer;
+}
- return new DeferredLayerUpdater(layer);
+DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
+ mEglManager.initialize();
+ return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
}
void OpenGLPipeline::onStop() {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 022e871315a9..fb79272e18af 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -230,19 +230,18 @@ int64_t* RenderProxy::frameInfo() {
return mDrawFrameTask.frameInfo();
}
-int RenderProxy::syncAndDrawFrame(TreeObserver* observer) {
- return mDrawFrameTask.drawFrame(observer);
+int RenderProxy::syncAndDrawFrame() {
+ return mDrawFrameTask.drawFrame();
}
-CREATE_BRIDGE2(destroy, CanvasContext* context, TreeObserver* observer) {
- args->context->destroy(args->observer);
+CREATE_BRIDGE1(destroy, CanvasContext* context) {
+ args->context->destroy();
return nullptr;
}
-void RenderProxy::destroy(TreeObserver* observer) {
+void RenderProxy::destroy() {
SETUP_TASK(destroy);
args->context = mContext;
- args->observer = observer;
// destroyCanvasAndSurface() needs a fence as when it returns the
// underlying BufferQueue is going to be released from under
// the render thread.
@@ -282,16 +281,15 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() {
return layer;
}
-CREATE_BRIDGE3(buildLayer, CanvasContext* context, RenderNode* node, TreeObserver* observer) {
- args->context->buildLayer(args->node, args->observer);
+CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
+ args->context->buildLayer(args->node);
return nullptr;
}
-void RenderProxy::buildLayer(RenderNode* node, TreeObserver* observer) {
+void RenderProxy::buildLayer(RenderNode* node) {
SETUP_TASK(buildLayer);
args->context = mContext;
args->node = node;
- args->observer = observer;
postAndWait(task);
}
@@ -328,15 +326,14 @@ void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
postAndWait(task);
}
-CREATE_BRIDGE2(destroyHardwareResources, CanvasContext* context, TreeObserver* observer) {
- args->context->destroyHardwareResources(args->observer);
+CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
+ args->context->destroyHardwareResources();
return nullptr;
}
-void RenderProxy::destroyHardwareResources(TreeObserver* observer) {
+void RenderProxy::destroyHardwareResources() {
SETUP_TASK(destroyHardwareResources);
args->context = mContext;
- args->observer = observer;
postAndWait(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 44a5a147b6da..1629090d84a4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -44,7 +44,6 @@ class RenderNode;
class DisplayList;
class Layer;
class Rect;
-class TreeObserver;
namespace renderthread {
@@ -87,19 +86,19 @@ public:
ANDROID_API void setLightCenter(const Vector3& lightCenter);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API int64_t* frameInfo();
- ANDROID_API int syncAndDrawFrame(TreeObserver* observer);
- ANDROID_API void destroy(TreeObserver* observer);
+ ANDROID_API int syncAndDrawFrame();
+ ANDROID_API void destroy();
ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
ANDROID_API DeferredLayerUpdater* createTextureLayer();
- ANDROID_API void buildLayer(RenderNode* node, TreeObserver* observer);
+ ANDROID_API void buildLayer(RenderNode* node);
ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
- ANDROID_API void destroyHardwareResources(TreeObserver* observer);
+ ANDROID_API void destroyHardwareResources();
ANDROID_API static void trimMemory(int level);
ANDROID_API static void overrideProperty(const char* name, const char* value);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 454ce4d9e8ff..c2c2f2239c7f 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -603,6 +603,11 @@ static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
}
void VulkanManager::swapBuffers(VulkanSurface* surface) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mBackendContext->fDevice);
+ }
+
VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
surface->mCurrentBackbufferIndex;
GrVkImageInfo* imageInfo;
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 5e937f3239ff..c1ca1e7ac28a 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -16,6 +16,8 @@
#include "tests/common/TestContext.h"
+#include <cutils/trace.h>
+
namespace android {
namespace uirenderer {
namespace test {
@@ -98,6 +100,11 @@ void TestContext::createOffscreenSurface() {
}
void TestContext::waitForVsync() {
+ // Hacky fix for not getting sysprop change callbacks
+ // We just poll the sysprop in vsync since it's when the UI thread is
+ // "idle" and shouldn't burn too much time
+ atrace_update_tags();
+
if (mConsumer.get()) {
BufferItem buffer;
if (mConsumer->acquireBuffer(&buffer, 0, false) == OK) {
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
index 6d2e85996444..38c4848ebc41 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.cpp
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -69,7 +69,7 @@ void TestListViewSceneBase::doFrame(int frameNr) {
// draw it to parent DisplayList
canvas->drawRenderNode(mListItems[ci].get());
}
- mListView->setStagingDisplayList(canvas->finishRecording(), nullptr);
+ mListView->setStagingDisplayList(canvas->finishRecording());
}
} // namespace test
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 79daa3f9ffeb..3e52c39b5c1f 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -60,6 +60,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread);
}
sp<DeferredLayerUpdater> layerUpdater = pipeline->createTextureLayer();
+ layerUpdater->apply();
delete pipeline;
return layerUpdater;
}
@@ -193,9 +194,7 @@ SkColor TestUtils::getColor(const sk_sp<SkSurface>& surface, int x, int y) {
}
SkRect TestUtils::getClipBounds(const SkCanvas* canvas) {
- SkIRect bounds;
- (void)canvas->getClipDeviceBounds(&bounds);
- return SkRect::Make(bounds);
+ return SkRect::Make(canvas->getDeviceClipBounds());
}
SkRect TestUtils::getLocalClipBounds(const SkCanvas* canvas) {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 8b287de3220e..0c7bb6079fea 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -156,6 +156,11 @@ public:
int* mSignal;
};
+ class MockTreeObserver : public TreeObserver {
+ public:
+ virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+ };
+
static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
for (int i = 0; i < 16; i++) {
if (!MathUtils::areEqual(a[i], b[i])) {
@@ -215,7 +220,7 @@ public:
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(props.getWidth(),
props.getHeight()));
setup(props, *canvas.get());
- node->setStagingDisplayList(canvas->finishRecording(), nullptr);
+ node->setStagingDisplayList(canvas->finishRecording());
}
node->setPropertyFieldsDirty(0xFFFFFFFF);
return node;
@@ -236,7 +241,7 @@ public:
if (setup) {
RecordingCanvasType canvas(props.getWidth(), props.getHeight());
setup(props, canvas);
- node->setStagingDisplayList(canvas.finishRecording(), nullptr);
+ node->setStagingDisplayList(canvas.finishRecording());
}
node->setPropertyFieldsDirty(0xFFFFFFFF);
return node;
@@ -247,7 +252,7 @@ public:
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
contentCallback(*canvas.get());
- node.setStagingDisplayList(canvas->finishRecording(), nullptr);
+ node.setStagingDisplayList(canvas->finishRecording());
}
static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
@@ -265,14 +270,14 @@ public:
RenderProperties& props = node->mutateStagingProperties();
props.setLeftTopRightBottom(left, top, right, bottom);
if (displayList) {
- node->setStagingDisplayList(displayList, nullptr);
+ node->setStagingDisplayList(displayList);
}
if (setup) {
std::unique_ptr<skiapipeline::SkiaRecordingCanvas> canvas(
new skiapipeline::SkiaRecordingCanvas(nullptr,
props.getWidth(), props.getHeight()));
setup(props, *canvas.get());
- node->setStagingDisplayList(canvas->finishRecording(), nullptr);
+ node->setStagingDisplayList(canvas->finishRecording());
}
node->setPropertyFieldsDirty(0xFFFFFFFF);
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
@@ -350,8 +355,12 @@ public:
private:
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
+ MarkAndSweepRemoved observer(nullptr);
node->syncProperties();
- node->syncDisplayList(nullptr);
+ if (node->mNeedsDisplayListSync) {
+ node->mNeedsDisplayListSync = false;
+ node->syncDisplayList(observer, nullptr);
+ }
auto displayList = node->getDisplayList();
if (displayList) {
for (auto&& childOp : displayList->getChildren()) {
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index c0d9450ebace..5b685bb2f3f7 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -60,6 +60,6 @@ public:
0, 100 * (i + 2), minikin::kBidi_Force_LTR, paint, nullptr);
}
- container->setStagingDisplayList(canvas->finishRecording(), nullptr);
+ container->setStagingDisplayList(canvas->finishRecording());
}
};
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
new file mode 100644
index 000000000000..ad0b1f15abff
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include <string>
+#include <hwui/Paint.h>
+#include <minikin/Layout.h>
+
+class SaveLayer2Animation;
+
+static TestScene::Registrar _SaveLayer(TestScene::Info{
+ "savelayer2",
+ "Interleaving 20 drawText/drawRect ops with saveLayer"
+ "Tests the clipped saveLayer performance and FBO switching overhead.",
+ TestScene::simpleCreateScene<SaveLayer2Animation>
+});
+
+class SaveLayer2Animation : public TestScene {
+public:
+ Paint mBluePaint;
+ Paint mGreenPaint;
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ canvas.drawColor(SkColorSetARGB(255, 255, 0, 0), SkBlendMode::kSrcOver);
+ SkIRect bounds = SkIRect::MakeWH(width, height);
+ int regions = 20;
+ int smallRectHeight = (bounds.height()/regions);
+ int padding = smallRectHeight / 4;
+ int top = bounds.fTop;
+
+ mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255));
+ mBluePaint.setTextSize(padding);
+ mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
+ mGreenPaint.setTextSize(padding);
+
+ //interleave drawText and drawRect with saveLayer ops
+ for (int i = 0; i < regions; i++, top += smallRectHeight) {
+ canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding,
+ &mBluePaint, SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
+ canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
+ std::string stri = std::to_string(i);
+ std::string offscreen = "offscreen line " + stri;
+ std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
+ canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(),
+ bounds.fLeft, top + padding, minikin::kBidi_Force_LTR, mBluePaint, nullptr);
+ canvas.restore();
+
+ canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
+ top + smallRectHeight - padding, mBluePaint);
+ std::string onscreen = "onscreen line " + stri;
+ std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
+ canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
+ top + smallRectHeight - padding, minikin::kBidi_Force_LTR, mGreenPaint,
+ nullptr);
+ }
+ }
+ void doFrame(int frameNr) override {
+ }
+};
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
new file mode 100644
index 000000000000..a63a5852a9ff
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+
+#include <SkColorMatrixFilter.h>
+#include <SkGradientShader.h>
+
+class SimpleColorMatrixAnimation;
+
+static TestScene::Registrar _SimpleColorMatrix(TestScene::Info{
+ "simpleColorMatrix",
+ "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and B "
+ "all scaled and translated the same amount.",
+ TestScene::simpleCreateScene<SimpleColorMatrixAnimation>
+});
+
+class SimpleColorMatrixAnimation : public TestScene {
+public:
+ std::vector< sp<RenderNode> > cards;
+ void createContent(int width, int height, Canvas& canvas) override {
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+
+ sp<RenderNode> card = createCard(0, 0, width, height);
+ canvas.drawRenderNode(card.get());
+ cards.push_back(card);
+ }
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 20;
+ for (size_t ci = 0; ci < cards.size(); ci++) {
+ cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+ cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+ cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+ }
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ return TestUtils::createNode(x, y, x + width, y + height,
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ float matrix[20] = { 0 };
+
+ // Simple scale/translate case where R, G, and B are all treated equivalently
+ matrix[SkColorMatrix::kR_Scale] = 1.1f;
+ matrix[SkColorMatrix::kG_Scale] = 1.1f;
+ matrix[SkColorMatrix::kB_Scale] = 1.1f;
+ matrix[SkColorMatrix::kA_Scale] = 0.5f;
+
+ matrix[SkColorMatrix::kR_Trans] = 5.0f;
+ matrix[SkColorMatrix::kG_Trans] = 5.0f;
+ matrix[SkColorMatrix::kB_Trans] = 5.0f;
+ matrix[SkColorMatrix::kA_Trans] = 10.0f;
+
+ paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
+
+ // set a shader so it's not likely for the matrix to be optimized away (since a clever
+ // enough renderer might apply it directly to the paint color)
+ float pos[] = { 0, 1 };
+ SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
+ SkColor colors[2] = { Color::DeepPurple_500, Color::DeepOrange_500 };
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+ SkShader::kClamp_TileMode));
+
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
+ }
+};
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
new file mode 100644
index 000000000000..053eb6dee31c
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "TestSceneBase.h"
+
+#include <SkGradientShader.h>
+
+class SimpleGradientAnimation;
+
+static TestScene::Registrar _SimpleGradient(TestScene::Info{
+ "simpleGradient",
+ "A benchmark of shader performance of linear, 2 color gradients with black in them.",
+ TestScene::simpleCreateScene<SimpleGradientAnimation>
+});
+
+class SimpleGradientAnimation : public TestScene {
+public:
+ std::vector< sp<RenderNode> > cards;
+ void createContent(int width, int height, Canvas& canvas) override {
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+
+ sp<RenderNode> card = createCard(0, 0, width, height);
+ canvas.drawRenderNode(card.get());
+ cards.push_back(card);
+ }
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 20;
+ for (size_t ci = 0; ci < cards.size(); ci++) {
+ cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+ cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+ cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+ }
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ return TestUtils::createNode(x, y, x + width, y + height,
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ float pos[] = { 0, 1 };
+ SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
+ SkPaint paint;
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ // use i%2 start position to pick 2 color combo with black in it
+ SkColor colors[3] = { Color::Transparent, Color::Black, Color::Cyan_500 };
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
+ SkShader::kClamp_TileMode));
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
+ }
+};
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 396e896a7517..f8d63978bb53 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -151,7 +151,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
- proxy->syncAndDrawFrame(nullptr);
+ proxy->syncAndDrawFrame();
}
proxy->resetProfileInfo();
@@ -167,7 +167,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
ATRACE_NAME("UI-Draw Frame");
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
scene->doFrame(i);
- proxy->syncAndDrawFrame(nullptr);
+ proxy->syncAndDrawFrame();
}
if (opts.reportFrametimeWeight) {
proxy->fence();
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index 42ba3dbd2362..ef5ce0d9968e 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -40,7 +40,7 @@ RENDERTHREAD_TEST(CanvasContext, create) {
ASSERT_FALSE(canvasContext->hasSurface());
- canvasContext->destroy(nullptr);
+ canvasContext->destroy();
}
RENDERTHREAD_TEST(CanvasContext, invokeFunctor) {
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 5a2791cdfd82..a391d1e61a57 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -322,10 +322,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
}
for (auto& node : nodes) {
+ EXPECT_TRUE(node->isValid());
EXPECT_FALSE(node->nothingToDraw());
- node->setStagingDisplayList(nullptr, nullptr);
- node->destroyHardwareResources(nullptr);
+ node->setStagingDisplayList(nullptr);
+ EXPECT_FALSE(node->isValid());
+ EXPECT_FALSE(node->nothingToDraw());
+ node->destroyHardwareResources();
EXPECT_TRUE(node->nothingToDraw());
+ EXPECT_FALSE(node->isValid());
}
{
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 2f1eae3ec10e..f21b3f7ec334 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -321,7 +321,6 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
parent->prepareTree(info);
//parent(A) -> (receiverBackground, child)
@@ -437,7 +436,6 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) {
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
parent->prepareTree(info);
int drawCounter = 0;
@@ -527,7 +525,6 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
parent->prepareTree(info);
std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
@@ -545,7 +542,6 @@ static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
renderNode->prepareTree(info);
//create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index ab8e4e106d3e..2925243d9f1c 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -66,6 +66,176 @@ TEST(RenderNode, hasParents) {
EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
}
+TEST(RenderNode, validity) {
+ auto child = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+ });
+ auto parent = TestUtils::createNode(0, 0, 200, 400,
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_TRUE(parent->nothingToDraw());
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent->nothingToDraw());
+
+ TestUtils::recordNode(*parent, [](Canvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
+ });
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent->nothingToDraw());
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_FALSE(child->isValid());
+ EXPECT_TRUE(parent->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_FALSE(parent->nothingToDraw());
+
+ TestUtils::recordNode(*child, [](Canvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
+ });
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+
+ TestUtils::recordNode(*parent, [&child](Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent->nothingToDraw());
+
+ parent->destroyHardwareResources();
+
+ EXPECT_FALSE(child->isValid());
+ EXPECT_FALSE(parent->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_TRUE(parent->nothingToDraw());
+}
+
+TEST(RenderNode, multiTreeValidity) {
+ auto child = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+ });
+ auto parent1 = TestUtils::createNode(0, 0, 200, 400,
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+ auto parent2 = TestUtils::createNode(0, 0, 200, 400,
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_TRUE(parent1->nothingToDraw());
+ EXPECT_TRUE(parent2->nothingToDraw());
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent1->nothingToDraw());
+ EXPECT_TRUE(parent2->nothingToDraw());
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent1->nothingToDraw());
+ EXPECT_FALSE(parent2->nothingToDraw());
+
+ TestUtils::recordNode(*parent1, [](Canvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent1->nothingToDraw());
+ EXPECT_FALSE(parent2->nothingToDraw());
+
+ TestUtils::recordNode(*parent2, [](Canvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
+
+ EXPECT_FALSE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_FALSE(parent1->nothingToDraw());
+ EXPECT_FALSE(parent2->nothingToDraw());
+
+ TestUtils::recordNode(*child, [](Canvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+ });
+ TestUtils::syncHierarchyPropertiesAndDisplayList(child);
+
+ TestUtils::recordNode(*parent1, [&child](Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
+
+ TestUtils::recordNode(*parent2, [&child](Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_TRUE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_FALSE(parent1->nothingToDraw());
+ EXPECT_FALSE(parent2->nothingToDraw());
+
+ parent1->destroyHardwareResources();
+
+ EXPECT_TRUE(child->isValid());
+ EXPECT_FALSE(parent1->isValid());
+ EXPECT_TRUE(parent2->isValid());
+ EXPECT_FALSE(child->nothingToDraw());
+ EXPECT_TRUE(parent1->nothingToDraw());
+ EXPECT_FALSE(parent2->nothingToDraw());
+
+ parent2->destroyHardwareResources();
+
+ EXPECT_FALSE(child->isValid());
+ EXPECT_FALSE(parent1->isValid());
+ EXPECT_FALSE(parent2->isValid());
+ EXPECT_TRUE(child->nothingToDraw());
+ EXPECT_TRUE(parent1->nothingToDraw());
+ EXPECT_TRUE(parent2->nothingToDraw());
+}
+
TEST(RenderNode, releasedCallback) {
class DecRefOnReleased : public GlFunctorLifecycleListener {
public:
@@ -112,7 +282,6 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
{
auto nonNullDLNode = TestUtils::createNode(0, 0, 200, 400,
@@ -131,7 +300,7 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
nullDLNode->prepareTree(info);
}
- canvasContext->destroy(nullptr);
+ canvasContext->destroy();
}
RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
@@ -151,7 +320,6 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
LayerUpdateQueue layerUpdateQueue;
info.damageAccumulator = &damageAccumulator;
info.layerUpdateQueue = &layerUpdateQueue;
- info.observer = nullptr;
// Put node on HW layer
rootNode->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
@@ -165,5 +333,5 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
EXPECT_FALSE(info.layerUpdateQueue->entries().empty());
EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode);
EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
- canvasContext->destroy(nullptr);
+ canvasContext->destroy();
}
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 8f6fc8b2e960..be460bf6bdfe 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -126,7 +126,6 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
- info.observer = nullptr;
SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200));
@@ -137,7 +136,9 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
ASSERT_FALSE(cleanVD.isDirty());
ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
- ASSERT_FALSE(skiaDL.prepareListAndChildren(info, false, [](RenderNode*, TreeInfo&, bool) {}));
+ TestUtils::MockTreeObserver observer;
+ ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false,
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a dirty VD
@@ -146,7 +147,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
ASSERT_TRUE(dirtyVD.isDirty());
ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
- ASSERT_TRUE(skiaDL.prepareListAndChildren(info, false, [](RenderNode*, TreeInfo&, bool) {}));
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a RenderNode and a callback
@@ -155,8 +157,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
SkCanvas dummyCanvas;
skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
bool hasRun = false;
- ASSERT_TRUE(skiaDL.prepareListAndChildren(info, false,
- [&hasRun, renderNode, infoPtr](RenderNode* n, TreeInfo& i, bool r) {
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
+ [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i, bool r) {
hasRun = true;
ASSERT_EQ(renderNode.get(), n);
ASSERT_EQ(infoPtr, &i);
@@ -164,7 +166,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
}));
ASSERT_TRUE(hasRun);
- canvasContext->destroy(nullptr);
+ canvasContext->destroy();
}
TEST(SkiaDisplayList, updateChildren) {
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 0b8c2a98fab5..5bb0b6db06b5 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -170,9 +170,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
// 1 Overdraw, should be blue blended onto white.
- renderNodes.push_back(whiteNode); //this is the "content" node
- renderNodes.push_back(whiteNode); //the "content" node above does not cause an overdraw, because
- //it clips the first "background" node
+ renderNodes.push_back(whiteNode);
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
diff --git a/libs/hwui/tests/unit/TextureCacheTests.cpp b/libs/hwui/tests/unit/TextureCacheTests.cpp
new file mode 100644
index 000000000000..72384bfa87d8
--- /dev/null
+++ b/libs/hwui/tests/unit/TextureCacheTests.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Extensions.h"
+#include "TextureCache.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+RENDERTHREAD_OPENGL_PIPELINE_TEST(TextureCache, clear) {
+ TextureCache cache;
+ ASSERT_EQ(cache.getSize(), 0u);
+ // it is not 0, because FontRenderer allocates one texture
+ int initialCount = GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture);
+ SkBitmap skBitmap;
+ SkImageInfo info = SkImageInfo::Make(100, 100, kN32_SkColorType, kPremul_SkAlphaType);
+ skBitmap.setInfo(info);
+ sk_sp<Bitmap> hwBitmap(Bitmap::allocateHardwareBitmap(renderThread, skBitmap));
+ cache.get(hwBitmap.get());
+ ASSERT_EQ(GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture), initialCount + 1);
+ cache.clear();
+ ASSERT_EQ(GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture), initialCount);
+}
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index f9cc46d1cf30..0950eb8e7134 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -83,7 +83,7 @@ namespace uirenderer {
static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
// Opto-electronic conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+ // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
static constexpr float OECF_sRGB(float linear) {
// IEC 61966-2-1:1999
return linear <= 0.0031308f ?
@@ -91,7 +91,7 @@ namespace uirenderer {
}
// Opto-electronic conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+ // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
// This function returns the input unmodified if linear blending is not enabled
static constexpr float OECF(float linear) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
@@ -102,14 +102,14 @@ namespace uirenderer {
}
// Electro-optical conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+ // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
static constexpr float EOCF_sRGB(float srgb) {
// IEC 61966-2-1:1999
return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
}
// Electro-optical conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+ // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
// This function returns the input unmodified if linear blending is not enabled
static constexpr float EOCF(float srgb) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 8b80d690b39f..79fc8643859c 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -98,8 +98,8 @@ public:
}
void finishDrawing() {
- mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
- mProxy->syncAndDrawFrame(nullptr);
+ mRootNode->setStagingDisplayList(mCanvas->finishRecording());
+ mProxy->syncAndDrawFrame();
// Surprisingly, calling mProxy->fence() here appears to make no difference to
// the timings we record.
}
diff --git a/location/java/android/location/BatchedLocationCallback.java b/location/java/android/location/BatchedLocationCallback.java
new file mode 100644
index 000000000000..f1c40ae256b7
--- /dev/null
+++ b/location/java/android/location/BatchedLocationCallback.java
@@ -0,0 +1,44 @@
+/*
+ * 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.location;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Used for receiving notifications from the LocationManager when
+ * the a batch of location is ready. These methods are called if the
+ * BatchedLocationCallback has been registered with the location manager service
+ * using the
+ * {@link LocationManager#registerGnssBatchedLocationCallback#startGnssBatch(long,
+ * boolean, BatchedLocationCallback, android.os.Handler)} method.
+ * @hide
+ */
+@SystemApi
+public abstract class BatchedLocationCallback {
+
+ /**
+ * Called when a new batch of locations is ready
+ *
+ * @param locations A list of all new locations (possibly zero of them.)
+ */
+ public void onLocationBatch(List<Location> locations) {}
+}
diff --git a/location/java/android/location/BatchedLocationCallbackTransport.java b/location/java/android/location/BatchedLocationCallbackTransport.java
new file mode 100644
index 000000000000..e00f855e9302
--- /dev/null
+++ b/location/java/android/location/BatchedLocationCallbackTransport.java
@@ -0,0 +1,66 @@
+/*
+ * 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.location;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A handler class to manage transport callbacks for {@link BatchedLocationCallback}.
+ *
+ * @hide
+ */
+class BatchedLocationCallbackTransport
+ extends LocalListenerHelper<BatchedLocationCallback> {
+ private final ILocationManager mLocationManager;
+
+ private final IBatchedLocationCallback mCallbackTransport = new CallbackTransport();
+
+ public BatchedLocationCallbackTransport(Context context, ILocationManager locationManager) {
+ super(context, "BatchedLocationCallbackTransport");
+ mLocationManager = locationManager;
+ }
+
+ @Override
+ protected boolean registerWithServer() throws RemoteException {
+ return mLocationManager.addGnssBatchingCallback(
+ mCallbackTransport,
+ getContext().getPackageName());
+ }
+
+ @Override
+ protected void unregisterFromServer() throws RemoteException {
+ mLocationManager.removeGnssBatchingCallback();
+ }
+
+ private class CallbackTransport extends IBatchedLocationCallback.Stub {
+ @Override
+ public void onLocationBatch(final List<Location> locations) {
+ ListenerOperation<BatchedLocationCallback> operation =
+ new ListenerOperation<BatchedLocationCallback>() {
+ @Override
+ public void execute(BatchedLocationCallback callback)
+ throws RemoteException {
+ callback.onLocationBatch(locations);
+ }
+ };
+ foreach(operation);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index aa26111a73e7..c7188aa34522 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -89,7 +89,7 @@ public final class GnssNavigationMessage implements Parcelable {
*/
public static abstract class Callback {
/**
- * The status of GNSS measurements event.
+ * The status of GNSS Navigation Message event.
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
diff --git a/location/java/android/location/IBatchedLocationCallback.aidl b/location/java/android/location/IBatchedLocationCallback.aidl
new file mode 100644
index 000000000000..dce9f964c010
--- /dev/null
+++ b/location/java/android/location/IBatchedLocationCallback.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.location;
+
+import android.location.Location;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+oneway interface IBatchedLocationCallback
+{
+ void onLocationBatch(in List<Location> locations);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index bc8b026222ed..fc31f326354f 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,6 +21,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.IBatchedLocationCallback;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
import android.location.IGnssNavigationMessageListener;
@@ -71,6 +72,13 @@ interface ILocationManager
int getGnssYearOfHardware();
+ int getGnssBatchSize(String packageName);
+ boolean addGnssBatchingCallback(in IBatchedLocationCallback callback, String packageName);
+ void removeGnssBatchingCallback();
+ boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName);
+ void flushGnssBatch(String packageName);
+ boolean stopGnssBatch();
+
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
@@ -99,6 +107,9 @@ interface ILocationManager
// it need not be shared with other providers.
void reportLocation(in Location location, boolean passive);
+ // Used when a (initially Gnss) Location batch arrives
+ void reportLocationBatch(in List<Location> locations);
+
// for reporting callback completion
void locationCallbackFinished(ILocationListener listener);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 4e146268b256..f9385c6d3b7f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -18,6 +18,7 @@ package android.location;
import com.android.internal.location.ProviderProperties;
+import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -59,13 +60,15 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION;
* return location results, but the update rate will be throttled and the exact
* location will be obfuscated to a coarse level of accuracy.
*/
-public class LocationManager {
+public class LocationManager
+{
private static final String TAG = "LocationManager";
private final Context mContext;
private final ILocationManager mService;
private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport;
private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport;
+ private final BatchedLocationCallbackTransport mBatchedLocationCallbackTransport;
private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
new HashMap<>();
private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
@@ -321,9 +324,13 @@ public class LocationManager {
public LocationManager(Context context, ILocationManager service) {
mService = service;
mContext = context;
- mGnssMeasurementCallbackTransport = new GnssMeasurementCallbackTransport(mContext, mService);
+ mGnssMeasurementCallbackTransport =
+ new GnssMeasurementCallbackTransport(mContext, mService);
mGnssNavigationMessageCallbackTransport =
new GnssNavigationMessageCallbackTransport(mContext, mService);
+ mBatchedLocationCallbackTransport =
+ new BatchedLocationCallbackTransport(mContext, mService);
+
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1878,7 +1885,8 @@ public class LocationManager {
* No-op method to keep backward-compatibility.
* Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead.
* @hide
- * @deprecated use {@link #unregisterGnssNavigationMessageCallback(GnssMeasurements.Callback)}
+ * @deprecated use
+ * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)}
* instead
*/
@Deprecated
@@ -1960,6 +1968,96 @@ public class LocationManager {
}
/**
+ * Returns the batch size (in number of Location objects) that are supported by the batching
+ * interface.
+ *
+ * @return Maximum number of location objects that can be returned
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public int getGnssBatchSize() {
+ try {
+ return mService.getGnssBatchSize(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Start hardware-batching of GNSS locations. This API is primarily used when the AP is
+ * asleep and the device can batch GNSS locations in the hardware.
+ *
+ * Note this is designed (as was the fused location interface before it) for a single user
+ * SystemApi - requests are not consolidated. Care should be taken when the System switches
+ * users that may have different batching requests, to stop hardware batching for one user, and
+ * restart it for the next.
+ *
+ * @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 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
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
+ BatchedLocationCallback callback, Handler handler) {
+ mBatchedLocationCallbackTransport.add(callback, handler);
+
+ try {
+ return mService.startGnssBatch(periodNanos, wakeOnFifoFull, mContext.getPackageName());
+ } 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.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public void flushGnssBatch() {
+ try {
+ mService.flushGnssBatch(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * 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
+ *
+ * @return True if batching was successfully started
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public boolean unregisterGnssBatchedLocationCallback(BatchedLocationCallback callback) {
+
+ mBatchedLocationCallbackTransport.remove(callback);
+
+ try {
+ return mService.stopGnssBatch();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sends additional commands to a location provider.
* Can be used to support provider specific extensions to the Location Manager API
*
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index dc8264a81427..ce58a9c4b91e 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -306,12 +306,26 @@ public final class AudioAttributes implements Parcelable {
* until there are no glitches.
* This tuning step should be done while playing silence.
* This technique provides a compromise between latency and glitch rate.
+ *
+ * @deprecated Use {@link AudioTrack.Builder#setPerformanceMode(int)} with
+ * {@link AudioTrack#PERFORMANCE_MODE_LOW_LATENCY} to control performance.
*/
public final static int FLAG_LOW_LATENCY = 0x1 << 8;
+ /**
+ * @hide
+ * Flag requesting a deep buffer path when creating an {@code AudioTrack}.
+ *
+ * A deep buffer path, if available, may consume less power and is
+ * suitable for media playback where latency is not a concern.
+ * Use {@link AudioTrack.Builder#setPerformanceMode(int)} with
+ * {@link AudioTrack#PERFORMANCE_MODE_POWER_SAVING} to enable.
+ */
+ public final static int FLAG_DEEP_BUFFER = 0x1 << 9;
+
private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
- FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY;
+ FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER;
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
@@ -541,6 +555,8 @@ public final class AudioAttributes implements Parcelable {
/**
* Sets the combination of flags.
+ *
+ * This is a bitwise OR with the existing flags.
* @param flags a combination of {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED},
* {@link AudioAttributes#FLAG_HW_AV_SYNC}.
* @return the same Builder instance.
@@ -553,6 +569,17 @@ public final class AudioAttributes implements Parcelable {
/**
* @hide
+ * Replaces flags.
+ * @param flags any combination of {@link AudioAttributes#FLAG_ALL}.
+ * @return the same Builder instance.
+ */
+ public Builder replaceFlags(int flags) {
+ mFlags = flags & AudioAttributes.FLAG_ALL;
+ return this;
+ }
+
+ /**
+ * @hide
* Adds a Bundle of data
* @param bundle a non-null Bundle
* @return the same builder instance
@@ -886,13 +913,13 @@ public final class AudioAttributes implements Parcelable {
}
}
/**
- * @hide
- * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
* Returns the stream type matching the given attributes for volume control.
* Use this method to derive the stream type needed to configure the volume
- * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
+ * control slider in an {@link android.app.Activity} with
+ * {@link android.app.Activity#setVolumeControlStream(int)}.
* <BR>Do not use this method to set the stream type on an audio player object
- * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
+ * (e.g. {@link AudioTrack}, {@link MediaPlayer}) as this is deprecated,
+ * use <code>AudioAttributes</code> instead.
* @param aa non-null AudioAttributes.
* @return a valid stream type for <code>Activity</code> or stream volume control that matches
* the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index 540c328f834b..60dbe00dcbe0 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -29,9 +29,10 @@ import java.util.Objects;
@SystemApi
public final class AudioFocusInfo implements Parcelable {
- private AudioAttributes mAttributes;
- private String mClientId;
- private String mPackageName;
+ private final AudioAttributes mAttributes;
+ private final int mClientUid;
+ private final String mClientId;
+ private final String mPackageName;
private int mGainRequest;
private int mLossReceived;
private int mFlags;
@@ -47,9 +48,10 @@ public final class AudioFocusInfo implements Parcelable {
* @param flags
* @hide
*/
- public AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
+ public AudioFocusInfo(AudioAttributes aa, int clientUid, String clientId, String packageName,
int gainRequest, int lossReceived, int flags) {
mAttributes = aa == null ? new AudioAttributes.Builder().build() : aa;
+ mClientUid = clientUid;
mClientId = clientId == null ? "" : clientId;
mPackageName = packageName == null ? "" : packageName;
mGainRequest = gainRequest;
@@ -66,6 +68,9 @@ public final class AudioFocusInfo implements Parcelable {
public AudioAttributes getAttributes() { return mAttributes; }
@SystemApi
+ public int getClientUid() { return mClientUid; }
+
+ @SystemApi
public String getClientId() { return mClientId; }
@SystemApi
@@ -111,6 +116,7 @@ public final class AudioFocusInfo implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
mAttributes.writeToParcel(dest, flags);
+ dest.writeInt(mClientUid);
dest.writeString(mClientId);
dest.writeString(mPackageName);
dest.writeInt(mGainRequest);
@@ -121,7 +127,7 @@ public final class AudioFocusInfo implements Parcelable {
@SystemApi
@Override
public int hashCode() {
- return Objects.hash(mAttributes, mClientId, mPackageName, mGainRequest, mFlags);
+ return Objects.hash(mAttributes, mClientUid, mClientId, mPackageName, mGainRequest, mFlags);
}
@SystemApi
@@ -137,6 +143,9 @@ public final class AudioFocusInfo implements Parcelable {
if (!mAttributes.equals(other.mAttributes)) {
return false;
}
+ if (mClientUid != other.mClientUid) {
+ return false;
+ }
if (!mClientId.equals(other.mClientId)) {
return false;
}
@@ -161,6 +170,7 @@ public final class AudioFocusInfo implements Parcelable {
public AudioFocusInfo createFromParcel(Parcel in) {
return new AudioFocusInfo(
AudioAttributes.CREATOR.createFromParcel(in), //AudioAttributes aa
+ in.readInt(), // int clientUid
in.readString(), //String clientId
in.readString(), //String packageName
in.readInt(), //int gainRequest
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7c603853a3ba..fb3f5b38959b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -730,61 +730,6 @@ public class AudioManager {
}
/**
- * @hide
- */
- public void handleKeyDown(KeyEvent event, int stream) {
- int keyCode = event.getKeyCode();
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- /*
- * Adjust the volume in on key down since it is more
- * responsive to the user.
- */
- adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? ADJUST_RAISE
- : ADJUST_LOWER,
- stream,
- FLAG_SHOW_UI | FLAG_VIBRATE);
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- if (event.getRepeatCount() == 0) {
- MediaSessionLegacyHelper.getHelper(getContext())
- .sendVolumeKeyEvent(event, false);
- }
- break;
- }
- }
-
- /**
- * @hide
- */
- public void handleKeyUp(KeyEvent event, int stream) {
- int keyCode = event.getKeyCode();
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- /*
- * Play a sound. This is done on key up since we don't want the
- * sound to play when a user holds down volume down to mute.
- */
- if (mUseVolumeKeySounds) {
- adjustSuggestedStreamVolume(
- ADJUST_SAME,
- stream,
- FLAG_PLAY_SOUND);
- }
- mVolumeKeyUpTime = SystemClock.uptimeMillis();
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- MediaSessionLegacyHelper.getHelper(getContext())
- .sendVolumeKeyEvent(event, false);
- break;
- }
- }
-
- /**
* Indicates if the device implements a fixed volume policy.
* <p>Some devices may not have volume control and may operate at a fixed volume,
* and may not enable muting or changing the volume of audio streams.
@@ -2485,6 +2430,23 @@ public class AudioManager {
/**
* @hide
+ * Return the volume ramping time for a sound to be played after the given focus request,
+ * and to play a sound of the given attributes
+ * @param focusGain
+ * @param attr
+ * @return
+ */
+ public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
+ IAudioService service = getService();
+ try {
+ return service.getFocusRampTimeMs(focusGain, attr);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
* Used internally by telephony package to abandon audio focus, typically after a call or
* when ringing ends and the call is rejected or not answered.
* Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
@@ -4129,7 +4091,9 @@ public class AudioManager {
* currently connected to the system and meeting the criteria specified in the
* <code>flags</code> parameter.
* @param flags A set of bitflags specifying the criteria to test.
- * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}.
+ * @see #GET_DEVICES_OUTPUTS
+ * @see #GET_DEVICES_INPUTS
+ * @see #GET_DEVICES_ALL
* @return A (possibly zero-length) array of AudioDeviceInfo objects.
*/
public AudioDeviceInfo[] getDevices(int flags) {
@@ -4200,7 +4164,9 @@ public class AudioManager {
* parameter.
* This is an internal function. The public API front is getDevices(int).
* @param flags A set of bitflags specifying the criteria to test.
- * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}.
+ * @see #GET_DEVICES_OUTPUTS
+ * @see #GET_DEVICES_INPUTS
+ * @see #GET_DEVICES_ALL
* @return A (possibly zero-length) array of AudioDeviceInfo objects.
* @hide
*/
@@ -4246,7 +4212,7 @@ public class AudioManager {
* Unregisters an {@link AudioDeviceCallback} object which has been previously registered
* to receive notifications of changes to the set of connected audio devices.
* @param callback The {@link AudioDeviceCallback} object that was previously registered
- * with {@link AudioManager#registerAudioDeviceCallback) to be unregistered.
+ * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
*/
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
synchronized (mDeviceCallbacks) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 031ac0667c64..9083c1630cca 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
import android.os.Handler;
@@ -214,6 +215,66 @@ public class AudioTrack extends PlayerBase
*/
public final static int WRITE_NON_BLOCKING = 1;
+ /** @hide */
+ @IntDef({
+ PERFORMANCE_MODE_NONE,
+ PERFORMANCE_MODE_LOW_LATENCY,
+ PERFORMANCE_MODE_POWER_SAVING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PerformanceMode {}
+
+ /**
+ * Default performance mode for an {@link AudioTrack}.
+ */
+ public static final int PERFORMANCE_MODE_NONE = 0;
+
+ /**
+ * Low latency performance mode for an {@link AudioTrack}.
+ * If the device supports it, this mode
+ * enables a lower latency path through to the audio output sink.
+ * Effects may no longer work with such an {@code AudioTrack} and
+ * the sample rate must match that of the output sink.
+ * <p>
+ * Applications should be aware that low latency requires careful
+ * buffer management, with smaller chunks of audio data written by each
+ * {@code write()} call.
+ * <p>
+ * If this flag is used without specifying a {@code bufferSizeInBytes} then the
+ * {@code AudioTrack}'s actual buffer size may be too small.
+ * It is recommended that a fairly
+ * large buffer should be specified when the {@code AudioTrack} is created.
+ * Then the actual size can be reduced by calling
+ * {@link #setBufferSizeInFrames(int)}. The buffer size can be optimized
+ * by lowering it after each {@code write()} call until the audio glitches,
+ * which is detected by calling
+ * {@link #getUnderrunCount()}. Then the buffer size can be increased
+ * until there are no glitches.
+ * This tuning step should be done while playing silence.
+ * This technique provides a compromise between latency and glitch rate.
+ */
+ public static final int PERFORMANCE_MODE_LOW_LATENCY = 1;
+
+ /**
+ * Power saving performance mode for an {@link AudioTrack}.
+ * If the device supports it, this
+ * mode will enable a lower power path to the audio output sink.
+ * In addition, this lower power path typically will have
+ * deeper internal buffers and better underrun resistance,
+ * with a tradeoff of higher latency.
+ * <p>
+ * In this mode, applications should attempt to use a larger buffer size
+ * and deliver larger chunks of audio data per {@code write()} call.
+ * Use {@link #getBufferSizeInFrames()} to determine
+ * the actual buffer size of the {@code AudioTrack} as it may have increased
+ * to accommodate a deeper buffer.
+ */
+ public static final int PERFORMANCE_MODE_POWER_SAVING = 2;
+
+ // keep in sync with system/media/audio/include/system/audio-base.h
+ private static final int AUDIO_OUTPUT_FLAG_FAST = 0x4;
+ private static final int AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8;
+
//--------------------------------------------------------------------------
// Member variables
//--------------------
@@ -478,6 +539,15 @@ public class AudioTrack extends PlayerBase
throw new IllegalArgumentException("Illegal null AudioFormat");
}
+ // Check if we should enable deep buffer mode
+ if (shouldEnablePowerSaving(mAttributes, format, bufferSizeInBytes, mode)) {
+ mAttributes = new AudioAttributes.Builder(mAttributes)
+ .replaceFlags((mAttributes.getAllFlags()
+ | AudioAttributes.FLAG_DEEP_BUFFER)
+ & ~AudioAttributes.FLAG_LOW_LATENCY)
+ .build();
+ }
+
// remember which looper is associated with the AudioTrack instantiation
Looper looper;
if ((looper = Looper.myLooper()) == null) {
@@ -648,6 +718,7 @@ public class AudioTrack extends PlayerBase
private int mBufferSizeInBytes;
private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
private int mMode = MODE_STREAM;
+ private int mPerformanceMode = PERFORMANCE_MODE_NONE;
/**
* Constructs a new Builder with the default values as described above.
@@ -752,6 +823,32 @@ public class AudioTrack extends PlayerBase
}
/**
+ * Sets the {@link AudioTrack} performance mode. This is an advisory request which
+ * may not be supported by the particular device, and the framework is free
+ * to ignore such request if it is incompatible with other requests or hardware.
+ *
+ * @param performanceMode one of
+ * {@link AudioTrack#PERFORMANCE_MODE_NONE},
+ * {@link AudioTrack#PERFORMANCE_MODE_LOW_LATENCY},
+ * or {@link AudioTrack#PERFORMANCE_MODE_POWER_SAVING}.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException if {@code performanceMode} is not valid.
+ */
+ public @NonNull Builder setPerformanceMode(@PerformanceMode int performanceMode) {
+ switch (performanceMode) {
+ case PERFORMANCE_MODE_NONE:
+ case PERFORMANCE_MODE_LOW_LATENCY:
+ case PERFORMANCE_MODE_POWER_SAVING:
+ mPerformanceMode = performanceMode;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid performance mode " + performanceMode);
+ }
+ return this;
+ }
+
+ /**
* Builds an {@link AudioTrack} instance initialized with all the parameters set
* on this <code>Builder</code>.
* @return a new successfully initialized {@link AudioTrack} instance.
@@ -765,6 +862,28 @@ public class AudioTrack extends PlayerBase
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
}
+ switch (mPerformanceMode) {
+ case PERFORMANCE_MODE_LOW_LATENCY:
+ mAttributes = new AudioAttributes.Builder(mAttributes)
+ .replaceFlags((mAttributes.getAllFlags()
+ | AudioAttributes.FLAG_LOW_LATENCY)
+ & ~AudioAttributes.FLAG_DEEP_BUFFER)
+ .build();
+ break;
+ case PERFORMANCE_MODE_NONE:
+ if (!shouldEnablePowerSaving(mAttributes, mFormat, mBufferSizeInBytes, mMode)) {
+ break; // do not enable deep buffer mode.
+ }
+ // permitted to fall through to enable deep buffer
+ case PERFORMANCE_MODE_POWER_SAVING:
+ mAttributes = new AudioAttributes.Builder(mAttributes)
+ .replaceFlags((mAttributes.getAllFlags()
+ | AudioAttributes.FLAG_DEEP_BUFFER)
+ & ~AudioAttributes.FLAG_LOW_LATENCY)
+ .build();
+ break;
+ }
+
if (mFormat == null) {
mFormat = new AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
@@ -806,6 +925,56 @@ public class AudioTrack extends PlayerBase
AudioFormat.CHANNEL_OUT_SIDE_LEFT |
AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
+ // Returns a boolean whether the attributes, format, bufferSizeInBytes, mode allow
+ // power saving to be automatically enabled for an AudioTrack. Returns false if
+ // power saving is already enabled in the attributes parameter.
+ private static boolean shouldEnablePowerSaving(
+ @Nullable AudioAttributes attributes, @Nullable AudioFormat format,
+ int bufferSizeInBytes, int mode) {
+ // If no attributes, OK
+ // otherwise check attributes for USAGE_MEDIA and CONTENT_UNKNOWN, MUSIC, or MOVIE.
+ if (attributes != null &&
+ (attributes.getAllFlags() != 0 // cannot have any special flags
+ || attributes.getUsage() != AudioAttributes.USAGE_MEDIA
+ || (attributes.getContentType() != AudioAttributes.CONTENT_TYPE_UNKNOWN
+ && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MUSIC
+ && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MOVIE))) {
+ return false;
+ }
+
+ // Format must be fully specified and be linear pcm
+ if (format == null
+ || format.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
+ || !AudioFormat.isEncodingLinearPcm(format.getEncoding())
+ || !AudioFormat.isValidEncoding(format.getEncoding())
+ || format.getChannelCount() < 1) {
+ return false;
+ }
+
+ // Mode must be streaming
+ if (mode != MODE_STREAM) {
+ return false;
+ }
+
+ // A buffer size of 0 is always compatible with deep buffer (when called from the Builder)
+ // but for app compatibility we only use deep buffer power saving for large buffer sizes.
+ if (bufferSizeInBytes != 0) {
+ final long BUFFER_TARGET_MODE_STREAM_MS = 100;
+ final int MILLIS_PER_SECOND = 1000;
+ final long bufferTargetSize =
+ BUFFER_TARGET_MODE_STREAM_MS
+ * format.getChannelCount()
+ * format.getBytesPerSample(format.getEncoding())
+ * format.getSampleRate()
+ / MILLIS_PER_SECOND;
+ if (bufferSizeInBytes < bufferTargetSize) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// Convenience method for the constructor's parameter checks.
// This is where constructor IllegalArgumentException-s are thrown
// postconditions:
@@ -1278,6 +1447,27 @@ public class AudioTrack extends PlayerBase
}
/**
+ * Returns the current performance mode of the {@link AudioTrack}.
+ *
+ * @return one of {@link AudioTrack#PERFORMANCE_MODE_NONE},
+ * {@link AudioTrack#PERFORMANCE_MODE_LOW_LATENCY},
+ * or {@link AudioTrack#PERFORMANCE_MODE_POWER_SAVING}.
+ * Use {@link AudioTrack.Builder#setPerformanceMode}
+ * in the {@link AudioTrack.Builder} to enable a performance mode.
+ * @throws IllegalStateException if track is not initialized.
+ */
+ public @PerformanceMode int getPerformanceMode() {
+ final int flags = native_get_flags();
+ if ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+ return PERFORMANCE_MODE_LOW_LATENCY;
+ } else if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+ return PERFORMANCE_MODE_POWER_SAVING;
+ } else {
+ return PERFORMANCE_MODE_NONE;
+ }
+ }
+
+ /**
* Returns the output sample rate in Hz for the specified stream type.
*/
static public int getNativeOutputSampleRate(int streamType) {
@@ -1753,6 +1943,32 @@ public class AudioTrack extends PlayerBase
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("play() called on uninitialized AudioTrack.");
}
+ //FIXME use lambda to pass startImpl to superclass
+ final int delay = getStartDelayMs();
+ if (delay == 0) {
+ startImpl();
+ } else {
+ new Thread() {
+ public void run() {
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ baseSetStartDelayMs(0);
+ try {
+ startImpl();
+ } catch (IllegalStateException e) {
+ // fail silently for a state exception when it is happening after
+ // a delayed start, as the player state could have changed between the
+ // call to start() and the execution of startImpl()
+ }
+ }
+ }.start();
+ }
+ }
+
+ private void startImpl() {
synchronized(mPlayStateLock) {
baseStart();
native_start();
@@ -2855,6 +3071,8 @@ public class AudioTrack extends PlayerBase
private native final int native_get_underrun_count();
+ private native final int native_get_flags();
+
// longArray must be a non-null array of length >= 2
// [0] is assigned the frame position
// [1] is assigned the time in CLOCK_MONOTONIC nanoseconds
diff --git a/media/java/android/media/BufferingParams.aidl b/media/java/android/media/BufferingParams.aidl
new file mode 100644
index 000000000000..d156d44cd7df
--- /dev/null
+++ b/media/java/android/media/BufferingParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable BufferingParams;
diff --git a/media/java/android/media/BufferingParams.java b/media/java/android/media/BufferingParams.java
new file mode 100644
index 000000000000..fdcd6baa7d18
--- /dev/null
+++ b/media/java/android/media/BufferingParams.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Structure for source buffering management params.
+ *
+ * Used by {@link MediaPlayer#getDefaultBufferingParams()},
+ * {@link MediaPlayer#getBufferingParams()} and
+ * {@link MediaPlayer#setBufferingParams(BufferingParams)}
+ * to control source buffering behavior.
+ *
+ * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering
+ * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer}
+ * is playing back source). {@link BufferingParams} includes mode and corresponding
+ * watermarks for each stage of source buffering. The watermarks could be either size
+ * based (in milliseconds), or time based (in kilobytes) or both, depending on the mode.
+ *
+ * <p>There are 4 buffering modes: {@link #BUFFERING_MODE_NONE},
+ * {@link #BUFFERING_MODE_TIME_ONLY}, {@link #BUFFERING_MODE_SIZE_ONLY} and
+ * {@link #BUFFERING_MODE_TIME_THEN_SIZE}.
+ * {@link MediaPlayer} source component has default buffering modes which can be queried
+ * by calling {@link MediaPlayer#getDefaultBufferingParams()}.
+ * Users should always use those default modes or their downsized version when trying to
+ * change buffering params. For example, {@link #BUFFERING_MODE_TIME_THEN_SIZE} can be
+ * downsized to {@link #BUFFERING_MODE_NONE}, {@link #BUFFERING_MODE_TIME_ONLY} or
+ * {@link #BUFFERING_MODE_SIZE_ONLY}. But {@link #BUFFERING_MODE_TIME_ONLY} can not be
+ * downsized to {@link #BUFFERING_MODE_SIZE_ONLY}.
+ * <ul>
+ * <li><strong>initial buffering stage:</strong> has one watermark which is used when
+ * {@link MediaPlayer} is being prepared. When cached data amount exceeds this watermark,
+ * {@link MediaPlayer} is prepared.</li>
+ * <li><strong>rebuffering stage:</strong> has two watermarks, low and high, which are
+ * used when {@link MediaPlayer} is playing back content.
+ * <ul>
+ * <li> When cached data amount exceeds high watermark, {@link MediaPlayer} will pause
+ * buffering. Buffering will resume when cache runs below some limit which could be low
+ * watermark or some intermediate value decided by the source component.</li>
+ * <li> When cached data amount runs below low watermark, {@link MediaPlayer} will paused
+ * playback. Playback will resume when cached data amount exceeds high watermark
+ * or reaches end of stream.</li>
+ * </ul>
+ * </ul>
+ * <p>Users should use {@link Builder} to change {@link BufferingParams}.
+ */
+public final class BufferingParams implements Parcelable {
+ /**
+ * This mode indicates that source buffering is not supported.
+ */
+ public static final int BUFFERING_MODE_NONE = 0;
+ /**
+ * This mode indicates that only time based source buffering is supported. This means
+ * the watermark(s) are time based.
+ */
+ public static final int BUFFERING_MODE_TIME_ONLY = 1;
+ /**
+ * This mode indicates that only size based source buffering is supported. This means
+ * the watermark(s) are size based.
+ */
+ public static final int BUFFERING_MODE_SIZE_ONLY = 2;
+ /**
+ * This mode indicates that both time and size based source buffering are supported,
+ * and time based calculation precedes size based. Size based calculation will be used
+ * only when time information is not available from the source.
+ */
+ public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3;
+
+ /** @hide */
+ @IntDef(
+ value = {
+ BUFFERING_MODE_NONE,
+ BUFFERING_MODE_TIME_ONLY,
+ BUFFERING_MODE_SIZE_ONLY,
+ BUFFERING_MODE_TIME_THEN_SIZE,
+ }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BufferingMode {}
+
+ private static final int BUFFERING_NO_WATERMARK = -1;
+
+ // params
+ private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+ private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+ private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+ private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+ private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+ private BufferingParams() {
+ }
+
+ /**
+ * Return the initial buffering mode used when {@link MediaPlayer} is being prepared.
+ * @return one of the values that can be set in {@link Builder#setInitialBufferingMode(int)}
+ */
+ public int getInitialBufferingMode() {
+ return mInitialBufferingMode;
+ }
+
+ /**
+ * Return the rebuffering mode used when {@link MediaPlayer} is playing back source.
+ * @return one of the values that can be set in {@link Builder#setRebufferingMode(int)}
+ */
+ public int getRebufferingMode() {
+ return mRebufferingMode;
+ }
+
+ /**
+ * Return the time based initial buffering watermark in milliseconds.
+ * It is meaningful only when initial buffering mode obatined from
+ * {@link #getInitialBufferingMode()} is time based.
+ * @return time based initial buffering watermark in milliseconds
+ */
+ public int getInitialBufferingWatermarkMs() {
+ return mInitialWatermarkMs;
+ }
+
+ /**
+ * Return the size based initial buffering watermark in kilobytes.
+ * It is meaningful only when initial buffering mode obatined from
+ * {@link #getInitialBufferingMode()} is size based.
+ * @return size based initial buffering watermark in kilobytes
+ */
+ public int getInitialBufferingWatermarkKB() {
+ return mInitialWatermarkKB;
+ }
+
+ /**
+ * Return the time based low watermark in milliseconds for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is time based.
+ * @return time based low watermark for rebuffering in milliseconds
+ */
+ public int getRebufferingWatermarkLowMs() {
+ return mRebufferingWatermarkLowMs;
+ }
+
+ /**
+ * Return the time based high watermark in milliseconds for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is time based.
+ * @return time based high watermark for rebuffering in milliseconds
+ */
+ public int getRebufferingWatermarkHighMs() {
+ return mRebufferingWatermarkHighMs;
+ }
+
+ /**
+ * Return the size based low watermark in kilobytes for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is size based.
+ * @return size based low watermark for rebuffering in kilobytes
+ */
+ public int getRebufferingWatermarkLowKB() {
+ return mRebufferingWatermarkLowKB;
+ }
+
+ /**
+ * Return the size based high watermark in kilobytes for rebuffering.
+ * It is meaningful only when rebuffering mode obatined from
+ * {@link #getRebufferingMode()} is size based.
+ * @return size based high watermark for rebuffering in kilobytes
+ */
+ public int getRebufferingWatermarkHighKB() {
+ return mRebufferingWatermarkHighKB;
+ }
+
+ /**
+ * Builder class for {@link BufferingParams} objects.
+ * <p> Here is an example where <code>Builder</code> is used to define the
+ * {@link BufferingParams} to be used by a {@link MediaPlayer} instance:
+ *
+ * <pre class="prettyprint">
+ * BufferingParams myParams = mediaplayer.getDefaultBufferingParams();
+ * myParams = new BufferingParams.Builder(myParams)
+ * .setInitialBufferingWatermarkMs(10000)
+ * .build();
+ * mediaplayer.setBufferingParams(myParams);
+ * </pre>
+ */
+ public static class Builder {
+ private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+ private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+ private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+ private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+ private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+ private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+ /**
+ * Constructs a new Builder with the defaults.
+ * By default, both initial buffering mode and rebuffering mode are
+ * {@link BufferingParams#BUFFERING_MODE_NONE}, and all watermarks are -1.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link BufferingParams} instance
+ * @param bp the {@link BufferingParams} object whose data will be reused
+ * in the new Builder.
+ */
+ public Builder(BufferingParams bp) {
+ mInitialBufferingMode = bp.mInitialBufferingMode;
+ mRebufferingMode = bp.mRebufferingMode;
+
+ mInitialWatermarkMs = bp.mInitialWatermarkMs;
+ mInitialWatermarkKB = bp.mInitialWatermarkKB;
+
+ mRebufferingWatermarkLowMs = bp.mRebufferingWatermarkLowMs;
+ mRebufferingWatermarkHighMs = bp.mRebufferingWatermarkHighMs;
+ mRebufferingWatermarkLowKB = bp.mRebufferingWatermarkLowKB;
+ mRebufferingWatermarkHighKB = bp.mRebufferingWatermarkHighKB;
+ }
+
+ /**
+ * Combines all of the fields that have been set and return a new
+ * {@link BufferingParams} object. <code>IllegalStateException</code> will be
+ * thrown if there is conflict between fields.
+ * @return a new {@link BufferingParams} object
+ */
+ public BufferingParams build() {
+ if (isTimeBasedMode(mRebufferingMode)
+ && mRebufferingWatermarkLowMs > mRebufferingWatermarkHighMs) {
+ throw new IllegalStateException("Illegal watermark:"
+ + mRebufferingWatermarkLowMs + " : " + mRebufferingWatermarkHighMs);
+ }
+ if (isSizeBasedMode(mRebufferingMode)
+ && mRebufferingWatermarkLowKB > mRebufferingWatermarkHighKB) {
+ throw new IllegalStateException("Illegal watermark:"
+ + mRebufferingWatermarkLowKB + " : " + mRebufferingWatermarkHighKB);
+ }
+
+ BufferingParams bp = new BufferingParams();
+ bp.mInitialBufferingMode = mInitialBufferingMode;
+ bp.mRebufferingMode = mRebufferingMode;
+
+ bp.mInitialWatermarkMs = mInitialWatermarkMs;
+ bp.mInitialWatermarkKB = mInitialWatermarkKB;
+
+ bp.mRebufferingWatermarkLowMs = mRebufferingWatermarkLowMs;
+ bp.mRebufferingWatermarkHighMs = mRebufferingWatermarkHighMs;
+ bp.mRebufferingWatermarkLowKB = mRebufferingWatermarkLowKB;
+ bp.mRebufferingWatermarkHighKB = mRebufferingWatermarkHighKB;
+ return bp;
+ }
+
+ private boolean isTimeBasedMode(int mode) {
+ return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+ }
+
+ private boolean isSizeBasedMode(int mode) {
+ return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+ }
+
+ /**
+ * Sets the initial buffering mode.
+ * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingMode(@BufferingMode int mode) {
+ switch (mode) {
+ case BUFFERING_MODE_NONE:
+ case BUFFERING_MODE_TIME_ONLY:
+ case BUFFERING_MODE_SIZE_ONLY:
+ case BUFFERING_MODE_TIME_THEN_SIZE:
+ mInitialBufferingMode = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal buffering mode " + mode);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the rebuffering mode.
+ * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+ * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingMode(@BufferingMode int mode) {
+ switch (mode) {
+ case BUFFERING_MODE_NONE:
+ case BUFFERING_MODE_TIME_ONLY:
+ case BUFFERING_MODE_SIZE_ONLY:
+ case BUFFERING_MODE_TIME_THEN_SIZE:
+ mRebufferingMode = mode;
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal buffering mode " + mode);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the time based watermark in milliseconds for initial buffering.
+ * @param watermarkMs time based watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingWatermarkMs(int watermarkMs) {
+ mInitialWatermarkMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based watermark in kilobytes for initial buffering.
+ * @param watermarkKB size based watermark in kilobytes
+ * @return the same Builder instance.
+ */
+ public Builder setInitialBufferingWatermarkKB(int watermarkKB) {
+ mInitialWatermarkKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the time based low watermark in milliseconds for rebuffering.
+ * @param watermarkMs time based low watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkLowMs(int watermarkMs) {
+ mRebufferingWatermarkLowMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the time based high watermark in milliseconds for rebuffering.
+ * @param watermarkMs time based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkHighMs(int watermarkMs) {
+ mRebufferingWatermarkHighMs = watermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based low watermark in milliseconds for rebuffering.
+ * @param watermarkKB size based low watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkLowKB(int watermarkKB) {
+ mRebufferingWatermarkLowKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the size based high watermark in milliseconds for rebuffering.
+ * @param watermarkKB size based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarkHighKB(int watermarkKB) {
+ mRebufferingWatermarkHighKB = watermarkKB;
+ return this;
+ }
+
+ /**
+ * Sets the time based low and high watermarks in milliseconds for rebuffering.
+ * @param lowWatermarkMs time based low watermark in milliseconds
+ * @param highWatermarkMs time based high watermark in milliseconds
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarksMs(int lowWatermarkMs, int highWatermarkMs) {
+ mRebufferingWatermarkLowMs = lowWatermarkMs;
+ mRebufferingWatermarkHighMs = highWatermarkMs;
+ return this;
+ }
+
+ /**
+ * Sets the size based low and high watermarks in kilobytes for rebuffering.
+ * @param lowWatermarkKB size based low watermark in kilobytes
+ * @param highWatermarkKB size based high watermark in kilobytes
+ * @return the same Builder instance.
+ */
+ public Builder setRebufferingWatermarksKB(int lowWatermarkKB, int highWatermarkKB) {
+ mRebufferingWatermarkLowKB = lowWatermarkKB;
+ mRebufferingWatermarkHighKB = highWatermarkKB;
+ return this;
+ }
+ }
+
+ private BufferingParams(Parcel in) {
+ mInitialBufferingMode = in.readInt();
+ mRebufferingMode = in.readInt();
+
+ mInitialWatermarkMs = in.readInt();
+ mInitialWatermarkKB = in.readInt();
+
+ mRebufferingWatermarkLowMs = in.readInt();
+ mRebufferingWatermarkHighMs = in.readInt();
+ mRebufferingWatermarkLowKB = in.readInt();
+ mRebufferingWatermarkHighKB = in.readInt();
+ }
+
+ public static final Parcelable.Creator<BufferingParams> CREATOR =
+ new Parcelable.Creator<BufferingParams>() {
+ @Override
+ public BufferingParams createFromParcel(Parcel in) {
+ return new BufferingParams(in);
+ }
+
+ @Override
+ public BufferingParams[] newArray(int size) {
+ return new BufferingParams[size];
+ }
+ };
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mInitialBufferingMode);
+ dest.writeInt(mRebufferingMode);
+
+ dest.writeInt(mInitialWatermarkMs);
+ dest.writeInt(mInitialWatermarkKB);
+
+ dest.writeInt(mRebufferingWatermarkLowMs);
+ dest.writeInt(mRebufferingWatermarkHighMs);
+ dest.writeInt(mRebufferingWatermarkLowKB);
+ dest.writeInt(mRebufferingWatermarkHighKB);
+ }
+}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 52d5b7ca9188..71f779073703 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1597,8 +1597,8 @@ public class ExifInterface {
final Rational[] rationalArray = new Rational[values.length];
for (int j = 0; j < values.length; ++j) {
final String[] numbers = values[j].split("/");
- rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
- Long.parseLong(numbers[1]));
+ rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
+ (long) Double.parseDouble(numbers[1]));
}
mAttributes[i].put(tag,
ExifAttribute.createURational(rationalArray, mExifByteOrder));
@@ -1609,8 +1609,8 @@ public class ExifInterface {
final Rational[] rationalArray = new Rational[values.length];
for (int j = 0; j < values.length; ++j) {
final String[] numbers = values[j].split("/");
- rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
- Long.parseLong(numbers[1]));
+ rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
+ (long) Double.parseDouble(numbers[1]));
}
mAttributes[i].put(tag,
ExifAttribute.createSRational(rationalArray, mExifByteOrder));
@@ -3442,8 +3442,8 @@ public class ExifInterface {
String[] rationalNumber = entryValue.split("/");
if (rationalNumber.length == 2) {
try {
- long numerator = Long.parseLong(rationalNumber[0]);
- long denominator = Long.parseLong(rationalNumber[1]);
+ long numerator = (long) Double.parseDouble(rationalNumber[0]);
+ long denominator = (long) Double.parseDouble(rationalNumber[1]);
if (numerator < 0L || denominator < 0L) {
return new Pair<>(IFD_FORMAT_SRATIONAL, -1);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index a76a328e2274..fa4796a15134 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -194,5 +194,7 @@ interface IAudioService {
void disableRingtoneSync();
+ int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
+
// WARNING: read warning at top of file, it is recommended to add new methods at the end
}
diff --git a/media/java/android/media/IPlayer.aidl b/media/java/android/media/IPlayer.aidl
index ccb60f7fd843..f068a0a1b945 100644
--- a/media/java/android/media/IPlayer.aidl
+++ b/media/java/android/media/IPlayer.aidl
@@ -25,4 +25,6 @@ interface IPlayer {
oneway void pause();
oneway void stop();
oneway void setVolume(float vol);
+ oneway void setPan(float pan);
+ oneway void setStartDelayMs(int delayMs);
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 264944f43bae..75ccffee6f09 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3134,6 +3134,15 @@ final public class MediaCodec {
public native final String getName();
/**
+ * Returns Analytics/Metrics data about the current content being
+ *
+ * @return a Bundle containint the set of attributes and values available
+ * for the media being handled by this instance of MediaCodec
+ *
+ */
+ public native Bundle getMetrics();
+
+ /**
* Change a video encoder's target bitrate on the fly. The value is an
* Integer object containing the new bitrate in bps.
*/
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 2650ee0ee3b3..2723826cc92e 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.annotation.SystemApi;
+import android.app.ActivityThread;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -213,7 +214,7 @@ public final class MediaDrm {
* It's easier to create it here than in C++.
*/
native_setup(new WeakReference<MediaDrm>(this),
- getByteArrayFromUUID(uuid));
+ getByteArrayFromUUID(uuid), ActivityThread.currentOpPackageName());
}
/**
@@ -1307,7 +1308,8 @@ public final class MediaDrm {
public native final void release();
private static native final void native_init();
- private native final void native_setup(Object mediadrm_this, byte[] uuid);
+ private native final void native_setup(Object mediadrm_this, byte[] uuid,
+ String appPackageName);
private native final void native_finalize();
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index e481aa141d6b..80832f8a2977 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -83,19 +83,24 @@ final public class MediaMuxer {
private OutputFormat() {}
/** MPEG4 media file format*/
public static final int MUXER_OUTPUT_MPEG_4 = 0;
+ /** WEBM media file format*/
public static final int MUXER_OUTPUT_WEBM = 1;
+ /** 3GPP media file format*/
+ public static final int MUXER_OUTPUT_3GPP = 2;
};
/** @hide */
@IntDef({
OutputFormat.MUXER_OUTPUT_MPEG_4,
OutputFormat.MUXER_OUTPUT_WEBM,
+ OutputFormat.MUXER_OUTPUT_3GPP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Format {}
// All the native functions are listed here.
- private static native long nativeSetup(@NonNull FileDescriptor fd, int format);
+ private static native long nativeSetup(@NonNull FileDescriptor fd, int format)
+ throws IllegalArgumentException, IOException;
private static native void nativeRelease(long nativeObject);
private static native void nativeStart(long nativeObject);
private static native void nativeStop(long nativeObject);
@@ -134,19 +139,13 @@ final public class MediaMuxer {
if (path == null) {
throw new IllegalArgumentException("path must not be null");
}
- if (format != OutputFormat.MUXER_OUTPUT_MPEG_4 &&
- format != OutputFormat.MUXER_OUTPUT_WEBM) {
- throw new IllegalArgumentException("format is invalid");
- }
// Use RandomAccessFile so we can open the file with RW access;
// RW access allows the native writer to memory map the output file.
RandomAccessFile file = null;
try {
file = new RandomAccessFile(path, "rws");
FileDescriptor fd = file.getFD();
- mNativeObject = nativeSetup(fd, format);
- mState = MUXER_STATE_INITIALIZED;
- mCloseGuard.open("release");
+ setUpMediaMuxer(fd, format);
} finally {
if (file != null) {
file.close();
@@ -155,6 +154,32 @@ final public class MediaMuxer {
}
/**
+ * Constructor.
+ * Creates a media muxer that writes to the specified FileDescriptor. File descriptor
+ * must be seekable and writable. Application should not use the file referenced
+ * by this file descriptor until {@link #stop}. It is the application's responsibility
+ * to close the file descriptor. It is safe to do so as soon as this call returns.
+ * @param fd The FileDescriptor of the output media file.
+ * @param format The format of the output media file.
+ * @see android.media.MediaMuxer.OutputFormat
+ * @throws IllegalArgumentException if fd is invalid or format is not supported.
+ * @throws IOException if failed to open the file for write.
+ */
+ public MediaMuxer(@NonNull FileDescriptor fd, @Format int format) throws IOException {
+ setUpMediaMuxer(fd, format);
+ }
+
+ private void setUpMediaMuxer(@NonNull FileDescriptor fd, @Format int format) throws IOException {
+ if (format != OutputFormat.MUXER_OUTPUT_MPEG_4 && format != OutputFormat.MUXER_OUTPUT_WEBM
+ && format != OutputFormat.MUXER_OUTPUT_3GPP) {
+ throw new IllegalArgumentException("format: " + format + " is invalid");
+ }
+ mNativeObject = nativeSetup(fd, format);
+ mState = MUXER_STATE_INITIALIZED;
+ mCloseGuard.open("release");
+ }
+
+ /**
* Sets the orientation hint for output video playback.
* <p>This method should be called before {@link #start}. Calling this
* method will not rotate the video frame when muxer is generating the file,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e3a0f25d5ccd..1a1d0f350696 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -25,6 +25,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -45,6 +46,8 @@ import android.view.SurfaceHolder;
import android.widget.VideoView;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
+import android.media.BufferingParams;
+import android.media.MediaDrm;
import android.media.MediaFormat;
import android.media.MediaTimeProvider;
import android.media.PlaybackParams;
@@ -58,6 +61,7 @@ import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
import libcore.io.Libcore;
+import libcore.io.Streams;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -68,13 +72,20 @@ import java.io.InputStream;
import java.lang.Runnable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.ByteOrder;
+import java.util.Arrays;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
+import java.util.UUID;
import java.util.Vector;
-import java.lang.ref.WeakReference;
+
/**
* MediaPlayer class can be used to control playback
@@ -479,6 +490,11 @@ import java.lang.ref.WeakReference;
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
+ * <tr><td>setBufferingParams</p></td>
+ * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}</p></td>
+ * <td>{Idle} </p></td>
+ * <td>This method does not change the object state.
+ * </p></td></tr>
* <tr><td>setPlaybackParams</p></td>
* <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
* <td>{Idle, Stopped} </p></td>
@@ -618,6 +634,17 @@ public class MediaPlayer extends PlayerBase
private int mUsage = -1;
private boolean mBypassInterruptionPolicy;
+ // Modular DRM
+ private UUID mDrmUUID;
+ private final Object mDrmLock = new Object();
+ private DrmInfo mDrmInfo;
+ private boolean mDrmInfoResolved;
+ private boolean mActiveDrmScheme;
+ private boolean mDrmConfigAllowed;
+ private boolean mDrmProvisioningInProgress;
+ private boolean mPrepareDrmInProgress;
+ private ProvisioningThread mDrmProvisioningThread;
+
/**
* Default constructor. Consider using one of the create() methods for
* synchronously instantiating a MediaPlayer from a Uri or resource.
@@ -1218,6 +1245,32 @@ public class MediaPlayer extends PlayerBase
* @throws IllegalStateException if it is called in an invalid state
*/
public void start() throws IllegalStateException {
+ //FIXME use lambda to pass startImpl to superclass
+ final int delay = getStartDelayMs();
+ if (delay == 0) {
+ startImpl();
+ } else {
+ new Thread() {
+ public void run() {
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ baseSetStartDelayMs(0);
+ try {
+ startImpl();
+ } catch (IllegalStateException e) {
+ // fail silently for a state exception when it is happening after
+ // a delayed start, as the player state could have changed between the
+ // call to start() and the execution of startImpl()
+ }
+ }
+ }.start();
+ }
+ }
+
+ private void startImpl() {
baseStart();
stayAwake(true);
_start();
@@ -1381,6 +1434,14 @@ public class MediaPlayer extends PlayerBase
public native int getVideoHeight();
/**
+ * Returns Analytics/Metrics data about the current video in this player.
+ *
+ * @return the a map of attributes and values available for this video
+ * player or null if no metrics are available.
+ */
+ public native Bundle getMetrics();
+
+ /**
* Checks whether the MediaPlayer is playing.
*
* @return true if currently playing, false otherwise
@@ -1390,6 +1451,45 @@ public class MediaPlayer extends PlayerBase
public native boolean isPlaying();
/**
+ * Gets the default buffering management params.
+ * Calling it only after {@code setDataSource} has been called.
+ * Each type of data source might have different set of default params.
+ *
+ * @return the default buffering management params supported by the source component.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized, or {@code setDataSource} has not been called.
+ */
+ @NonNull
+ public native BufferingParams getDefaultBufferingParams();
+
+ /**
+ * Gets the current buffering management params used by the source component.
+ * Calling it only after {@code setDataSource} has been called.
+ *
+ * @return the current buffering management params used by the source component.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized, or {@code setDataSource} has not been called.
+ */
+ @NonNull
+ public native BufferingParams getBufferingParams();
+
+ /**
+ * Sets buffering management params.
+ * The object sets its internal BufferingParams to the input, except that the input is
+ * invalid or not supported.
+ * Call it only after {@code setDataSource} has been called.
+ * Users should only use supported mode returned by {@link #getDefaultBufferingParams()}
+ * or its downsized version as described in {@link BufferingParams}.
+ *
+ * @param params the buffering management params.
+ *
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized or has been released, or {@code setDataSource} has not been called.
+ * @throws IllegalArgumentException if params is invalid or not supported.
+ */
+ public native void setBufferingParams(@NonNull BufferingParams params);
+
+ /**
* Change playback speed of audio by resampling the audio.
* <p>
* Specifies resampling as audio mode for variable rate playback, i.e.,
@@ -1812,6 +1912,12 @@ public class MediaPlayer extends PlayerBase
mTimeProvider = null;
}
mOnSubtitleDataListener = null;
+
+ // Modular DRM clean up
+ mOnDrmInfoHandlerDelegate = null;
+ mOnDrmPreparedHandlerDelegate = null;
+ resetDrmState();
+
_release();
}
@@ -1852,6 +1958,8 @@ public class MediaPlayer extends PlayerBase
mIndexTrackPairs.clear();
mInbandTrackIndices.clear();
};
+
+ resetDrmState();
}
private native void _reset();
@@ -2945,6 +3053,7 @@ public class MediaPlayer extends PlayerBase
private static final int MEDIA_INFO = 200;
private static final int MEDIA_SUBTITLE_DATA = 201;
private static final int MEDIA_META_DATA = 202;
+ private static final int MEDIA_DRM_INFO = 210;
private TimeProvider mTimeProvider;
@@ -2983,11 +3092,43 @@ public class MediaPlayer extends PlayerBase
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
sendMessage(msg2);
}
+
+ // MEDIA_DRM_INFO is fired (if available) before MEDIA_PREPARED.
+ // An empty mDrmInfo indicates prepared is done but the source is not DRM protected.
+ // Setting this before the callback so onPreparedListener can call getDrmInfo to
+ // get the right state
+ mDrmInfoResolved = true;
+
OnPreparedListener onPreparedListener = mOnPreparedListener;
if (onPreparedListener != null)
onPreparedListener.onPrepared(mMediaPlayer);
return;
+ case MEDIA_DRM_INFO:
+ Log.v(TAG, "MEDIA_DRM_INFO " + mOnDrmInfoHandlerDelegate);
+
+ if (msg.obj == null) {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
+ } else if (msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ DrmInfo drmInfo = new DrmInfo(parcel);
+
+ OnDrmInfoHandlerDelegate onDrmInfoHandlerDelegate;
+ synchronized (mDrmLock) {
+ mDrmInfo = drmInfo.makeCopy();
+ // local copy while keeping the lock
+ onDrmInfoHandlerDelegate = mOnDrmInfoHandlerDelegate;
+ }
+
+ // notifying the client outside the lock
+ if (onDrmInfoHandlerDelegate != null) {
+ onDrmInfoHandlerDelegate.notifyClient(drmInfo);
+ }
+ } else {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj NONE; UNEXPECTED" + msg.obj);
+ }
+ return;
+
case MEDIA_PLAYBACK_COMPLETE:
{
mOnCompletionInternalListener.onCompletion(mMediaPlayer);
@@ -3646,6 +3787,988 @@ public class MediaPlayer extends PlayerBase
private OnInfoListener mOnInfoListener;
+ // Modular DRM begin
+
+ /**
+ * Interface definition of a callback to be invoked when the app
+ * can do DRM configuration (get/set properties) before the session
+ * is opened. This facilitates configuration of the properties, like
+ * 'securityLevel', which has to be set after DRM scheme creation but
+ * before the DRM session is opened.
+ *
+ * The only allowed DRM calls in this listener are getDrmPropertyString
+ * and setDrmPropertyString.
+ *
+ */
+ public static abstract class OnDrmConfigCallback
+ {
+ /**
+ * Called to give the app the opportunity to configure DRM before the session is created
+ *
+ * @param mp the {@code MediaPlayer} associated with this callback
+ */
+ public void onDrmConfig(MediaPlayer mp) {}
+ }
+
+ /**
+ * Interface definition of a callback to be invoked when the
+ * DRM info becomes available
+ */
+ public interface OnDrmInfoListener
+ {
+ /**
+ * Called to indicate DRM info is available
+ *
+ * @param mp the {@code MediaPlayer} associated with this callback
+ * @param drmInfo DRM info of the source including PSSH, mimes, and subset
+ * of crypto schemes supported by this device
+ */
+ public void onDrmInfo(MediaPlayer mp, DrmInfo drmInfo);
+ }
+
+ /**
+ * Register a callback to be invoked when the DRM info is
+ * known.
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnDrmInfoListener(OnDrmInfoListener listener)
+ {
+ setOnDrmInfoListener(listener, null);
+ }
+
+ /**
+ * Register a callback to be invoked when the DRM info is
+ * known.
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnDrmInfoListener(OnDrmInfoListener listener, Handler handler)
+ {
+ synchronized (mDrmLock) {
+ if (listener != null) {
+ mOnDrmInfoHandlerDelegate = new OnDrmInfoHandlerDelegate(this, listener, handler);
+ } else {
+ mOnDrmInfoHandlerDelegate = null;
+ }
+ } // synchronized
+ }
+
+ private OnDrmInfoHandlerDelegate mOnDrmInfoHandlerDelegate;
+
+ /**
+ * Interface definition of a callback to notify the app when the
+ * DRM is ready for key request/response
+ */
+ public interface OnDrmPreparedListener
+ {
+ /**
+ * Called to notify the app that prepareDrm is finished and ready for key request/response
+ *
+ * @param mp the {@code MediaPlayer} associated with this callback
+ * @param success the result of DRM preparation
+ */
+ public void onDrmPrepared(MediaPlayer mp, boolean success);
+ }
+
+ /**
+ * Register a callback to be invoked when the DRM object is prepared.
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnDrmPreparedListener(OnDrmPreparedListener listener)
+ {
+ setOnDrmPreparedListener(listener, null);
+ }
+
+ /**
+ * Register a callback to be invoked when the DRM object is prepared.
+ *
+ * @param listener the callback that will be run
+ * @param handler the Handler that will receive the callback
+ */
+ public void setOnDrmPreparedListener(OnDrmPreparedListener listener, Handler handler)
+ {
+ synchronized (mDrmLock) {
+ if (listener != null) {
+ mOnDrmPreparedHandlerDelegate = new OnDrmPreparedHandlerDelegate(this,
+ listener, handler);
+ } else {
+ mOnDrmPreparedHandlerDelegate = null;
+ }
+ } // synchronized
+ }
+
+ private OnDrmPreparedHandlerDelegate mOnDrmPreparedHandlerDelegate;
+
+
+ private class OnDrmInfoHandlerDelegate {
+ private MediaPlayer mMediaPlayer;
+ private OnDrmInfoListener mOnDrmInfoListener;
+ private Handler mHandler;
+
+ OnDrmInfoHandlerDelegate(MediaPlayer mp, OnDrmInfoListener listener, Handler handler) {
+ mMediaPlayer = mp;
+ mOnDrmInfoListener = listener;
+
+ // find the looper for our new event handler
+ Looper looper = null;
+ if (handler != null) {
+ looper = handler.getLooper();
+ }
+
+ // construct the event handler with this looper
+ if (looper != null) {
+ // implement the event handler delegate
+ mHandler = new Handler(looper) {
+ public void handleMessage(Message msg) {
+ DrmInfo drmInfo = (DrmInfo)msg.obj;
+ mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo);
+ }
+ };
+ }
+ }
+
+ void notifyClient(DrmInfo drmInfo) {
+ if ( mHandler != null ) {
+ Message msg = new Message(); // no message type needed
+ msg.obj = drmInfo;
+ mHandler.sendMessage(msg);
+ }
+ else { // no handler: direct call
+ mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo);
+ }
+ }
+ }
+
+ private class OnDrmPreparedHandlerDelegate {
+ private MediaPlayer mMediaPlayer;
+ private OnDrmPreparedListener mOnDrmPreparedListener;
+ private Handler mHandler;
+
+ OnDrmPreparedHandlerDelegate(MediaPlayer mp, OnDrmPreparedListener listener,
+ Handler handler) {
+ mMediaPlayer = mp;
+ mOnDrmPreparedListener = listener;
+
+ // find the looper for our new event handler
+ Looper looper = null;
+ if (handler != null) {
+ looper = handler.getLooper();
+ }
+
+ // construct the event handler with this looper
+ if (looper != null) {
+ // implement the event handler delegate
+ mHandler = new Handler(looper) {
+ public void handleMessage(Message msg) {
+ boolean success = (msg.arg1 == 0) ? false : true;
+ mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success);
+ }
+ };
+ }
+ }
+
+ void notifyClient(boolean success) {
+ if ( mHandler != null ) {
+ Message msg = new Message(); // no message type needed
+ msg.arg1 = success ? 1 : 0;
+ mHandler.sendMessage(msg);
+ }
+ else { // no handler: direct call
+ mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the DRM Info associated with the current source
+ *
+ * @throws IllegalStateException if called before prepare()
+ */
+ public DrmInfo getDrmInfo()
+ {
+ DrmInfo drmInfo = null;
+
+ // there is not much point if the app calls getDrmInfo within an OnDrmInfoListenet;
+ // regardless below returns drmInfo anyway instead of raising an exception
+ synchronized (mDrmLock) {
+ if (!mDrmInfoResolved && mDrmInfo == null) {
+ final String msg = "The Player has not been prepared yet";
+ Log.v(TAG, msg);
+ throw new IllegalStateException(msg);
+ }
+
+ if (mDrmInfo != null) {
+ drmInfo = mDrmInfo.makeCopy();
+ }
+ } // synchronized
+
+ return drmInfo;
+ }
+
+ private native void _prepareDrm(@NonNull byte[] uuid, int mode)
+ throws UnsupportedSchemeException, ResourceBusyException, NotProvisionedException;
+
+ /**
+ * Prepares the DRM for the current source
+ * <p>
+ * If {@code OnDrmConfigCallback} is registered, it will be called half-way into
+ * preparation to allow configuration of the DRM properties before opening the
+ * DRM session. Note that the callback is called synchronously in the thread that called
+ * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
+ * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
+ * <p>
+ * If the device has not been provisioned before, this call also provisions the device
+ * which involves accessing the provisioning server and can take a variable time to
+ * complete depending on the network connectivity.
+ * If OnDrmPreparedListener is registered, prepareDrm() runs in non-blocking
+ * mode by launching the provisioning in the background and returning. The listener
+ * will be called when provisioning and preperation has finished. If a
+ * OnDrmPreparedListener is not registered, prepareDrm() waits till provisioning
+ * and preperation has finished, i.e., runs in blocking mode.
+ * <p>
+ * If OnDrmPreparedListener is registered, it is called to indicated the DRM session
+ * being ready regardless of blocking or non-blocking mode. The application should
+ * not make any assumption about its call sequence (e.g., before or after prepareDrm
+ * returns) or the thread context that will execute the listener.
+ * <p>
+ *
+ * @param uuid The UUID of the crypto scheme.
+ *
+ * @throws IllegalStateException if called before prepare(), or there exists a Drm already
+ * @throws UnsupportedSchemeException if the crypto scheme is not supported
+ * @throws ResourceBusyException if required DRM resources are in use
+ * @throws ProvisioningErrorException if provisioning is required but an attempt failed
+ */
+ public void prepareDrm(@NonNull UUID uuid, OnDrmConfigCallback configCallback)
+ throws UnsupportedSchemeException,
+ ResourceBusyException, ProvisioningErrorException
+ {
+ boolean allDoneWithoutProvisioning = false;
+ // get a snapshot as we'll use them outside the lock
+ OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate = null;
+
+ synchronized (mDrmLock) {
+
+ // only allowing if tied to a protected source; might releax for releasing offline keys
+ if (mDrmInfo == null) {
+ final String msg = String.format("prepareDrm(%s): Wrong usage: " +
+ "The player must be prepared and DRM " +
+ "info be retrieved before this call.", uuid);
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ }
+
+ if (mActiveDrmScheme) {
+ final String msg = String.format("prepareDrm(%s): Wrong usage: There is already " +
+ "an active DRM scheme with %s.", uuid, mDrmUUID);
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ }
+
+ if (mPrepareDrmInProgress) {
+ final String msg = String.format("prepareDrm(%s): Wrong usage: There is already " +
+ "a pending prepareDrm call.", uuid);
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ }
+
+ if (mDrmProvisioningInProgress) {
+ final String msg = String.format("prepareDrm(%s): Unexpectd: Provisioning is " +
+ "already in progress.", uuid);
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ }
+
+ mPrepareDrmInProgress = true;
+ // local copy while the lock is held
+ onDrmPreparedHandlerDelegate = mOnDrmPreparedHandlerDelegate;
+
+ if (configCallback != null) {
+ try {
+ boolean allowOpenSession = false; // just pre-openSession
+ _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0);
+ } catch (IllegalStateException e) {
+ final String msg = String.format("prepareDrm(): Wrong usage: The player must " +
+ "be in prepared state to call prepareDrm().");
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ } catch (NotProvisionedException e) { // the pre-config step won't raise this
+ final String msg = String.format("prepareDrm: Unexpected " +
+ "NotProvisionedException here.");
+ Log.e(TAG, msg);
+ throw new ProvisioningErrorException(msg);
+ } catch (Exception e) {
+ Log.w(TAG, String.format("prepareDrm: Exception %s", e));
+ throw e;
+ } finally {
+ mPrepareDrmInProgress = false;
+ }
+ }
+
+ mDrmConfigAllowed = true;
+ } // synchronized
+
+
+ // call the callback outside the lock
+ if (configCallback != null) {
+ configCallback.onDrmConfig(this);
+ }
+
+ synchronized (mDrmLock) {
+ mDrmConfigAllowed = false;
+
+ try {
+ boolean allowOpenSession = true; // all in
+ _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0);
+
+ mDrmUUID = uuid;
+ mActiveDrmScheme = true;
+
+ mPrepareDrmInProgress = false;
+
+ allDoneWithoutProvisioning = true;
+ } catch (IllegalStateException e) {
+ final String msg = String.format("prepareDrm(%s): Wrong usage: The player must be" +
+ " in prepared state to call prepareDrm().", uuid);
+ Log.e(TAG, msg);
+ throw new IllegalStateException(msg);
+ } catch (NotProvisionedException e) {
+ Log.w(TAG, String.format("prepareDrm: NotProvisionedException"));
+
+ // handle provisioning internally
+ boolean result = HandleProvisioninig(uuid);
+
+ // if blocking mode, we're already done;
+ // if non-blocking mode, we attempted to launch background provisioning
+ if (result == false) {
+ final String msg =
+ String.format("prepareDrm: Provisioning was required but failed.");
+ Log.e(TAG, msg);
+ throw new ProvisioningErrorException(msg);
+ }
+
+ // nothing else to do;
+ // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
+ } catch (Exception e) {
+ Log.w(TAG, String.format("prepareDrm: Exception %s", e));
+ throw e;
+ } finally {
+ mPrepareDrmInProgress = false;
+ }
+ } // synchronized
+
+
+ // if finished successfully without provisioning, call the callback outside the lock
+ if (allDoneWithoutProvisioning) {
+ if (onDrmPreparedHandlerDelegate != null)
+ onDrmPreparedHandlerDelegate.notifyClient(true /*success*/);
+ }
+
+ }
+
+
+ private native void _releaseDrm();
+
+ /**
+ * Releases the DRM session
+ *
+ * @throws NoDrmSchemeException if there is no active DRM session to release
+ */
+ public void releaseDrm()
+ throws NoDrmSchemeException
+ {
+ synchronized (mDrmLock) {
+ if (!mActiveDrmScheme) {
+ Log.e(TAG, String.format("releaseDrm(%s): No active DRM scheme to release."));
+ throw new NoDrmSchemeException("releaseDrm: No active DRM scheme to release.");
+ } else {
+ _releaseDrm();
+
+ mActiveDrmScheme = false;
+ }
+ } // synchronized
+ }
+
+
+ @NonNull
+ private native MediaDrm.KeyRequest _getKeyRequest(@NonNull byte[] scope,
+ @Nullable String mimeType, @MediaDrm.KeyType int keyType,
+ @Nullable Map<String, String> optionalParameters)
+ throws NotProvisionedException;
+
+ /**
+ * A key request/response exchange occurs between the app and a license server
+ * to obtain or release keys used to decrypt encrypted content.
+ * <p>
+ * getKeyRequest() is used to obtain an opaque key request byte array that is
+ * delivered to the license server. The opaque key request byte array is returned
+ * in KeyRequest.data. The recommended URL to deliver the key request to is
+ * returned in KeyRequest.defaultUrl.
+ * <p>
+ * After the app has received the key request response from the server,
+ * it should deliver to the response to the DRM engine plugin using the method
+ * {@link #provideKeyResponse}.
+ *
+ * @param scope may be a container-specific initialization data or a keySetId,
+ * depending on the specified keyType.
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set to
+ * the container-specific initialization data. Its meaning is interpreted based on the
+ * mime type provided in the mimeType parameter. It could contain, for example,
+ * the content ID, key ID or other data obtained from the content metadata that is
+ * required in generating the key request.
+ * When the keyType is KEY_TYPE_RELEASE, scope should be set to the keySetId of
+ * the keys being released.
+ *
+ * @param mimeType identifies the mime type of the content
+ *
+ * @param keyType specifes the type of the request. The request may be to acquire
+ * keys for streaming or offline content, or to release previously acquired
+ * keys, which are identified by a keySetId.
+ *
+ * @param optionalParameters are included in the key request message to
+ * allow a client application to provide additional message parameters to the server.
+ * This may be {@code null} if no additional parameters are to be sent.
+ *
+ * @throws NoDrmSchemeException if there is no active DRM session
+ */
+ @NonNull
+ public MediaDrm.KeyRequest getKeyRequest(@NonNull byte[] scope, @Nullable String mimeType,
+ @MediaDrm.KeyType int keyType, @Nullable Map<String, String> optionalParameters)
+ throws NoDrmSchemeException
+ {
+ synchronized (mDrmLock) {
+ if (!mActiveDrmScheme) {
+ Log.e(TAG, String.format("getKeyRequest NoDrmSchemeException"));
+ throw new NoDrmSchemeException("getKeyRequest: Has to set a DRM scheme first.");
+ }
+
+ try {
+ return _getKeyRequest(scope, mimeType, keyType, optionalParameters);
+ } catch (NotProvisionedException e) {
+ Log.w(TAG, String.format("getKeyRequest NotProvisionedException: " +
+ "Unexpected. Shouldn't have reached here."));
+ throw new IllegalStateException("getKeyRequest: Unexpected provisioning error.");
+ } catch (Exception e) {
+ Log.w(TAG, String.format("getKeyRequest Exception %s", e));
+ throw e;
+ }
+
+ } // synchronized
+ }
+
+
+ @Nullable
+ private native byte[] _provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
+ throws DeniedByServerException;
+
+ /**
+ * A key response is received from the license server by the app, then it is
+ * provided to the DRM engine plugin using provideKeyResponse. When the
+ * response is for an offline key request, a key-set identifier is returned that
+ * can be used to later restore the keys to a new session with the method
+ * {@ link # restoreKeys}.
+ * When the response is for a streaming or release request, null is returned.
+ *
+ * @param keySetId When the response is for a release request, keySetId identifies
+ * the saved key associated with the release request (i.e., the same keySetId
+ * passed to the earlier {@ link # getKeyRequest} call. It MUST be null when the
+ * response is for either streaming or offline key requests.
+ *
+ * @param response the byte array response from the server
+ *
+ * @throws NoDrmSchemeException if there is no active DRM session
+ * @throws DeniedByServerException if the response indicates that the
+ * server rejected the request
+ */
+ public byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
+ throws NoDrmSchemeException, DeniedByServerException
+ {
+ synchronized (mDrmLock) {
+
+ if (!mActiveDrmScheme) {
+ Log.e(TAG, String.format("getKeyRequest NoDrmSchemeException"));
+ throw new NoDrmSchemeException("getKeyRequest: Has to set a DRM scheme first.");
+ }
+
+ try {
+ return _provideKeyResponse(keySetId, response);
+ } catch (Exception e) {
+ Log.w(TAG, String.format("provideKeyResponse Exception %s", e));
+ throw e;
+ }
+ } // synchronized
+ }
+
+
+ private native void _restoreKeys(@NonNull byte[] keySetId);
+
+ /**
+ * Restore persisted offline keys into a new session. keySetId identifies the
+ * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
+ *
+ * @param keySetId identifies the saved key set to restore
+ */
+ public void restoreKeys(@NonNull byte[] keySetId)
+ throws NoDrmSchemeException
+ {
+ synchronized (mDrmLock) {
+
+ if (!mActiveDrmScheme) {
+ Log.w(TAG, String.format("restoreKeys NoDrmSchemeException"));
+ throw new NoDrmSchemeException("restoreKeys: Has to set a DRM scheme first.");
+ }
+
+ try {
+ _restoreKeys(keySetId);
+ } catch (Exception e) {
+ Log.w(TAG, String.format("restoreKeys Exception %s", e));
+ throw e;
+ }
+
+ } // synchronized
+ }
+
+
+ @NonNull
+ private native String _getDrmPropertyString(@NonNull String propertyName);
+
+ /**
+ * Read a DRM engine plugin String property value, given the property name string.
+ * <p>
+ * @param propertyName the property name
+ *
+ * Standard fields names are:
+ * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION},
+ * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS}
+ */
+ @NonNull
+ public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
+ throws NoDrmSchemeException
+ {
+ String value;
+ synchronized (mDrmLock) {
+
+ if (!mActiveDrmScheme && !mDrmConfigAllowed) {
+ Log.w(TAG, String.format("getDrmPropertyString NoDrmSchemeException"));
+ throw new NoDrmSchemeException("getDrmPropertyString: Has to prepareDrm() first.");
+ }
+
+ try {
+ value = _getDrmPropertyString(propertyName);
+ } catch (Exception e) {
+ Log.w(TAG, String.format("getDrmPropertyString Exception %s", e));
+ throw e;
+ }
+ } // synchronized
+
+ return value;
+ }
+
+ private native void _setDrmPropertyString(@NonNull String propertyName, @NonNull String value);
+
+ /**
+ * Set a DRM engine plugin String property value.
+ * <p>
+ * @param propertyName the property name
+ * @param value the property value
+ *
+ * Standard fields names are:
+ * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION},
+ * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS}
+ */
+ public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
+ @NonNull String value)
+ throws NoDrmSchemeException
+ {
+ synchronized (mDrmLock) {
+
+ if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
+ Log.w(TAG, String.format("setDrmPropertyString NoDrmSchemeException"));
+ throw new NoDrmSchemeException("setDrmPropertyString: Has to prepareDrm() first.");
+ }
+
+ try {
+ _setDrmPropertyString(propertyName, value);
+ } catch ( Exception e ) {
+ Log.w(TAG, String.format("setDrmPropertyString Exception %s", e));
+ throw e;
+ }
+ } // synchronized
+ }
+
+ public static final class DrmInfo {
+ private Map<UUID, byte[]> mapPssh;
+ private UUID[] supportedSchemes;
+ // TODO: Won't need this in final release. Only keeping it for the existing test app.
+ private String[] mimes;
+
+ public Map<UUID, byte[]> getPssh() {
+ return mapPssh;
+ }
+ public UUID[] getSupportedSchemes() {
+ return supportedSchemes;
+ }
+ // TODO: Won't need this in final release. Only keeping it for the existing test app.
+ public String[] getMimes() {
+ return mimes;
+ }
+
+ private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes, String[] Mimes) {
+ mapPssh = Pssh;
+ supportedSchemes = SupportedSchemes;
+ mimes = Mimes;
+ }
+
+ private DrmInfo(Parcel parcel) {
+ Log.v(TAG, "DrmInfo(" + parcel + ") size " + parcel.dataSize());
+
+ int psshsize = parcel.readInt();
+ byte[] pssh = new byte[psshsize];
+ parcel.readByteArray(pssh);
+
+ Log.v(TAG, "DrmInfo() PSSH: " + arrToHex(pssh));
+ mapPssh = parsePSSH(pssh, psshsize);
+ Log.v(TAG, "DrmInfo() PSSH: " + mapPssh);
+
+ int supportedDRMsCount = parcel.readInt();
+ supportedSchemes = new UUID[supportedDRMsCount];
+ for (int i = 0; i < supportedDRMsCount; i++) {
+ byte[] uuid = new byte[16];
+ parcel.readByteArray(uuid);
+
+ supportedSchemes[i] = bytesToUUID(uuid);
+
+ Log.v(TAG, "DrmInfo() supportedScheme[" + i + "]: " +
+ supportedSchemes[i]);
+ }
+
+ // TODO: Won't need this in final release. Only keeping it for the test app.
+ mimes = parcel.readStringArray();
+ int mimeCount = mimes.length;
+ Log.v(TAG, "DrmInfo() mime: " + Arrays.toString(mimes));
+
+ Log.v(TAG, "DrmInfo() Parcel psshsize: " + psshsize +
+ " supportedDRMsCount: " + supportedDRMsCount +
+ " mimeCount: " + mimeCount);
+ }
+
+ private DrmInfo makeCopy() {
+ return new DrmInfo(this.mapPssh, this.supportedSchemes, this.mimes);
+ }
+
+ private String arrToHex(byte[] bytes) {
+ String out = "0x";
+ for (int i = 0; i < bytes.length; i++) {
+ out += String.format("%02x", bytes[i]);
+ }
+
+ return out;
+ }
+
+ private UUID bytesToUUID(byte[] uuid) {
+ long msb = 0, lsb = 0;
+ for (int i = 0; i < 8; i++) {
+ msb |= ( ((long)uuid[i] & 0xff) << (8 * (7 - i)) );
+ lsb |= ( ((long)uuid[i+8] & 0xff) << (8 * (7 - i)) );
+ }
+
+ return new UUID(msb, lsb);
+ }
+
+ private Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
+ Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
+
+ final int UUID_SIZE = 16;
+ final int DATALEN_SIZE = 4;
+
+ int len = psshsize;
+ int numentries = 0;
+ int i = 0;
+
+ while (len > 0) {
+ if (len < UUID_SIZE) {
+ Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
+ "UUID: (%d < 16) pssh: %d", len, psshsize));
+ return null;
+ }
+
+ byte[] subset = Arrays.copyOfRange(pssh, i, i + UUID_SIZE);
+ UUID uuid = bytesToUUID(subset);
+ i += UUID_SIZE;
+ len -= UUID_SIZE;
+
+ // get data length
+ if (len < 4) {
+ Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
+ "datalen: (%d < 4) pssh: %d", len, psshsize));
+ return null;
+ }
+
+ subset = Arrays.copyOfRange(pssh, i, i+DATALEN_SIZE);
+ int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) ?
+ ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16) |
+ ((subset[1] & 0xff) << 8) | (subset[0] & 0xff) :
+ ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16) |
+ ((subset[2] & 0xff) << 8) | (subset[3] & 0xff) ;
+ i += DATALEN_SIZE;
+ len -= DATALEN_SIZE;
+
+ if (len < datalen) {
+ Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
+ "data: (%d < %d) pssh: %d", len, datalen, psshsize));
+ return null;
+ }
+
+ byte[] data = Arrays.copyOfRange(pssh, i, i+datalen);
+
+ // skip the data
+ i += datalen;
+ len -= datalen;
+
+ Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
+ numentries, uuid, arrToHex(data), psshsize));
+ numentries++;
+ result.put(uuid, data);
+ }
+
+ return result;
+ }
+
+ }; // DrmInfo
+
+ /**
+ * Thrown when a DRM method is called before preparing a DRM scheme through prepareDrm().
+ * Extends MediaDrm.MediaDrmException
+ */
+ public static final class NoDrmSchemeException extends MediaDrmException {
+ public NoDrmSchemeException(String detailMessage) {
+ super(detailMessage);
+ }
+ }
+
+ /**
+ * Thrown when the device requires DRM provisioning but the provisioning attempt has
+ * failed (for example: network timeout, provisioning server error).
+ * Extends MediaDrm.MediaDrmException
+ */
+ public static final class ProvisioningErrorException extends MediaDrmException {
+ public ProvisioningErrorException(String detailMessage) {
+ super(detailMessage);
+ }
+ }
+
+ // Modular DRM helpers
+
+ private class ProvisioningThread extends Thread
+ {
+ public static final int TIMEOUT_MS = 60000;
+
+ private UUID uuid;
+ private String urlStr;
+ private byte[] response;
+ private Object drmLock;
+ private OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate;
+ private MediaPlayer mediaPlayer;
+ private boolean succeeded;
+ private boolean finished;
+ public boolean succeeded() {
+ return succeeded;
+ }
+
+ public ProvisioningThread initialize(MediaDrm.ProvisionRequest request,
+ UUID uuid, MediaPlayer mediaPlayer) {
+ // lock is held by the caller
+ drmLock = mediaPlayer.mDrmLock;
+ onDrmPreparedHandlerDelegate = mediaPlayer.mOnDrmPreparedHandlerDelegate;
+ this.mediaPlayer = mediaPlayer;
+
+ urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
+ this.uuid = uuid;
+
+ Log.v(TAG, String.format("HandleProvisioninig: Thread is initialised url: %s", urlStr));
+ return this;
+ }
+
+ public void run() {
+
+ boolean provisioningSucceeded = false;
+ try {
+ URL url = new URL(urlStr);
+ final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ try {
+ connection.setRequestMethod("POST");
+ connection.setDoOutput(false);
+ connection.setDoInput(true);
+ connection.setConnectTimeout(TIMEOUT_MS);
+ connection.setReadTimeout(TIMEOUT_MS);
+
+ connection.connect();
+ response = Streams.readFully(connection.getInputStream());
+
+ Log.v(TAG, String.format("HandleProvisioninig: Thread run response %d %s",
+ response.length, response));
+ } catch (Exception e) {
+ Log.w(TAG, String.format("HandleProvisioninig: Thread run connect %s url: %s",
+ e, url));
+ } finally {
+ connection.disconnect();
+ }
+ } catch (Exception e) {
+ Log.w(TAG, String.format("HandleProvisioninig: Thread run openConnection %s", e));
+ }
+
+ if (response != null) {
+ try {
+ MediaDrm drm = new MediaDrm(uuid);
+ drm.provideProvisionResponse(response);
+ drm.release();
+ Log.v(TAG, String.format("HandleProvisioninig: Thread run " +
+ "newDrm+provideProvisionResponse SUCCEEDED!"));
+
+ provisioningSucceeded = true;
+ } catch (Exception e) {
+ Log.w(TAG, String.format("HandleProvisioninig: Thread run " +
+ "newDrm+provideProvisionResponse %s", e));
+ }
+ }
+
+ // non-blocking mode needs the lock
+ if (onDrmPreparedHandlerDelegate != null) {
+
+ synchronized (drmLock) {
+ // continuing with prepareDrm
+ if (provisioningSucceeded) {
+ succeeded = mediaPlayer.resumePrepareDrm(uuid);
+ }
+ mediaPlayer.mDrmProvisioningInProgress = false;
+ mediaPlayer.mPrepareDrmInProgress = false;
+ }
+
+ // calling the callback outside the lock
+ onDrmPreparedHandlerDelegate.notifyClient(succeeded);
+ } else { // blocking mode already has the lock
+
+ // continuing with prepareDrm
+ if (provisioningSucceeded) {
+ succeeded = mediaPlayer.resumePrepareDrm(uuid);
+ }
+ mediaPlayer.mDrmProvisioningInProgress = false;
+ mediaPlayer.mPrepareDrmInProgress = false;
+ }
+
+ finished = true;
+ } // run()
+
+ } // ProvisioningThread
+
+ private boolean HandleProvisioninig(UUID uuid)
+ {
+ // the lock is already held by the caller
+
+ if (mDrmProvisioningInProgress) {
+ Log.e(TAG, String.format("HandleProvisioninig: Unexpected mDrmProvisioningInProgress"));
+ return false;
+ }
+
+ MediaDrm.ProvisionRequest provReq = null;
+ try {
+ MediaDrm drm = new MediaDrm(uuid);
+ provReq = drm.getProvisionRequest();
+ drm.release();
+ } catch (Exception e) {
+ Log.e(TAG, String.format("HandleProvisioninig: getProvisionRequest failed with %s", e));
+ return false;
+ }
+
+ Log.v(TAG, String.format("HandleProvisioninig provReq: data %s url %s",
+ (provReq != null) ? provReq.getData() : "-",
+ (provReq != null) ? provReq.getDefaultUrl() : "://")
+ );
+
+ // networking in a background thread
+ mDrmProvisioningInProgress = true;
+
+ mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
+ mDrmProvisioningThread.start();
+
+ boolean result = false;
+
+ // non-blocking
+ if (mOnDrmPreparedHandlerDelegate != null) {
+ result = true;
+ } else {
+ // if blocking mode, wait till provisioning is done
+ try {
+ mDrmProvisioningThread.join();
+ } catch (Exception e) {
+ Log.w(TAG, String.format("HandleProvisioninig: Thread.join Exception %s", e));
+ }
+ result = mDrmProvisioningThread.succeeded();
+ // no longer need the thread
+ mDrmProvisioningThread = null;
+ }
+
+ return result;
+ }
+
+ private boolean resumePrepareDrm(UUID uuid)
+ {
+ // mDrmLock is guaranteed to be held
+ boolean success = false;
+ try {
+ boolean allowOpenSession = true; // resuming
+ _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0);
+
+ mDrmUUID = uuid;
+ mActiveDrmScheme = true;
+
+ success = true;
+ } catch (Exception e) {
+ Log.w(TAG, String.format("HandleProvisioninig: " +
+ "Thread run _prepareDrm resume failed with %s", e));
+ }
+
+ return success;
+ }
+
+ private void resetDrmState()
+ {
+ synchronized (mDrmLock) {
+ mDrmInfoResolved = false;
+ mDrmInfo = null;
+
+ if (mDrmProvisioningThread != null) {
+ // timeout; relying on HttpUrlConnection
+ try {
+ mDrmProvisioningThread.join();
+ }
+ catch (InterruptedException e) {
+ Log.w(TAG, String.format("resetDrmState: ProvThread.join Exception %s", e));
+ }
+ mDrmProvisioningThread = null;
+ }
+
+ mPrepareDrmInProgress = false;
+ } // synchronized
+ }
+
+ private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
+ long msb = uuid.getMostSignificantBits();
+ long lsb = uuid.getLeastSignificantBits();
+
+ byte[] uuidBytes = new byte[16];
+ for (int i = 0; i < 8; ++i) {
+ uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
+ uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
+ }
+
+ return uuidBytes;
+ }
+
+ // Modular DRM end
+
/*
* Test whether a given video scaling mode is supported.
*/
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index e62dfaab26b5..3e884509833b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -803,15 +803,17 @@ public class MediaRecorder
/**
* Sets the next output file descriptor to be used when the maximum filesize is reached
* on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File descriptor
- * must be seekable and in read-write mode. After setting the next output file, application
- * should not use the file referenced by this file descriptor until {@link #stop}. Application
- * must call this after receiving on the {@link android.media.MediaRecorder.OnInfoListener} a
- * "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving
- * a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used
- * until switching to that output. Application will receive
- * {@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED} when the next output file is used.
- * Application will not be able to set a new output file if the previous one has not been used.
- * Application is responsible for cleaning up unused files after {@link #stop} is called.
+ * must be seekable and writable. After setting the next output file, application should not
+ * use the file referenced by this file descriptor until {@link #stop}. It is the application's
+ * responsibility to close the file descriptor. It is safe to do so as soon as this call returns.
+ * Application must call this after receiving on the
+ * {@link android.media.MediaRecorder.OnInfoListener} a "what" code of
+ * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving a "what" code of
+ * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used until switching to
+ * that output. Application will receive{@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED}
+ * when the next output file is used. Application will not be able to set a new output file if
+ * the previous one has not been used. Application is responsible for cleaning up unused files
+ * after {@link #stop} is called.
*
* @param fd an open file descriptor to be written into.
* @throws IllegalStateException if it is called before prepare().
diff --git a/media/java/android/media/MediaSyncEvent.java b/media/java/android/media/MediaSyncEvent.java
index 31af6b512b31..04448f04ef5c 100644
--- a/media/java/android/media/MediaSyncEvent.java
+++ b/media/java/android/media/MediaSyncEvent.java
@@ -36,7 +36,7 @@ public class MediaSyncEvent {
* The corresponding action is triggered only when the presentation is completed
* (meaning the media has been presented to the user) on the specified session.
* A synchronization of this type requires a source audio session ID to be set via
- * {@link #setAudioSessionId(int) method.
+ * {@link #setAudioSessionId(int)} method.
*/
public static final int SYNC_EVENT_PRESENTATION_COMPLETE =
AudioSystem.SYNC_EVENT_PRESENTATION_COMPLETE;
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index bd0a1b42ce7d..d2b052ab60a0 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -58,14 +58,17 @@ public abstract class PlayerBase {
// for AppOps
private IAppOpsService mAppOps;
private IAppOpsCallback mAppOpsCallback;
- private boolean mHasAppOpsPlayAudio = true;
- private final Object mAppOpsLock = new Object();
+ private boolean mHasAppOpsPlayAudio = true; // sync'd on mLock
+ private final Object mLock = new Object();
private final int mImplType;
// uniquely identifies the Player Interface throughout the system (P I Id)
private int mPlayerIId;
- private int mState;
+ private int mState; // sync'd on mLock
+ private int mStartDelayMs = 0; // sync'd on mLock
+ private float mPanMultiplierL = 1.0f; // sync'd on mLock
+ private float mPanMultiplierR = 1.0f; // sync'd on mLock
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -89,11 +92,13 @@ public abstract class PlayerBase {
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
// initialize mHasAppOpsPlayAudio
- updateAppOpsPlayAudio_sync();
+ synchronized (mLock) {
+ updateAppOpsPlayAudio_sync();
+ }
// register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
- synchronized (mAppOpsLock) {
+ synchronized (mLock) {
if (op == AppOpsManager.OP_PLAY_AUDIO) {
updateAppOpsPlayAudio_sync();
}
@@ -130,7 +135,7 @@ public abstract class PlayerBase {
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e);
}
- synchronized (mAppOpsLock) {
+ synchronized (mLock) {
mAttributes = attr;
updateAppOpsPlayAudio_sync();
}
@@ -139,23 +144,39 @@ public abstract class PlayerBase {
void baseStart() {
if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
try {
- mState = AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
- getService().playerEvent(mPlayerIId, mState);
+ synchronized (mLock) {
+ mState = AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
+ getService().playerEvent(mPlayerIId, mState);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e);
}
- synchronized (mAppOpsLock) {
+ synchronized (mLock) {
if (isRestricted_sync()) {
playerSetVolume(true/*muting*/,0, 0);
}
}
}
+ void baseSetStartDelayMs(int delayMs) {
+ synchronized(mLock) {
+ mStartDelayMs = Math.max(delayMs, 0);
+ }
+ }
+
+ protected int getStartDelayMs() {
+ synchronized(mLock) {
+ return mStartDelayMs;
+ }
+ }
+
void basePause() {
if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
try {
- mState = AudioPlaybackConfiguration.PLAYER_STATE_PAUSED;
- getService().playerEvent(mPlayerIId, mState);
+ synchronized (mLock) {
+ mState = AudioPlaybackConfiguration.PLAYER_STATE_PAUSED;
+ getService().playerEvent(mPlayerIId, mState);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, PAUSED state will not be tracked", e);
}
@@ -164,26 +185,45 @@ public abstract class PlayerBase {
void baseStop() {
if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
try {
- mState = AudioPlaybackConfiguration.PLAYER_STATE_STOPPED;
- getService().playerEvent(mPlayerIId, mState);
+ synchronized (mLock) {
+ mState = AudioPlaybackConfiguration.PLAYER_STATE_STOPPED;
+ getService().playerEvent(mPlayerIId, mState);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, STOPPED state will not be tracked", e);
}
}
+ void baseSetPan(float pan) {
+ final float p = Math.min(Math.max(-1.0f, pan), 1.0f);
+ synchronized (mLock) {
+ if (p >= 0.0f) {
+ mPanMultiplierL = 1.0f - p;
+ mPanMultiplierR = 1.0f;
+ } else {
+ mPanMultiplierL = 1.0f;
+ mPanMultiplierR = 1.0f + p;
+ }
+ }
+ baseSetVolume(mLeftVolume, mRightVolume);
+ }
+
void baseSetVolume(float leftVolume, float rightVolume) {
- synchronized (mAppOpsLock) {
+ final boolean hasAppOpsPlayAudio;
+ synchronized (mLock) {
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
+ hasAppOpsPlayAudio = mHasAppOpsPlayAudio;
if (isRestricted_sync()) {
return;
}
}
- playerSetVolume(false/*muting*/,leftVolume, rightVolume);
+ playerSetVolume(!hasAppOpsPlayAudio/*muting*/,
+ leftVolume * mPanMultiplierL, rightVolume * mPanMultiplierR);
}
int baseSetAuxEffectSendLevel(float level) {
- synchronized (mAppOpsLock) {
+ synchronized (mLock) {
mAuxEffectSendLevel = level;
if (isRestricted_sync()) {
return AudioSystem.SUCCESS;
@@ -199,9 +239,11 @@ public abstract class PlayerBase {
void baseRelease() {
if (DEBUG) { Log.v(TAG, "baseRelease() piid=" + mPlayerIId + " state=" + mState); }
try {
- if (mState != AudioPlaybackConfiguration.PLAYER_STATE_RELEASED) {
- getService().releasePlayer(mPlayerIId);
- mState = AudioPlaybackConfiguration.PLAYER_STATE_RELEASED;
+ synchronized (mLock) {
+ if (mState != AudioPlaybackConfiguration.PLAYER_STATE_RELEASED) {
+ getService().releasePlayer(mPlayerIId);
+ mState = AudioPlaybackConfiguration.PLAYER_STATE_RELEASED;
+ }
}
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, the player will still be tracked", e);
@@ -215,7 +257,7 @@ public abstract class PlayerBase {
/**
* To be called whenever a condition that might affect audibility of this player is updated.
- * Must be called synchronized on mAppOpsLock.
+ * Must be called synchronized on mLock.
*/
void updateAppOpsPlayAudio_sync() {
boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
@@ -237,7 +279,8 @@ public abstract class PlayerBase {
Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume
+ "/" + mRightVolume);
}
- playerSetVolume(false/*muting*/, mLeftVolume, mRightVolume);
+ playerSetVolume(false/*muting*/,
+ mLeftVolume * mPanMultiplierL, mRightVolume * mPanMultiplierR);
playerSetAuxEffectSendLevel(false/*muting*/, mAuxEffectSendLevel);
} else {
if (DEBUG_APP_OPS) {
@@ -297,6 +340,14 @@ public abstract class PlayerBase {
return sService;
}
+ /**
+ * @hide
+ * @param delayMs
+ */
+ public void setStartDelayMs(int delayMs) {
+ baseSetStartDelayMs(delayMs);
+ }
+
//=====================================================================
// Abstract methods a subclass needs to implement
/**
@@ -335,6 +386,16 @@ public abstract class PlayerBase {
public void setVolume(float vol) {
baseSetVolume(vol, vol);
}
+
+ @Override
+ public void setPan(float pan) {
+ baseSetPan(pan);
+ }
+
+ @Override
+ public void setStartDelayMs(int delayMs) {
+ baseSetStartDelayMs(delayMs);
+ }
};
//=====================================================================
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
index 171be277e18f..1a2c6688fbd5 100644
--- a/media/java/android/media/PlayerProxy.java
+++ b/media/java/android/media/PlayerProxy.java
@@ -52,10 +52,9 @@ public class PlayerProxy {
// Methods matching the IPlayer interface
/**
* @hide
- * @throws IllegalStateException
*/
@SystemApi
- public void start() throws IllegalStateException {
+ public void start() {
try {
mConf.getIPlayer().start();
} catch (NullPointerException|RemoteException e) {
@@ -66,10 +65,9 @@ public class PlayerProxy {
/**
* @hide
- * @throws IllegalStateException
*/
@SystemApi
- public void pause() throws IllegalStateException {
+ public void pause() {
try {
mConf.getIPlayer().pause();
} catch (NullPointerException|RemoteException e) {
@@ -80,10 +78,9 @@ public class PlayerProxy {
/**
* @hide
- * @throws IllegalStateException
*/
@SystemApi
- public void stop() throws IllegalStateException {
+ public void stop() {
try {
mConf.getIPlayer().stop();
} catch (NullPointerException|RemoteException e) {
@@ -94,10 +91,10 @@ public class PlayerProxy {
/**
* @hide
- * @throws IllegalStateException
+ * @param vol
*/
@SystemApi
- public void setVolume(float vol) throws IllegalStateException {
+ public void setVolume(float vol) {
try {
mConf.getIPlayer().setVolume(vol);
} catch (NullPointerException|RemoteException e) {
@@ -106,4 +103,33 @@ public class PlayerProxy {
}
}
+ /**
+ * @hide
+ * @param pan
+ */
+ @SystemApi
+ public void setPan(float pan) {
+ try {
+ mConf.getIPlayer().setPan(pan);
+ } catch (NullPointerException|RemoteException e) {
+ throw new IllegalStateException(
+ "No player to proxy for setPan operation, player already released?", e);
+ }
+ }
+
+ /**
+ * @hide
+ * @param delayMs
+ */
+ @SystemApi
+ public void setStartDelayMs(int delayMs) {
+ try {
+ mConf.getIPlayer().setStartDelayMs(delayMs);
+ } catch (NullPointerException|RemoteException e) {
+ throw new IllegalStateException(
+ "No player to proxy for setStartDelayMs operation, player already released?",
+ e);
+ }
+ }
+
}
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index e197141e0214..5f12742128bf 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -224,7 +224,7 @@ public class AudioMixingRule {
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
* @return the same Builder instance.
* @throws IllegalArgumentException
- * @see {@link #excludeRule(AudioAttributes, int)}
+ * @see #excludeRule(AudioAttributes, int)
*/
@SystemApi
public Builder addRule(AudioAttributes attrToMatch, int rule)
@@ -253,7 +253,7 @@ public class AudioMixingRule {
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
* @return the same Builder instance.
* @throws IllegalArgumentException
- * @see {@link #addRule(AudioAttributes, int)}
+ * @see #addRule(AudioAttributes, int)
*/
@SystemApi
public Builder excludeRule(AudioAttributes attrToMatch, int rule)
@@ -275,7 +275,7 @@ public class AudioMixingRule {
* {@link AudioAttributes} or an {@link java.lang.Integer}).
* @return the same Builder instance.
* @throws IllegalArgumentException
- * @see {@link #excludeMixRule(int, Object)}
+ * @see #excludeMixRule(int, Object)
*/
@SystemApi
public Builder addMixRule(int rule, Object property) throws IllegalArgumentException {
diff --git a/media/java/android/media/session/IOnMediaKeyListener.aidl b/media/java/android/media/session/IOnMediaKeyListener.aidl
new file mode 100644
index 000000000000..aa98ea312ab9
--- /dev/null
+++ b/media/java/android/media/session/IOnMediaKeyListener.aidl
@@ -0,0 +1,28 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.os.ResultReceiver;
+import android.view.KeyEvent;
+
+/**
+ * Listener to handle media key.
+ * @hide
+ */
+oneway interface IOnMediaKeyListener {
+ void onMediaKey(in KeyEvent event, in ResultReceiver result);
+}
+
diff --git a/media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl b/media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
new file mode 100644
index 000000000000..07b83471d166
--- /dev/null
+++ b/media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
@@ -0,0 +1,27 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.view.KeyEvent;
+
+/**
+ * Listener to handle volume key long-press.
+ * @hide
+ */
+oneway interface IOnVolumeKeyLongPressListener {
+ void onVolumeKeyLongPress(in KeyEvent event);
+}
+
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 2f6e260741c4..a146c6226171 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -16,6 +16,7 @@
package android.media.session;
import android.content.Intent;
+import android.media.MediaDescription;
import android.media.Rating;
import android.net.Uri;
import android.os.Bundle;
@@ -49,6 +50,10 @@ oneway interface ISessionCallback {
void onRepeatMode(int repeatMode);
void onShuffleMode(boolean enabled);
void onCustomAction(String action, in Bundle args);
+ void onAddQueueItem(in MediaDescription description);
+ void onAddQueueItemAt(in MediaDescription description, int index);
+ void onRemoveQueueItem(in MediaDescription description);
+ void onRemoveQueueItemAt(int index);
// These callbacks are for volume handling
void onAdjustVolume(int direction);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e92758c950af..7b5233ac0704 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -18,6 +18,7 @@ package android.media.session;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.session.ISessionControllerCallback;
@@ -51,6 +52,11 @@ interface ISessionController {
MediaMetadata getMetadata();
PlaybackState getPlaybackState();
ParceledListSlice getQueue();
+ void addQueueItem(in MediaDescription description);
+ void addQueueItemAt(in MediaDescription description, int index);
+ void removeQueueItem(in MediaDescription description);
+ void removeQueueItemAt(int index);
+
CharSequence getQueueTitle();
Bundle getExtras();
int getRatingType();
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index bb59e5b4be35..8a987733ee64 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -18,6 +18,8 @@ package android.media.session;
import android.content.ComponentName;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.IOnMediaKeyListener;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -31,6 +33,7 @@ interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
List<IBinder> getSessions(in ComponentName compName, int userId);
void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
+ void dispatchVolumeKeyEvent(in KeyEvent keyEvent, int stream, boolean musicOnly);
void dispatchAdjustVolume(int suggestedStream, int delta, int flags);
void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
int userId);
@@ -41,4 +44,8 @@ interface ISessionManager {
// For PhoneWindowManager to precheck media keys
boolean isGlobalPriorityActive();
-} \ No newline at end of file
+
+ void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
+ void setOnMediaKeyListener(in IOnMediaKeyListener listener);
+}
+
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 8cbf8e1eccdf..bab2af25dde5 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.AudioManager;
+import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
@@ -38,6 +39,7 @@ import android.util.Log;
import android.view.KeyEvent;
import java.lang.ref.WeakReference;
+import java.lang.UnsupportedOperationException;
import java.util.ArrayList;
import java.util.List;
@@ -111,8 +113,7 @@ public final class MediaController {
}
/**
- * Get a {@link TransportControls} instance to send transport actions to
- * the associated session.
+ * Get a {@link TransportControls} instance to send transport actions to this session.
*
* @return A transport controls instance.
*/
@@ -151,7 +152,7 @@ public final class MediaController {
try {
return mSessionBinder.getPlaybackState();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPlaybackState.", e);
+ Log.wtf(TAG, "Error calling getPlaybackState", e);
return null;
}
}
@@ -165,7 +166,7 @@ public final class MediaController {
try {
return mSessionBinder.getMetadata();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getMetadata.", e);
+ Log.wtf(TAG, "Error calling getMetadata", e);
return null;
}
}
@@ -183,12 +184,103 @@ public final class MediaController {
return queue.getList();
}
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getQueue.", e);
+ Log.wtf(TAG, "Error calling getQueue", e);
}
return null;
}
/**
+ * Add a queue item from the given {@code description} at the end of the play queue
+ * of this session. Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescription} for creating the
+ * {@link MediaSession.QueueItem} to be inserted.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void addQueueItem(MediaDescription description) {
+ try {
+ long flags = mSessionBinder.getFlags();
+ if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mSessionBinder.addQueueItem(description);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling addQueueItem", e);
+ }
+ }
+
+ /**
+ * Add a queue item from the given {@code description} at the specified position
+ * in the play queue of this session. Shifts the queue item currently at that position
+ * (if any) and any subsequent queue items to the right (adds one to their indices).
+ * Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescription} for creating the
+ * {@link MediaSession.QueueItem} to be inserted.
+ * @param index The index at which the created {@link MediaSession.QueueItem} is to be inserted.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void addQueueItem(MediaDescription description, int index) {
+ try {
+ long flags = mSessionBinder.getFlags();
+ if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mSessionBinder.addQueueItemAt(description, index);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling addQueueItemAt", e);
+ }
+ }
+
+ /**
+ * Remove the first occurrence of the specified {@link MediaSession.QueueItem}
+ * with the given {@link MediaDescription description} in the play queue of the associated
+ * session. Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescription} for denoting the
+ * {@link MediaSession.QueueItem} to be removed.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void removeQueueItem(MediaDescription description) {
+ try {
+ long flags = mSessionBinder.getFlags();
+ if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mSessionBinder.removeQueueItem(description);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling removeQueueItem", e);
+ }
+ }
+
+ /**
+ * Remove an queue item at the specified position in the play queue
+ * of this session. Not all sessions may support this.
+ *
+ * @param index The index of the element to be removed.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void removeQueueItemAt(int index) {
+ try {
+ long flags = mSessionBinder.getFlags();
+ if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mSessionBinder.removeQueueItemAt(index);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling removeQueueItemAt", e);
+ }
+ }
+
+ /**
* Get the queue title for this session.
*/
public @Nullable CharSequence getQueueTitle() {
@@ -230,7 +322,7 @@ public final class MediaController {
try {
return mSessionBinder.getRatingType();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getRatingType.", e);
+ Log.wtf(TAG, "Error calling getRatingType", e);
return Rating.RATING_NONE;
}
}
@@ -245,7 +337,7 @@ public final class MediaController {
try {
return mSessionBinder.getRepeatMode();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getRepeatMode.", e);
+ Log.wtf(TAG, "Error calling getRepeatMode", e);
return PlaybackState.REPEAT_MODE_NONE;
}
}
@@ -259,7 +351,7 @@ public final class MediaController {
try {
return mSessionBinder.isShuffleModeEnabled();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling isShuffleModeEnabled.", e);
+ Log.wtf(TAG, "Error calling isShuffleModeEnabled", e);
return false;
}
}
@@ -273,7 +365,7 @@ public final class MediaController {
try {
return mSessionBinder.getFlags();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getFlags.", e);
+ Log.wtf(TAG, "Error calling getFlags", e);
}
return 0;
}
@@ -290,7 +382,7 @@ public final class MediaController {
result.maxVolume, result.currentVolume);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getAudioInfo.", e);
+ Log.wtf(TAG, "Error calling getAudioInfo", e);
}
return null;
}
@@ -305,7 +397,7 @@ public final class MediaController {
try {
return mSessionBinder.getLaunchPendingIntent();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPendingIntent.", e);
+ Log.wtf(TAG, "Error calling getPendingIntent", e);
}
return null;
}
@@ -334,7 +426,7 @@ public final class MediaController {
try {
mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName());
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling setVolumeTo.", e);
+ Log.wtf(TAG, "Error calling setVolumeTo", e);
}
}
@@ -355,7 +447,7 @@ public final class MediaController {
try {
mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName());
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
+ Log.wtf(TAG, "Error calling adjustVolumeBy", e);
}
}
@@ -421,7 +513,7 @@ public final class MediaController {
try {
mSessionBinder.sendCommand(command, args, cb);
} catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCommand.", e);
+ Log.d(TAG, "Dead object in sendCommand", e);
}
}
@@ -435,7 +527,7 @@ public final class MediaController {
try {
mPackageName = mSessionBinder.getPackageName();
} catch (RemoteException e) {
- Log.d(TAG, "Dead object in getPackageName.", e);
+ Log.d(TAG, "Dead object in getPackageName", e);
}
}
return mPackageName;
@@ -452,7 +544,7 @@ public final class MediaController {
try {
mTag = mSessionBinder.getTag();
} catch (RemoteException e) {
- Log.d(TAG, "Dead object in getTag.", e);
+ Log.d(TAG, "Dead object in getTag", e);
}
}
return mTag;
@@ -652,7 +744,7 @@ public final class MediaController {
try {
mSessionBinder.prepare();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare.", e);
+ Log.wtf(TAG, "Error calling prepare", e);
}
}
@@ -671,12 +763,12 @@ public final class MediaController {
public void prepareFromMediaId(String mediaId, Bundle extras) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException(
- "You must specify a non-empty String for prepareFromMediaId.");
+ "You must specify a non-empty String for prepareFromMediaId");
}
try {
mSessionBinder.prepareFromMediaId(mediaId, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
+ Log.wtf(TAG, "Error calling prepare(" + mediaId + ")", e);
}
}
@@ -702,7 +794,7 @@ public final class MediaController {
try {
mSessionBinder.prepareFromSearch(query, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
+ Log.wtf(TAG, "Error calling prepare(" + query + ")", e);
}
}
@@ -721,12 +813,12 @@ public final class MediaController {
public void prepareFromUri(Uri uri, Bundle extras) {
if (uri == null || Uri.EMPTY.equals(uri)) {
throw new IllegalArgumentException(
- "You must specify a non-empty Uri for prepareFromUri.");
+ "You must specify a non-empty Uri for prepareFromUri");
}
try {
mSessionBinder.prepareFromUri(uri, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
+ Log.wtf(TAG, "Error calling prepare(" + uri + ")", e);
}
}
@@ -737,7 +829,7 @@ public final class MediaController {
try {
mSessionBinder.play();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play.", e);
+ Log.wtf(TAG, "Error calling play", e);
}
}
@@ -751,12 +843,12 @@ public final class MediaController {
public void playFromMediaId(String mediaId, Bundle extras) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException(
- "You must specify a non-empty String for playFromMediaId.");
+ "You must specify a non-empty String for playFromMediaId");
}
try {
mSessionBinder.playFromMediaId(mediaId, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
+ Log.wtf(TAG, "Error calling play(" + mediaId + ")", e);
}
}
@@ -778,7 +870,7 @@ public final class MediaController {
try {
mSessionBinder.playFromSearch(query, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + query + ").", e);
+ Log.wtf(TAG, "Error calling play(" + query + ")", e);
}
}
@@ -792,12 +884,12 @@ public final class MediaController {
public void playFromUri(Uri uri, Bundle extras) {
if (uri == null || Uri.EMPTY.equals(uri)) {
throw new IllegalArgumentException(
- "You must specify a non-empty Uri for playFromUri.");
+ "You must specify a non-empty Uri for playFromUri");
}
try {
mSessionBinder.playFromUri(uri, extras);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+ Log.wtf(TAG, "Error calling play(" + uri + ")", e);
}
}
@@ -809,7 +901,7 @@ public final class MediaController {
try {
mSessionBinder.skipToQueueItem(id);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
+ Log.wtf(TAG, "Error calling skipToItem(" + id + ")", e);
}
}
@@ -821,7 +913,7 @@ public final class MediaController {
try {
mSessionBinder.pause();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling pause.", e);
+ Log.wtf(TAG, "Error calling pause", e);
}
}
@@ -833,7 +925,7 @@ public final class MediaController {
try {
mSessionBinder.stop();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling stop.", e);
+ Log.wtf(TAG, "Error calling stop", e);
}
}
@@ -846,7 +938,7 @@ public final class MediaController {
try {
mSessionBinder.seekTo(pos);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling seekTo.", e);
+ Log.wtf(TAG, "Error calling seekTo", e);
}
}
@@ -858,7 +950,7 @@ public final class MediaController {
try {
mSessionBinder.fastForward();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling fastForward.", e);
+ Log.wtf(TAG, "Error calling fastForward", e);
}
}
@@ -869,7 +961,7 @@ public final class MediaController {
try {
mSessionBinder.next();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling next.", e);
+ Log.wtf(TAG, "Error calling next", e);
}
}
@@ -881,7 +973,7 @@ public final class MediaController {
try {
mSessionBinder.rewind();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rewind.", e);
+ Log.wtf(TAG, "Error calling rewind", e);
}
}
@@ -892,7 +984,7 @@ public final class MediaController {
try {
mSessionBinder.previous();
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling previous.", e);
+ Log.wtf(TAG, "Error calling previous", e);
}
}
@@ -907,7 +999,7 @@ public final class MediaController {
try {
mSessionBinder.rate(rating);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rate.", e);
+ Log.wtf(TAG, "Error calling rate", e);
}
}
@@ -923,7 +1015,7 @@ public final class MediaController {
try {
mSessionBinder.repeatMode(repeatMode);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling setRepeatMode.", e);
+ Log.wtf(TAG, "Error calling setRepeatMode", e);
}
}
@@ -936,7 +1028,7 @@ public final class MediaController {
try {
mSessionBinder.shuffleMode(enabled);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling shuffleMode.", e);
+ Log.wtf(TAG, "Error calling shuffleMode", e);
}
}
@@ -950,7 +1042,7 @@ public final class MediaController {
public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
@Nullable Bundle args) {
if (customAction == null) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
+ throw new IllegalArgumentException("CustomAction cannot be null");
}
sendCustomAction(customAction.getAction(), args);
}
@@ -966,12 +1058,12 @@ public final class MediaController {
*/
public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
if (TextUtils.isEmpty(action)) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
+ throw new IllegalArgumentException("CustomAction cannot be null");
}
try {
mSessionBinder.sendCustomAction(action, args);
} catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCustomAction.", e);
+ Log.d(TAG, "Dead object in sendCustomAction", e);
}
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 84dc93ad4347..bee3f52c9b90 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@ public final class MediaSession {
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
+ * Set this flag on the session to indicate that it handles queue
+ * management commands through its {@link Callback}.
+ */
+ public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2;
+
+ /**
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
@@ -100,6 +106,7 @@ public final class MediaSession {
@IntDef(flag = true, value = {
FLAG_HANDLES_MEDIA_BUTTONS,
FLAG_HANDLES_TRANSPORT_CONTROLS,
+ FLAG_HANDLES_QUEUE_COMMANDS,
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
@@ -645,6 +652,22 @@ public final class MediaSession {
postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
}
+ private void dispatchAddQueueItem(MediaDescription description) {
+ postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM, description);
+ }
+
+ private void dispatchAddQueueItem(MediaDescription description, int index) {
+ postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM_AT, description, index);
+ }
+
+ private void dispatchRemoveQueueItem(MediaDescription description) {
+ postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM, description);
+ }
+
+ private void dispatchRemoveQueueItemAt(int index) {
+ postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM_AT, index);
+ }
+
private void dispatchMediaButton(Intent mediaButtonIntent) {
postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
}
@@ -666,10 +689,22 @@ public final class MediaSession {
postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd);
}
+ private void postToCallback(int what, int arg1) {
+ postToCallback(what, null, arg1);
+ }
+
private void postToCallback(int what, Object obj) {
postToCallback(what, obj, null);
}
+ private void postToCallback(int what, Object obj, int arg1) {
+ synchronized (mLock) {
+ if (mCallback != null) {
+ mCallback.post(what, obj, arg1);
+ }
+ }
+ }
+
private void postToCallback(int what, Object obj, Bundle extras) {
synchronized (mLock) {
if (mCallback != null) {
@@ -1043,6 +1078,47 @@ public final class MediaSession {
*/
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
}
+
+ /**
+ * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given
+ * {@link MediaDescription description} at the end of the play queue.
+ *
+ * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be
+ * inserted.
+ */
+ public void onAddQueueItem(MediaDescription description) {
+ }
+
+ /**
+ * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given
+ * {@link MediaDescription description} at the specified position in the play queue.
+ *
+ * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be
+ * inserted.
+ * @param index The index at which the created {@link QueueItem} is to be inserted.
+ */
+ public void onAddQueueItem(MediaDescription description, int index) {
+ }
+
+ /**
+ * Called when a {@link MediaController} wants to remove the first occurrence of the
+ * specified {@link QueueItem} with the given {@link MediaDescription description}
+ * in the play queue.
+ *
+ * @param description The {@link MediaDescription} for denoting the {@link QueueItem} to be
+ * removed.
+ */
+ public void onRemoveQueueItem(MediaDescription description) {
+ }
+
+ /**
+ * Called when a {@link MediaController} wants to remove a {@link QueueItem} at the
+ * specified position in the play queue.
+ *
+ * @param index The index of the element to be removed.
+ */
+ public void onRemoveQueueItemAt(int index) {
+ }
}
/**
@@ -1239,6 +1315,38 @@ public final class MediaSession {
}
@Override
+ public void onAddQueueItem(MediaDescription description) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchAddQueueItem(description);
+ }
+ }
+
+ @Override
+ public void onAddQueueItemAt(MediaDescription description, int index) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchAddQueueItem(description, index);
+ }
+ }
+
+ @Override
+ public void onRemoveQueueItem(MediaDescription description) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchRemoveQueueItem(description);
+ }
+ }
+
+ @Override
+ public void onRemoveQueueItemAt(int index) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchRemoveQueueItemAt(index);
+ }
+ }
+
+ @Override
public void onAdjustVolume(int direction) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1376,6 +1484,10 @@ public final class MediaSession {
private static final int MSG_CUSTOM_ACTION = 22;
private static final int MSG_ADJUST_VOLUME = 23;
private static final int MSG_SET_VOLUME = 24;
+ private static final int MSG_ADD_QUEUE_ITEM = 25;
+ private static final int MSG_ADD_QUEUE_ITEM_AT = 26;
+ private static final int MSG_REMOVE_QUEUE_ITEM = 27;
+ private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28;
private MediaSession.Callback mCallback;
@@ -1465,7 +1577,7 @@ public final class MediaSession {
mCallback.onSetRating((Rating) msg.obj);
break;
case MSG_REPEAT_MODE:
- mCallback.onSetRepeatMode((int) msg.obj);
+ mCallback.onSetRepeatMode(msg.arg1);
break;
case MSG_SHUFFLE_MODE:
mCallback.onSetShuffleModeEnabled((boolean) msg.obj);
@@ -1473,12 +1585,24 @@ public final class MediaSession {
case MSG_CUSTOM_ACTION:
mCallback.onCustomAction((String) msg.obj, msg.getData());
break;
+ case MSG_ADD_QUEUE_ITEM:
+ mCallback.onAddQueueItem((MediaDescription) msg.obj);
+ break;
+ case MSG_ADD_QUEUE_ITEM_AT:
+ mCallback.onAddQueueItem((MediaDescription) msg.obj, msg.arg1);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM:
+ mCallback.onRemoveQueueItem((MediaDescription) msg.obj);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM_AT:
+ mCallback.onRemoveQueueItemAt(msg.arg1);
+ break;
case MSG_ADJUST_VOLUME:
synchronized (mLock) {
vp = mVolumeProvider;
}
if (vp != null) {
- vp.onAdjustVolume((int) msg.obj);
+ vp.onAdjustVolume(msg.arg1);
}
break;
case MSG_SET_VOLUME:
@@ -1486,7 +1610,7 @@ public final class MediaSession {
vp = mVolumeProvider;
}
if (vp != null) {
- vp.onSetVolumeTo((int) msg.obj);
+ vp.onSetVolumeTo(msg.arg1);
}
break;
}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 95cb8aee6ac5..7c3af31a04d7 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -176,54 +176,12 @@ public class MediaSessionLegacyHelper {
}
}
- public void sendVolumeKeyEvent(KeyEvent keyEvent, boolean musicOnly) {
+ public void sendVolumeKeyEvent(KeyEvent keyEvent, int stream, boolean musicOnly) {
if (keyEvent == null) {
Log.w(TAG, "Tried to send a null key event. Ignoring.");
return;
}
- boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
- boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
- int direction = 0;
- boolean isMute = false;
- switch (keyEvent.getKeyCode()) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- isMute = true;
- break;
- }
- if (down || up) {
- int flags = AudioManager.FLAG_FROM_KEY;
- if (musicOnly) {
- // This flag is used when the screen is off to only affect
- // active media
- flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
- } else {
- // These flags are consistent with the home screen
- if (up) {
- flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
- } else {
- flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
- }
- }
- if (direction != 0) {
- // If this is action up we want to send a beep for non-music events
- if (up) {
- direction = 0;
- }
- mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
- direction, flags);
- } else if (isMute) {
- if (down && keyEvent.getRepeatCount() == 0) {
- mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
- AudioManager.ADJUST_TOGGLE_MUTE, flags);
- }
- }
- }
+ mSessionManager.dispatchVolumeKeyEvent(keyEvent, stream, musicOnly);
}
public void sendAdjustVolumeBy(int suggestedStream, int delta, int flags) {
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 2364a13e6385..80d2a0c2149e 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -18,6 +18,7 @@ package android.media.session;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
import android.media.AudioManager;
@@ -26,6 +27,7 @@ import android.media.session.ISessionManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
@@ -50,6 +52,18 @@ import java.util.List;
public final class MediaSessionManager {
private static final String TAG = "SessionManager";
+ /**
+ * Used by IOnMediaKeyListener to indicate that the media key event isn't handled.
+ * @hide
+ */
+ public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0;
+
+ /**
+ * Used by IOnMediaKeyListener to indicate that the media key event is handled.
+ * @hide
+ */
+ public static final int RESULT_MEDIA_KEY_HANDLED = 1;
+
private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
= new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
private final Object mLock = new Object();
@@ -57,6 +71,9 @@ public final class MediaSessionManager {
private Context mContext;
+ private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
+ private OnMediaKeyListenerImpl mOnMediaKeyListener;
+
/**
* @hide
*/
@@ -278,6 +295,21 @@ public final class MediaSessionManager {
}
/**
+ * Send a volume key event. The receiver will be selected automatically.
+ *
+ * @param keyEvent The volume KeyEvent to send.
+ * @param needWakeLock True if a wake lock should be held while sending the key.
+ * @hide
+ */
+ public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int stream, boolean musicOnly) {
+ try {
+ mService.dispatchVolumeKeyEvent(keyEvent, stream, musicOnly);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send volume key event.", e);
+ }
+ }
+
+ /**
* Dispatch an adjust volume request to the system. It will be sent to the
* most relevant audio stream or media session. The direction must be one of
* {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
@@ -313,6 +345,72 @@ public final class MediaSessionManager {
}
/**
+ * Set the volume key long-press listener. While the listener is set, the listener
+ * gets the volume key long-presses instead of changing volume.
+ *
+ * <p>System can only have a single volume key long-press listener.
+ *
+ * @param listener The volume key long-press listener. {@code null} to reset.
+ * @param handler The handler on which the listener should be invoked, or {@code null}
+ * if the listener should be invoked on the calling thread's looper.
+ * @hide
+ */
+ @SystemApi
+ public void setOnVolumeKeyLongPressListener(
+ OnVolumeKeyLongPressListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ try {
+ if (listener == null) {
+ mOnVolumeKeyLongPressListener = null;
+ mService.setOnVolumeKeyLongPressListener(null);
+ } else {
+ if (handler == null) {
+ handler = new Handler();
+ }
+ mOnVolumeKeyLongPressListener =
+ new OnVolumeKeyLongPressListenerImpl(listener, handler);
+ mService.setOnVolumeKeyLongPressListener(mOnVolumeKeyLongPressListener);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set volume key long press listener", e);
+ }
+ }
+ }
+
+ /**
+ * Set the media key listener. While the listener is set, the listener
+ * gets the media key before any other media sessions but after the global priority session.
+ * If the listener handles the key (i.e. returns {@code true}),
+ * other sessions will not get the event.
+ *
+ * <p>System can only have a single media key listener.
+ *
+ * @param listener The media key listener. {@code null} to reset.
+ * @param handler The handler on which the listener should be invoked, or {@code null}
+ * if the listener should be invoked on the calling thread's looper.
+ * @hide
+ */
+ @SystemApi
+ public void setOnMediaKeyListener(OnMediaKeyListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ try {
+ if (listener == null) {
+ mOnMediaKeyListener = null;
+ mService.setOnMediaKeyListener(null);
+ } else {
+ if (handler == null) {
+ handler = new Handler();
+ }
+ mOnMediaKeyListener = new OnMediaKeyListenerImpl(listener, handler);
+ mService.setOnMediaKeyListener(mOnMediaKeyListener);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set media key listener", e);
+ }
+ }
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
@@ -320,6 +418,33 @@ public final class MediaSessionManager {
public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);
}
+ /**
+ * Listens the volume key long-presses.
+ * @hide
+ */
+ @SystemApi
+ public interface OnVolumeKeyLongPressListener {
+ /**
+ * Called when the volume key is long-pressed.
+ * <p>This will be called for both down and up events.
+ */
+ void onVolumeKeyLongPress(KeyEvent event);
+ }
+
+ /**
+ * Listens the media key.
+ * @hide
+ */
+ @SystemApi
+ public interface OnMediaKeyListener {
+ /**
+ * Called when the media key is pressed.
+ * <p>If it takes more than 1s to return, the key event will be sent to
+ * other media sessions.
+ */
+ boolean onMediaKey(KeyEvent event);
+ }
+
private static final class SessionsChangedWrapper {
private Context mContext;
private OnActiveSessionsChangedListener mListener;
@@ -360,4 +485,60 @@ public final class MediaSessionManager {
mHandler = null;
}
}
+
+ private static final class OnVolumeKeyLongPressListenerImpl
+ extends IOnVolumeKeyLongPressListener.Stub {
+ private OnVolumeKeyLongPressListener mListener;
+ private Handler mHandler;
+
+ public OnVolumeKeyLongPressListenerImpl(
+ OnVolumeKeyLongPressListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
+
+ @Override
+ public void onVolumeKeyLongPress(KeyEvent event) {
+ if (mListener == null || mHandler == null) {
+ Log.w(TAG, "Failed to call volume key long-press listener." +
+ " Either mListener or mHandler is null");
+ return;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onVolumeKeyLongPress(event);
+ }
+ });
+ }
+ }
+
+ private static final class OnMediaKeyListenerImpl extends IOnMediaKeyListener.Stub {
+ private OnMediaKeyListener mListener;
+ private Handler mHandler;
+
+ public OnMediaKeyListenerImpl(OnMediaKeyListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
+
+ @Override
+ public void onMediaKey(KeyEvent event, ResultReceiver result) {
+ if (mListener == null || mHandler == null) {
+ Log.w(TAG, "Failed to call media key listener." +
+ " Either mListener or mHandler is null");
+ return;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ boolean handled = mListener.onMediaKey(event);
+ Log.d(TAG, "The media key listener is returned " + handled);
+ result.send(
+ handled ? RESULT_MEDIA_KEY_HANDLED : RESULT_MEDIA_KEY_NOT_HANDLED,
+ null);
+ }
+ });
+ }
+ }
}
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 3ee80af3de9f..ddbd542ec037 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -18,6 +18,7 @@ package android.media.tv;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -29,6 +30,8 @@ import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.ArraySet;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -359,6 +362,285 @@ public final class TvContract {
String COLUMN_PACKAGE_NAME = "package_name";
}
+ /**
+ * Common base for the tables of TV programs.
+ */
+ public interface BaseProgramColumns extends BaseTvColumns {
+ /**
+ * The ID of the TV channel that provides this TV program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
+ * The title of this TV program.
+ *
+ * <p>If this program is an episodic TV show, it is recommended that the title is the series
+ * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
+ * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_TITLE = "title";
+
+ /**
+ * The season display number of this TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+
+ /**
+ * The title of the season for this TV program for episodic TV shows.
+ *
+ * <p>This is an optional field supplied only when the season has a special title
+ * (e.g. The Final Season). If provided, the applications should display it instead of
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
+ * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+ * "Season The Final Season"). When displaying multiple programs, the order should be based
+ * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SEASON_TITLE = "season_title";
+
+ /**
+ * The episode display number of this TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+
+ /**
+ * The episode title of this TV program for episodic TV shows.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_TITLE = "episode_title";
+
+ /**
+ * The comma-separated canonical genre string of this TV program.
+ *
+ * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
+ * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
+ * genre strings from the text stored in the column.
+ *
+ * <p>Type: TEXT
+ * @see Genres
+ * @see Genres#encode
+ * @see Genres#decode
+ */
+ public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+
+ /**
+ * The short description of this TV program that is displayed to the user by default.
+ *
+ * <p>It is recommended to limit the length of the descriptions to 256 characters.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+
+ /**
+ * The detailed, lengthy description of this TV program that is displayed only when the user
+ * wants to see more information.
+ *
+ * <p>TV input services should leave this field empty if they have no additional details
+ * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+
+ /**
+ * The width of the video for this TV program, in the unit of pixels.
+ *
+ * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
+ * resolution of the current TV program. Can be empty if it is not known initially or the
+ * program does not convey any video such as the programs from type
+ * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_VIDEO_WIDTH = "video_width";
+
+ /**
+ * The height of the video for this TV program, in the unit of pixels.
+ *
+ * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
+ * resolution of the current TV program. Can be empty if it is not known initially or the
+ * program does not convey any video such as the programs from type
+ * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+
+ /**
+ * The comma-separated audio languages of this TV program.
+ *
+ * <p>This is used to describe available audio languages included in the program. Use either
+ * ISO 639-1 or 639-2/T codes.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+
+ /**
+ * The comma-separated content ratings of this TV program.
+ *
+ * <p>This is used to describe the content rating(s) of this program. Each comma-separated
+ * content rating sub-string should be generated by calling
+ * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
+ * rated by a single rating system, thus resulting in a corresponding single sub-string that
+ * does not require comma separation and multiple sub-strings appear only when the program
+ * content is rated by two or more content rating systems. If any of those ratings is
+ * specified as "blocked rating" in the user's parental control settings, the TV input
+ * service should block the current content and wait for the signal that it is okay to
+ * unblock.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CONTENT_RATING = "content_rating";
+
+ /**
+ * The URI for the poster art of this TV program.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+
+ /**
+ * The URI for the thumbnail of this TV program.
+ *
+ * <p>The system can generate a thumbnail from the poster art if this column is not
+ * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+ * just a scaled image of the poster art.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+
+ /**
+ * The flag indicating whether this TV program is searchable or not.
+ *
+ * <p>The columns of searchable programs can be read by other applications that have proper
+ * permission. Care must be taken not to open sensitive data.
+ *
+ * <p>A value of 1 indicates that the program is searchable and its columns can be read by
+ * other applications, a value of 0 indicates that the program is hidden and its columns can
+ * be read only by the package that owns the program and the system. If not specified, this
+ * value is set to 1 (searchable) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_SEARCHABLE = "searchable";
+
+ /**
+ * Internal data used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Type: BLOB
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+
+ /**
+ * The version number of this row entry used by TV input services.
+ *
+ * <p>This is best used by sync adapters to identify the rows to update. The number can be
+ * defined by individual TV input services. One may assign the same value as
+ * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+ * broadcast.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_VERSION_NUMBER = "version_number";
+ }
+
/** Column definitions for the TV channels table. */
public static final class Channels implements BaseTvColumns {
@@ -372,6 +654,37 @@ public final class TvContract {
/** The MIME type of a single TV channel. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+ /** @hide */
+ @StringDef({
+ TYPE_OTHER,
+ TYPE_NTSC,
+ TYPE_PAL,
+ TYPE_SECAM,
+ TYPE_DVB_T,
+ TYPE_DVB_T2,
+ TYPE_DVB_S,
+ TYPE_DVB_S2,
+ TYPE_DVB_C,
+ TYPE_DVB_C2,
+ TYPE_DVB_H,
+ TYPE_DVB_SH,
+ TYPE_ATSC_T,
+ TYPE_ATSC_C,
+ TYPE_ATSC_M_H,
+ TYPE_ISDB_T,
+ TYPE_ISDB_TB,
+ TYPE_ISDB_S,
+ TYPE_ISDB_C,
+ TYPE_1SEG,
+ TYPE_DTMB,
+ TYPE_CMMB,
+ TYPE_T_DMB,
+ TYPE_S_DMB,
+ TYPE_PREVIEW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
/**
* A generic channel type.
*
@@ -554,6 +867,15 @@ public final class TvContract {
*/
public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
+ /** @hide */
+ @StringDef({
+ SERVICE_TYPE_OTHER,
+ SERVICE_TYPE_AUDIO_VIDEO,
+ SERVICE_TYPE_AUDIO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ServiceType {}
+
/** A generic service type. */
public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
@@ -563,6 +885,22 @@ public final class TvContract {
/** The service type for radio channels that have audio only. */
public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+ /** @hide */
+ @StringDef({
+ VIDEO_FORMAT_240P,
+ VIDEO_FORMAT_360P,
+ VIDEO_FORMAT_480I,
+ VIDEO_FORMAT_576I,
+ VIDEO_FORMAT_576P,
+ VIDEO_FORMAT_720P,
+ VIDEO_FORMAT_1080I,
+ VIDEO_FORMAT_1080P,
+ VIDEO_FORMAT_2160P,
+ VIDEO_FORMAT_4320P,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VideoFormat {}
+
/** The video format for 240p. */
public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
@@ -596,6 +934,17 @@ public final class TvContract {
/** The video format for 4320p. */
public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+ /** @hide */
+ @StringDef({
+ VIDEO_RESOLUTION_SD,
+ VIDEO_RESOLUTION_ED,
+ VIDEO_RESOLUTION_HD,
+ VIDEO_RESOLUTION_FHD,
+ VIDEO_RESOLUTION_UHD,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VideoResolution {}
+
/** The video resolution for standard-definition. */
public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
@@ -634,7 +983,7 @@ public final class TvContract {
* @see #COLUMN_VIDEO_FORMAT
*/
@Nullable
- public static final String getVideoResolution(String videoFormat) {
+ public static final String getVideoResolution(@VideoFormat String videoFormat) {
return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
}
@@ -654,7 +1003,7 @@ public final class TvContract {
*
* <p>This is used to indicate the broadcast standard (e.g. ATSC, DVB or ISDB) the current
* channel conforms to. Use {@link #TYPE_OTHER} for streaming-based channels, which is the
- * default channel type. The value should match to one of the followings:
+ * default channel type. The value should match one of the followings:
* {@link #TYPE_1SEG},
* {@link #TYPE_ATSC_C},
* {@link #TYPE_ATSC_M_H},
@@ -1026,6 +1375,19 @@ public final class TvContract {
@SystemApi
public static final String COLUMN_TRANSIENT = "transient";
+ /**
+ * The flag indicating whether this TV channel is approved to be shown by the system.
+ *
+ * <p>A value of 1 indicates that the channel is approved to be shown by the system, and a
+ * value of 0 indicates that the channel is blocked by system. If not specified, this value
+ * is set to 0 (not approved) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ * @hide
+ */
+ @SystemApi
+ public static final String COLUMN_SYSTEM_APPROVED = "system_approved";
+
private Channels() {}
/**
@@ -1075,7 +1437,7 @@ public final class TvContract {
* <p>By default, the query results will be sorted by
* {@link Programs#COLUMN_START_TIME_UTC_MILLIS} in ascending order.
*/
- public static final class Programs implements BaseTvColumns {
+ public static final class Programs implements BaseProgramColumns {
/** The content:// style URI for this table. */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -1087,253 +1449,441 @@ public final class TvContract {
/** The MIME type of a single TV program. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
- /**
- * The ID of the TV channel that provides this TV program.
+ /** @hide */
+ @StringDef({
+ TYPE_MOVIE,
+ TYPE_TV_SERIES,
+ TYPE_TV_SEASON,
+ TYPE_TV_EPISODE,
+ TYPE_CLIP,
+ TYPE_EVENT,
+ TYPE_CHANNEL,
+ TYPE_TRACK,
+ TYPE_ALBUM,
+ TYPE_ARTIST,
+ TYPE_PLAYLIST,
+ TYPE_STATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * The program type for movie.
*
- * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_MOVIE = "TYPE_MOVIE";
+
+ /**
+ * The program type for TV series.
*
- * <p>This is a required field.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+
+ /**
+ * The program type for TV season.
*
- * <p>Type: INTEGER (long)
+ * @see #COLUMN_TYPE
*/
- public static final String COLUMN_CHANNEL_ID = "channel_id";
+ public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
/**
- * The title of this TV program.
+ * The program type for TV episode.
*
- * <p>If this program is an episodic TV show, it is recommended that the title is the series
- * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
- * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
- * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+
+ /**
+ * The program type for clip.
*
- * <p>Type: TEXT
+ * @see #COLUMN_TYPE
*/
- public static final String COLUMN_TITLE = "title";
+ public static final String TYPE_CLIP = "TYPE_CLIP";
/**
- * The season number of this TV program for episodic TV shows.
+ * The program type for event.
*
- * <p>Can be empty.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_EVENT = "TYPE_EVENT";
+
+ /**
+ * The program type for channel.
*
- * <p>Type: INTEGER
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+
+ /**
+ * The program type for track.
*
- * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
+ * @see #COLUMN_TYPE
*/
- @Deprecated
- public static final String COLUMN_SEASON_NUMBER = "season_number";
+ public static final String TYPE_TRACK = "TYPE_TRACK";
/**
- * The season display number of this TV program for episodic TV shows.
+ * The program type for album.
*
- * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
- * does not necessarily be numeric. (e.g. 12B)
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ALBUM = "TYPE_ALBUM";
+
+ /**
+ * The program type for artist.
*
- * <p>Can be empty.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ARTIST = "TYPE_ARTIST";
+
+ /**
+ * The program type for playlist.
*
- * <p>Type: TEXT
+ * @see #COLUMN_TYPE
*/
- public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
/**
- * The title of the season for this TV program for episodic TV shows.
+ * The program type for station.
*
- * <p>This is an optional field supplied only when the season has a special title
- * (e.g. The Final Season). If provided, the applications should display it instead of
- * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
- * (e.g. for "The Final Season", displayed string should be "The Final Season", not
- * "Season The Final Season"). When displaying multiple programs, the order should be based
- * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_STATION = "TYPE_STATION";
+
+ /** @hide */
+ @StringDef({
+ WATCH_NEXT_TYPE_CONTINUE,
+ WATCH_NEXT_TYPE_NEXT,
+ WATCH_NEXT_TYPE_NEW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WatchNextType {}
+
+ /**
+ * The watch next type for CONTINUE.
*
- * <p>Can be empty.
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+
+ /**
+ * The watch next type for NEXT.
*
- * <p>Type: TEXT
+ * @see #COLUMN_WATCH_NEXT_TYPE
*/
- public static final String COLUMN_SEASON_TITLE = "season_title";
+ public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
/**
- * The episode number of this TV program for episodic TV shows.
+ * The watch next type for NEW.
*
- * <p>Can be empty.
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+
+ /** @hide */
+ @StringDef({
+ ASPECT_RATIO_16_9,
+ ASPECT_RATIO_3_2,
+ ASPECT_RATIO_1_1,
+ ASPECT_RATIO_2_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AspectRatio {}
+
+ /**
+ * The aspect ratio for 16:9.
*
- * <p>Type: INTEGER
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+
+ /**
+ * The aspect ratio for 3:2.
*
- * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
*/
- @Deprecated
- public static final String COLUMN_EPISODE_NUMBER = "episode_number";
+ public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
/**
- * The episode display number of this TV program for episodic TV shows.
+ * The aspect ratio for 1:1.
*
- * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
- * does not necessarily be numeric. (e.g. 12B)
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+
+ /**
+ * The aspect ratio for 2:3.
*
- * <p>Can be empty.
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+
+ /** @hide */
+ @StringDef({
+ AVAILABILITY_AVAILABLE,
+ AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+ AVAILABILITY_PAID_CONTENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Availability {}
+
+ /**
+ * The availability for "available to this user".
*
- * <p>Type: TEXT
+ * @see #COLUMN_AVAILABILITY
*/
- public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
/**
- * The episode title of this TV program for episodic TV shows.
+ * The availability for "free with subscription".
*
- * <p>Can be empty.
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
+ "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+
+ /**
+ * The availability for "paid content, either to-own or rental
+ * (user has not purchased/rented).
*
- * <p>Type: TEXT
+ * @see #COLUMN_AVAILABILITY
*/
- public static final String COLUMN_EPISODE_TITLE = "episode_title";
+ public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+
+ /** @hide */
+ @StringDef({
+ INTERACTION_TYPE_LISTENS,
+ INTERACTION_TYPE_FOLLOWERS,
+ INTERACTION_TYPE_FANS,
+ INTERACTION_TYPE_LIKES,
+ INTERACTION_TYPE_THUMBS,
+ INTERACTION_TYPE_VIEWS,
+ INTERACTION_TYPE_VIEWERS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InteractionType {}
/**
- * The start time of this TV program, in milliseconds since the epoch.
+ * The interaction type for "listens".
*
- * <p>The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
- * previous program in the same channel. In practice, start time will usually be the end
- * time of the previous program.
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+
+ /**
+ * The interaction type for "followers".
*
- * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+
+ /**
+ * The interaction type for "fans".
*
- * <p>Type: INTEGER (long)
+ * @see #COLUMN_INTERACTION_TYPE
*/
- public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+ public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
/**
- * The end time of this TV program, in milliseconds since the epoch.
+ * The interaction type for "likes".
*
- * <p>The value should be equal to or less than {@link #COLUMN_START_TIME_UTC_MILLIS} of the
- * next program in the same channel. In practice, end time will usually be the start time of
- * the next program.
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+
+ /**
+ * The interaction type for "thumbs".
*
- * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+
+ /**
+ * The interaction type for "views".
*
- * <p>Type: INTEGER (long)
+ * @see #COLUMN_INTERACTION_TYPE
*/
- public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+ public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
/**
- * The comma-separated genre string of this TV program.
+ * The interaction type for "viewers".
*
- * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
- * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
- * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
- * {@link Genres#encode} to create a text that can be stored in this column. Use
- * {@link Genres#decode} to get the broadcast genre strings from the text stored in the
- * column.
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+
+ /** @hide */
+ @StringDef({
+ REVIEW_RATING_STYLE_STARS,
+ REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+ REVIEW_RATING_STYLE_PERCENTAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReviewRatingStyle {}
+
+ /**
+ * The review rating style for five star rating.
*
- * <p>Type: TEXT
- * @see Genres#encode
- * @see Genres#decode
+ * @see #COLUMN_REVIEW_RATING_STYLE
*/
- public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
/**
- * The comma-separated canonical genre string of this TV program.
+ * The review rating style for thumbs-up and thumbs-down rating.
*
- * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
- * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
- * genre strings from the text stored in the column.
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
+ "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+
+ /**
+ * The review rating style for 0 to 100 point system.
*
- * <p>Type: TEXT
- * @see Genres
- * @see Genres#encode
- * @see Genres#decode
+ * @see #COLUMN_REVIEW_RATING_STYLE
*/
- public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+ public static final String REVIEW_RATING_STYLE_PERCENTAGE =
+ "REVIEW_RATING_STYLE_PERCENTAGE";
/**
- * The short description of this TV program that is displayed to the user by default.
+ * The type of this program content.
*
- * <p>It is recommended to limit the length of the descriptions to 256 characters.
+ * <p>The value should match one of the followings:
+ * {@link #TYPE_MOVIE},
+ * {@link #TYPE_TV_SERIES},
+ * {@link #TYPE_TV_SEASON},
+ * {@link #TYPE_TV_EPISODE},
+ * {@link #TYPE_CLIP},
+ * {@link #TYPE_EVENT},
+ * {@link #TYPE_CHANNEL},
+ * {@link #TYPE_TRACK},
+ * {@link #TYPE_ALBUM},
+ * {@link #TYPE_ARTIST},
+ * {@link #TYPE_PLAYLIST}, and
+ * {@link #TYPE_STATION}.
+ *
+ * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
+ * channel.
*
* <p>Type: TEXT
*/
- public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+ public static final String COLUMN_TYPE = "type";
/**
- * The detailed, lengthy description of this TV program that is displayed only when the user
- * wants to see more information.
+ * The "watch next" type of this program content.
*
- * <p>TV input services should leave this field empty if they have no additional details
- * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+ * <p>The value should match one of the followings:
+ * {@link #WATCH_NEXT_TYPE_CONTINUE},
+ * {@link #WATCH_NEXT_TYPE_NEXT}, and
+ * {@link #WATCH_NEXT_TYPE_NEW}.
+ *
+ * <p>Can be empty.
*
* <p>Type: TEXT
*/
- public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+ public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
/**
- * The width of the video for this TV program, in the unit of pixels.
+ * The season number of this TV program for episodic TV shows.
*
- * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
- * resolution of the current TV program. Can be empty if it is not known initially or the
- * program does not convey any video such as the programs from type
- * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+ * <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
*/
- public static final String COLUMN_VIDEO_WIDTH = "video_width";
+ @Deprecated
+ public static final String COLUMN_SEASON_NUMBER = "season_number";
/**
- * The height of the video for this TV program, in the unit of pixels.
+ * The episode number of this TV program for episodic TV shows.
*
- * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
- * resolution of the current TV program. Can be empty if it is not known initially or the
- * program does not convey any video such as the programs from type
- * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+ * <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
*/
- public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+ @Deprecated
+ public static final String COLUMN_EPISODE_NUMBER = "episode_number";
+
+ /**
+ * The start time of this TV program, in milliseconds since the epoch.
+ *
+ * <p>The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
+ * previous program in the same channel. In practice, start time will usually be the end
+ * time of the previous program.
+ *
+ * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
/**
- * The comma-separated audio languages of this TV program.
+ * The end time of this TV program, in milliseconds since the epoch.
*
- * <p>This is used to describe available audio languages included in the program. Use either
- * ISO 639-1 or 639-2/T codes.
+ * <p>The value should be equal to or less than {@link #COLUMN_START_TIME_UTC_MILLIS} of the
+ * next program in the same channel. In practice, end time will usually be the start time of
+ * the next program.
*
- * <p>Type: TEXT
+ * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
+ *
+ * <p>Type: INTEGER (long)
*/
- public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
/**
- * The comma-separated content ratings of this TV program.
+ * The comma-separated genre string of this TV program.
*
- * <p>This is used to describe the content rating(s) of this program. Each comma-separated
- * content rating sub-string should be generated by calling
- * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
- * rated by a single rating system, thus resulting in a corresponding single sub-string that
- * does not require comma separation and multiple sub-strings appear only when the program
- * content is rated by two or more content rating systems. If any of those ratings is
- * specified as "blocked rating" in the user's parental control settings, the TV input
- * service should block the current content and wait for the signal that it is okay to
- * unblock.
+ * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+ * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
+ * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+ * {@link Genres#encode} to create a text that can be stored in this column. Use
+ * {@link Genres#decode} to get the broadcast genre strings from the text stored in the
+ * column.
*
* <p>Type: TEXT
+ * @see Genres#encode
+ * @see Genres#decode
*/
- public static final String COLUMN_CONTENT_RATING = "content_rating";
+ public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
/**
- * The URI for the poster art of this TV program.
+ * The aspect ratio of the poster art for this TV program.
*
- * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
*
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+
+ /**
+ * The aspect ratio of the thumbnail for this TV program.
*
- * <p>Can be empty.
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
*
* <p>Type: TEXT
*/
- public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
/**
- * The URI for the thumbnail of this TV program.
+ * The URI for the logo of this TV program.
*
- * <p>The system can generate a thumbnail from the poster art if this column is not
- * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
- * just a scaled image of the poster art.
+ * <p>This is a small badge shown on top of the poster art or thumbnail representing the
+ * source of the content.
*
* <p>The data in the column must be a URL, or a URI in one of the following formats:
*
@@ -1348,96 +1898,83 @@ public final class TvContract {
*
* <p>Type: TEXT
*/
- public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+ public static final String COLUMN_LOGO_URI = "logo_uri";
/**
- * The flag indicating whether this TV program is searchable or not.
+ * The availability of this TV program.
*
- * <p>The columns of searchable programs can be read by other applications that have proper
- * permission. Care must be taken not to open sensitive data.
+ * <p>The value should match one of the followings:
+ * {@link #AVAILABILITY_AVAILABLE},
+ * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+ * {@link #AVAILABILITY_PAID_CONTENT}.
*
- * <p>A value of 1 indicates that the program is searchable and its columns can be read by
- * other applications, a value of 0 indicates that the program is hidden and its columns can
- * be read only by the package that owns the program and the system. If not specified, this
- * value is set to 1 (searchable) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_SEARCHABLE = "searchable";
-
- /**
- * The flag indicating whether recording of this program is prohibited.
- *
- * <p>A value of 1 indicates that recording of this program is prohibited and application
- * will not schedule any recording for this program. A value of 0 indicates that the
- * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
- * default.
- *
- * <p>Type: INTEGER (boolean)
+ * <p>Type: TEXT
*/
- public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+ public static final String COLUMN_AVAILABILITY = "availability";
/**
- * Internal data used by individual TV input services.
+ * The starting price of this TV program.
*
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
+ * <p>This indicates the lowest regular acquisition cost of the content. It is only used
+ * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
*
- * <p>Type: BLOB
+ * <p>Type: TEXT
+ * @see #COLUMN_OFFER_PRICE
*/
- public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ public static final String COLUMN_STARTING_PRICE = "starting_price";
/**
- * Internal integer flag used by individual TV input services.
+ * The offer price of this TV program.
*
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
+ * <p>This is the promotional cost of the content. It is only used if the availability of
+ * the program is {@link #AVAILABILITY_PAID_CONTENT}.
*
- * <p>Type: INTEGER
+ * <p>Type: TEXT
+ * @see #COLUMN_STARTING_PRICE
*/
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ public static final String COLUMN_OFFER_PRICE = "offer_price";
/**
- * Internal integer flag used by individual TV input services.
+ * The release date of this TV program.
*
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
+ * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
*
- * <p>Type: INTEGER
+ * <p>Type: TEXT
*/
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ public static final String COLUMN_RELEASE_DATE = "release_date";
/**
- * Internal integer flag used by individual TV input services.
+ * The count of the items included in this TV program.
*
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
+ * <p>This is only relevant if the program represents a collection of items such as series,
+ * episodes, or music tracks.
*
* <p>Type: INTEGER
*/
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ public static final String COLUMN_ITEM_COUNT = "item_count";
/**
- * Internal integer flag used by individual TV input services.
+ * The flag indicating whether this TV program is live or not.
*
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
+ * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
+ * of 0 indicates that the content is off the air and does not need to be consumed at the
+ * present time. If not specified, the value is set to 0 (not live) by default.
*
- * <p>Type: INTEGER
+ * <p>Type: INTEGER (boolean)
*/
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ public static final String COLUMN_LIVE = "live";
/**
- * The version number of this row entry used by TV input services.
+ * The flag indicating whether recording of this program is prohibited.
*
- * <p>This is best used by sync adapters to identify the rows to update. The number can be
- * defined by individual TV input services. One may assign the same value as
- * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
- * broadcast.
+ * <p>A value of 1 indicates that recording of this program is prohibited and application
+ * will not schedule any recording for this program. A value of 0 indicates that the
+ * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
+ * default.
*
- * <p>Type: INTEGER
+ * <p>Type: INTEGER (boolean)
*/
- public static final String COLUMN_VERSION_NUMBER = "version_number";
+ public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
/**
* The internal ID used by individual TV input services.
@@ -1479,8 +2016,8 @@ public final class TvContract {
*
* <p>Type: INTEGER
*/
- public static final String COLUMN_PREVIEW_LAST_PLAYBACK_POSITION =
- "preview_last_playback_position";
+ public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
+ "last_playback_position_millis";
/**
* The duration (in milliseconds) of the preview video.
@@ -1491,7 +2028,7 @@ public final class TvContract {
*
* <p>Type: INTEGER
*/
- public static final String COLUMN_PREVIEW_DURATION = "preview_duration";
+ public static final String COLUMN_DURATION_MILLIS = "duration_millis";
/**
* The intent URI which is launched when the preview video is selected.
@@ -1504,8 +2041,8 @@ public final class TvContract {
*
* <p>Type: TEXT
*/
- public static final String COLUMN_PREVIEW_INTENT_URI =
- "preview_intent_uri";
+ public static final String COLUMN_APP_LINK_INTENT_URI =
+ "app_link_intent_uri";
/**
* The weight of the preview program within the channel.
@@ -1519,7 +2056,7 @@ public final class TvContract {
*
* <p>Type: INTEGER
*/
- public static final String COLUMN_PREVIEW_WEIGHT = "preview_weight";
+ public static final String COLUMN_WEIGHT = "weight";
/**
* The flag indicating whether this program is transient or not.
@@ -1535,10 +2072,94 @@ public final class TvContract {
@SystemApi
public static final String COLUMN_TRANSIENT = "transient";
+ /**
+ * The type of interaction for this TV program.
+ *
+ * <p> The value should match one of the followings:
+ * {@link #INTERACTION_TYPE_LISTENS},
+ * {@link #INTERACTION_TYPE_FOLLOWERS},
+ * {@link #INTERACTION_TYPE_FANS},
+ * {@link #INTERACTION_TYPE_LIKES},
+ * {@link #INTERACTION_TYPE_THUMBS},
+ * {@link #INTERACTION_TYPE_VIEWS}, and
+ * {@link #INTERACTION_TYPE_VIEWERS}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_INTERACTION_COUNT
+ */
+ public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+
+ /**
+ * The interaction count for this program.
+ *
+ * <p>This indicates the number of times interaction has happened.
+ *
+ * <p>Type: INTEGER
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+
+ /**
+ * The author or artist of this content.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AUTHOR = "author";
+
+ /**
+ * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
+ *
+ * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
+ * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING
+ */
+ public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+
+ /**
+ * The review rating score for this program.
+ *
+ * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
+ * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
+ * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
+ * the value should be two integers, one for thumbs-up count and the other for thumbs-down
+ * count, with a comma between them. (e.g. "200,40") If the style is
+ * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
+ * 100. (e.g. "99.9")
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String COLUMN_REVIEW_RATING = "review_rating";
+
private Programs() {}
/** Canonical genres for TV programs. */
public static final class Genres {
+ /** @hide */
+ @StringDef({
+ FAMILY_KIDS,
+ SPORTS,
+ SHOPPING,
+ MOVIES,
+ COMEDY,
+ TRAVEL,
+ DRAMA,
+ EDUCATION,
+ ANIMAL_WILDLIFE,
+ NEWS,
+ GAMING,
+ ARTS,
+ ENTERTAINMENT,
+ LIFE_STYLE,
+ MUSIC,
+ PREMIER,
+ TECH_SCIENCE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Genre {}
+
/** The genre for Family/Kids. */
public static final String FAMILY_KIDS = "FAMILY_KIDS";
@@ -1626,7 +2247,7 @@ public final class TvContract {
* @return an encoded genre string that can be inserted into the
* {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
*/
- public static String encode(@NonNull String... genres) {
+ public static String encode(@NonNull @Genre String... genres) {
if (genres == null) {
// MNC and before will throw a NPE.
return null;
@@ -1665,7 +2286,7 @@ public final class TvContract {
* {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
* @return genre strings.
*/
- public static String[] decode(@NonNull String genres) {
+ public static @Genre String[] decode(@NonNull String genres) {
if (TextUtils.isEmpty(genres)) {
// MNC and before will throw a NPE for {@code null} genres.
return EMPTY_STRING_ARRAY;
@@ -1725,7 +2346,7 @@ public final class TvContract {
* <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
* ascending order.
*/
- public static final class RecordedPrograms implements BaseTvColumns {
+ public static final class RecordedPrograms implements BaseProgramColumns {
/** The content:// style URI for this table. */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -1749,83 +2370,6 @@ public final class TvContract {
public static final String COLUMN_INPUT_ID = "input_id";
/**
- * The ID of the TV channel that provided this recorded TV program.
- *
- * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
- *
- * <p>This is a required field.
- *
- * <p>Type: INTEGER (long)
- * @see Programs#COLUMN_CHANNEL_ID
- */
- public static final String COLUMN_CHANNEL_ID = Programs.COLUMN_CHANNEL_ID;
-
- /**
- * The title of this recorded TV program.
- *
- * <p>If this recorded program is an episodic TV show, it is recommended that the title is
- * the series title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
- * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_EPISODE_DISPLAY_NUMBER},
- * and {@link #COLUMN_EPISODE_TITLE}) are filled in.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_TITLE
- */
- public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
-
- /**
- * The season display number of this recorded TV program for episodic TV shows.
- *
- * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
- * does not necessarily be numeric. (e.g. 12B)
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_SEASON_DISPLAY_NUMBER =
- Programs.COLUMN_SEASON_DISPLAY_NUMBER;
-
- /**
- * The title of the season for this recorded TV program for episodic TV shows.
- *
- * <p>This is an optional field supplied only when the season has a special title
- * (e.g. The Final Season). If provided, the applications should display it instead of
- * {@link #COLUMN_SEASON_DISPLAY_NUMBER} without alterations.
- * (e.g. for "The Final Season", displayed string should be "The Final Season", not
- * "Season The Final Season"). When displaying multiple programs, the order should be based
- * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_SEASON_TITLE = Programs.COLUMN_SEASON_TITLE;
-
- /**
- * The episode display number of this recorded TV program for episodic TV shows.
- *
- * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
- * does not necessarily be numeric. (e.g. 12B)
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_EPISODE_DISPLAY_NUMBER =
- Programs.COLUMN_EPISODE_DISPLAY_NUMBER;
-
- /**
- * The episode title of this recorded TV program for episodic TV shows.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_EPISODE_TITLE
- */
- public static final String COLUMN_EPISODE_TITLE = Programs.COLUMN_EPISODE_TITLE;
-
- /**
* The start time of the original TV program, in milliseconds since the epoch.
*
* <p>Type: INTEGER (long)
@@ -1858,154 +2402,6 @@ public final class TvContract {
public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
/**
- * The comma-separated canonical genre string of this recorded TV program.
- *
- * <p>Canonical genres are defined in {@link Programs.Genres}. Use
- * {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
- * this column. Use {@link Programs.Genres#decode Genres.decode()} to get the canonical
- * genre strings from the text stored in the column.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_CANONICAL_GENRE
- * @see Programs.Genres
- */
- public static final String COLUMN_CANONICAL_GENRE = Programs.COLUMN_CANONICAL_GENRE;
-
- /**
- * The short description of this recorded TV program that is displayed to the user by
- * default.
- *
- * <p>It is recommended to limit the length of the descriptions to 256 characters.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_SHORT_DESCRIPTION
- */
- public static final String COLUMN_SHORT_DESCRIPTION = Programs.COLUMN_SHORT_DESCRIPTION;
-
- /**
- * The detailed, lengthy description of this recorded TV program that is displayed only when
- * the user wants to see more information.
- *
- * <p>TV input services should leave this field empty if they have no additional details
- * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_LONG_DESCRIPTION
- */
- public static final String COLUMN_LONG_DESCRIPTION = Programs.COLUMN_LONG_DESCRIPTION;
-
- /**
- * The width of the video for this recorded TV program, in the unit of pixels.
- *
- * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
- * resolution of the current recorded TV program. Can be empty if it is not known or the
- * recorded program does not convey any video.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_VIDEO_WIDTH
- */
- public static final String COLUMN_VIDEO_WIDTH = Programs.COLUMN_VIDEO_WIDTH;
-
- /**
- * The height of the video for this recorded TV program, in the unit of pixels.
- *
- * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
- * resolution of the current recorded TV program. Can be empty if it is not known or the
- * recorded program does not convey any video.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_VIDEO_HEIGHT
- */
- public static final String COLUMN_VIDEO_HEIGHT = Programs.COLUMN_VIDEO_HEIGHT;
-
- /**
- * The comma-separated audio languages of this recorded TV program.
- *
- * <p>This is used to describe available audio languages included in the recorded program.
- * Use either ISO 639-1 or 639-2/T codes.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_AUDIO_LANGUAGE
- */
- public static final String COLUMN_AUDIO_LANGUAGE = Programs.COLUMN_AUDIO_LANGUAGE;
-
- /**
- * The comma-separated content ratings of this recorded TV program.
- *
- * <p>This is used to describe the content rating(s) of this recorded program. Each
- * comma-separated content rating sub-string should be generated by calling
- * {@link TvContentRating#flattenToString}. Note that in most cases the recorded program
- * content is rated by a single rating system, thus resulting in a corresponding single
- * sub-string that does not require comma separation and multiple sub-strings appear only
- * when the recorded program content is rated by two or more content rating systems. If any
- * of those ratings is specified as "blocked rating" in the user's parental control
- * settings, the TV input service should block the current content and wait for the signal
- * that it is okay to unblock.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_CONTENT_RATING
- */
- public static final String COLUMN_CONTENT_RATING = Programs.COLUMN_CONTENT_RATING;
-
- /**
- * The URI for the poster art of this recorded TV program.
- *
- * <p>The data in the column must be a URL, or a URI in one of the following formats:
- *
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_POSTER_ART_URI
- */
- public static final String COLUMN_POSTER_ART_URI = Programs.COLUMN_POSTER_ART_URI;
-
- /**
- * The URI for the thumbnail of this recorded TV program.
- *
- * <p>The system can generate a thumbnail from the poster art if this column is not
- * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
- * just a scaled image of the poster art.
- *
- * <p>The data in the column must be a URL, or a URI in one of the following formats:
- *
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- * @see Programs#COLUMN_THUMBNAIL_URI
- */
- public static final String COLUMN_THUMBNAIL_URI = Programs.COLUMN_THUMBNAIL_URI;
-
- /**
- * The flag indicating whether this recorded TV program is searchable or not.
- *
- * <p>The columns of searchable recorded programs can be read by other applications that
- * have proper permission. Care must be taken not to open sensitive data.
- *
- * <p>A value of 1 indicates that the recorded program is searchable and its columns can be
- * read by other applications, a value of 0 indicates that the recorded program is hidden
- * and its columns can be read only by the package that owns the recorded program and the
- * system. If not specified, this value is set to 1 (searchable) by default.
- *
- * <p>Type: INTEGER (boolean)
- * @see Programs#COLUMN_SEARCHABLE
- */
- public static final String COLUMN_SEARCHABLE = Programs.COLUMN_SEARCHABLE;
-
- /**
* The URI of the recording data for this recorded program.
*
* <p>Together with {@link #COLUMN_RECORDING_DATA_BYTES}, applications can use this
@@ -2055,80 +2451,6 @@ public final class TvContract {
public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS =
"recording_expire_time_utc_millis";
-
- /**
- * Internal data used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Type: BLOB
- * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
- */
- public static final String COLUMN_INTERNAL_PROVIDER_DATA =
- Programs.COLUMN_INTERNAL_PROVIDER_DATA;
-
- /**
- * Internal integer flag used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
- */
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 =
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG1;
-
- /**
- * Internal integer flag used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
- */
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 =
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG2;
-
- /**
- * Internal integer flag used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
- */
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 =
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG3;
-
- /**
- * Internal integer flag used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
- */
- public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 =
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG4;
-
- /**
- * The version number of this row entry used by TV input services.
- *
- * <p>This is best used by sync adapters to identify the rows to update. The number can be
- * defined by individual TV input services. One may assign the same value as
- * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
- * broadcast.
- *
- * <p>Type: INTEGER
- * @see Programs#COLUMN_VERSION_NUMBER
- */
- public static final String COLUMN_VERSION_NUMBER = Programs.COLUMN_VERSION_NUMBER;
-
private RecordedPrograms() {}
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 1eae8db60833..b630270f2616 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -324,6 +324,24 @@ public final class TvInputManager {
public static final String ACTION_VIEW_RECORDING_SCHEDULES =
"android.media.tv.action.VIEW_RECORDING_SCHEDULES";
+ /**
+ * Action sent by an application telling the system to set the given channel as browsable.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_CHANNEL_ID} then channel ID as an integer.
+ * <li>{@link #EXTRA_PACKAGE_NAME} the package name of the requesting application.
+ * </ul>
+ */
+ public static final String ACTION_MAKE_CHANNEL_BROWSABLE
+ = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+
+ /** The key for a bundle parameter containing a channel ID as an integer */
+ public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+
+ /** The key for a bundle parameter containing a package name as a string. */
+ public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+
private final ITvInputManager mService;
private final Object mLock = new Object();
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 8d4271f637a2..f69313c07c56 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \
android_media_MediaDrm.cpp \
android_media_MediaExtractor.cpp \
android_media_MediaHTTPConnection.cpp \
+ android_media_MediaMetricsJNI.cpp \
android_media_MediaMetadataRetriever.cpp \
android_media_MediaMuxer.cpp \
android_media_MediaPlayer.cpp \
diff --git a/media/jni/android_media_BufferingParams.h b/media/jni/android_media_BufferingParams.h
new file mode 100644
index 000000000000..24c51f5f00d4
--- /dev/null
+++ b/media/jni/android_media_BufferingParams.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+#define _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+
+#include <media/BufferingSettings.h>
+
+namespace android {
+
+// This entire class is inline
+struct BufferingParams {
+ BufferingSettings settings;
+
+ struct fields_t {
+ jclass clazz;
+ jmethodID constructID;
+
+ jfieldID initial_buffering_mode;
+ jfieldID rebuffering_mode;
+ jfieldID initial_watermark_ms;
+ jfieldID initial_watermark_kb;
+ jfieldID rebuffering_watermark_low_ms;
+ jfieldID rebuffering_watermark_high_ms;
+ jfieldID rebuffering_watermark_low_kb;
+ jfieldID rebuffering_watermark_high_kb;
+
+ void init(JNIEnv *env) {
+ jclass lclazz = env->FindClass("android/media/BufferingParams");
+ if (lclazz == NULL) {
+ return;
+ }
+
+ clazz = (jclass)env->NewGlobalRef(lclazz);
+ if (clazz == NULL) {
+ return;
+ }
+
+ constructID = env->GetMethodID(clazz, "<init>", "()V");
+
+ initial_buffering_mode = env->GetFieldID(clazz, "mInitialBufferingMode", "I");
+ rebuffering_mode = env->GetFieldID(clazz, "mRebufferingMode", "I");
+ initial_watermark_ms = env->GetFieldID(clazz, "mInitialWatermarkMs", "I");
+ initial_watermark_kb = env->GetFieldID(clazz, "mInitialWatermarkKB", "I");
+ rebuffering_watermark_low_ms = env->GetFieldID(clazz, "mRebufferingWatermarkLowMs", "I");
+ rebuffering_watermark_high_ms = env->GetFieldID(clazz, "mRebufferingWatermarkHighMs", "I");
+ rebuffering_watermark_low_kb = env->GetFieldID(clazz, "mRebufferingWatermarkLowKB", "I");
+ rebuffering_watermark_high_kb = env->GetFieldID(clazz, "mRebufferingWatermarkHighKB", "I");
+
+ env->DeleteLocalRef(lclazz);
+ }
+
+ void exit(JNIEnv *env) {
+ env->DeleteGlobalRef(clazz);
+ clazz = NULL;
+ }
+ };
+
+ void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject params) {
+ settings.mInitialBufferingMode =
+ (BufferingMode)env->GetIntField(params, fields.initial_buffering_mode);
+ settings.mRebufferingMode =
+ (BufferingMode)env->GetIntField(params, fields.rebuffering_mode);
+ settings.mInitialWatermarkMs =
+ env->GetIntField(params, fields.initial_watermark_ms);
+ settings.mInitialWatermarkKB =
+ env->GetIntField(params, fields.initial_watermark_kb);
+ settings.mRebufferingWatermarkLowMs =
+ env->GetIntField(params, fields.rebuffering_watermark_low_ms);
+ settings.mRebufferingWatermarkHighMs =
+ env->GetIntField(params, fields.rebuffering_watermark_high_ms);
+ settings.mRebufferingWatermarkLowKB =
+ env->GetIntField(params, fields.rebuffering_watermark_low_kb);
+ settings.mRebufferingWatermarkHighKB =
+ env->GetIntField(params, fields.rebuffering_watermark_high_kb);
+ }
+
+ jobject asJobject(JNIEnv *env, const fields_t& fields) {
+ jobject params = env->NewObject(fields.clazz, fields.constructID);
+ if (params == NULL) {
+ return NULL;
+ }
+ env->SetIntField(params, fields.initial_buffering_mode, (jint)settings.mInitialBufferingMode);
+ env->SetIntField(params, fields.rebuffering_mode, (jint)settings.mRebufferingMode);
+ env->SetIntField(params, fields.initial_watermark_ms, (jint)settings.mInitialWatermarkMs);
+ env->SetIntField(params, fields.initial_watermark_kb, (jint)settings.mInitialWatermarkKB);
+ env->SetIntField(params, fields.rebuffering_watermark_low_ms, (jint)settings.mRebufferingWatermarkLowMs);
+ env->SetIntField(params, fields.rebuffering_watermark_high_ms, (jint)settings.mRebufferingWatermarkHighMs);
+ env->SetIntField(params, fields.rebuffering_watermark_low_kb, (jint)settings.mRebufferingWatermarkLowKB);
+ env->SetIntField(params, fields.rebuffering_watermark_high_kb, (jint)settings.mRebufferingWatermarkHighKB);
+
+ return params;
+ }
+};
+
+} // namespace android
+
+#endif // _ANDROID_MEDIA_BUFFERING_PARAMS_H_
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index c2c66fdb6ca9..6f9883c08050 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -21,6 +21,7 @@
#include "android_media_MediaCodec.h"
#include "android_media_MediaCrypto.h"
+#include "android_media_MediaMetricsJNI.h"
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
@@ -618,6 +619,12 @@ status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
return OK;
}
+status_t JMediaCodec::getMetrics(JNIEnv *, Parcel *reply) const {
+
+ status_t status = mCodec->getMetrics(reply);
+ return status;
+}
+
status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
return mCodec->setParameters(msg);
}
@@ -1646,6 +1653,37 @@ static jobject android_media_MediaCodec_getName(
return NULL;
}
+static jobject
+android_media_MediaCodec_getMetrics(JNIEnv *env, jobject thiz)
+{
+ ALOGV("android_media_MediaCodec_getMetrics");
+
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+ if (codec == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return 0;
+ }
+
+ // get what we have for the metrics from the codec
+ Parcel reply;
+ status_t err = codec->getMetrics(env, &reply);
+ if (err != OK) {
+ ALOGE("getMetrics failed");
+ return (jobject) NULL;
+ }
+
+ // build and return the Bundle
+ MediaAnalyticsItem *item = new MediaAnalyticsItem;
+ item->readFromParcel(reply);
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
+
static void android_media_MediaCodec_setParameters(
JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
ALOGV("android_media_MediaCodec_setParameters");
@@ -1954,6 +1992,9 @@ static const JNINativeMethod gMethods[] = {
{ "getName", "()Ljava/lang/String;",
(void *)android_media_MediaCodec_getName },
+ { "getMetrics", "()Landroid/os/Bundle;",
+ (void *)android_media_MediaCodec_getMetrics},
+
{ "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
(void *)android_media_MediaCodec_setParameters },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 5f0d3df17360..b3b1b3a87ba4 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -111,6 +111,8 @@ struct JMediaCodec : public AHandler {
status_t getName(JNIEnv *env, jstring *name) const;
+ status_t getMetrics(JNIEnv *env, Parcel *reply) const;
+
status_t setParameters(const sp<AMessage> &params);
void setVideoScalingMode(int mode);
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7a98c954747f..ea35f78a3a7a 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -335,9 +335,10 @@ static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
}
JDrm::JDrm(
- JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
+ JNIEnv *env, jobject thiz, const uint8_t uuid[16],
+ const String8 &appPackageName) {
mObject = env->NewWeakGlobalRef(thiz);
- mDrm = MakeDrm(uuid);
+ mDrm = MakeDrm(uuid, appPackageName);
if (mDrm != NULL) {
mDrm->setListener(this);
}
@@ -369,14 +370,14 @@ sp<IDrm> JDrm::MakeDrm() {
}
// static
-sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
+sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
sp<IDrm> drm = MakeDrm();
if (drm == NULL) {
return NULL;
}
- status_t err = drm->createPlugin(uuid);
+ status_t err = drm->createPlugin(uuid, appPackageName);
if (err != OK) {
return NULL;
@@ -683,7 +684,7 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
static void android_media_MediaDrm_native_setup(
JNIEnv *env, jobject thiz,
- jobject weak_this, jbyteArray uuidObj) {
+ jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
if (uuidObj == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
@@ -698,7 +699,15 @@ static void android_media_MediaDrm_native_setup(
return;
}
- sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
+ String8 packageName;
+ if (jappPackageName == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "application package name cannot be null");
+ return;
+ }
+
+ packageName = JStringToString8(env, jappPackageName);
+ sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
status_t err = drm->initCheck();
@@ -1439,7 +1448,7 @@ static const JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
- { "native_setup", "(Ljava/lang/Object;[B)V",
+ { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
(void *)android_media_MediaDrm_native_setup },
{ "native_finalize", "()V",
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index b7b8e5dd6b6c..b9356f30bae8 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -39,7 +39,7 @@ public:
struct JDrm : public BnDrmClient {
static bool IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
- JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
+ JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16], const String8 &appPackageName);
status_t initCheck() const;
sp<IDrm> getDrm() { return mDrm; }
@@ -61,7 +61,7 @@ private:
Mutex mLock;
static sp<IDrm> MakeDrm();
- static sp<IDrm> MakeDrm(const uint8_t uuid[16]);
+ static sp<IDrm> MakeDrm(const uint8_t uuid[16], const String8 &appPackageName);
DISALLOW_EVIL_CONSTRUCTORS(JDrm);
};
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
new file mode 100644
index 000000000000..fb606bac7828
--- /dev/null
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include "android_media_MediaMetricsJNI.h"
+#include <media/MediaAnalyticsItem.h>
+
+
+namespace android {
+
+// place the attributes into a java Bundle object
+// decide whether this is appropriately scoped here.
+// if we do it somewhere else, we have to figure a "give me all the attrs"
+// access to the inside of MediaAnalyticsItem
+jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) {
+
+ jclass clazzBundle = env->FindClass("android/os/Bundle");
+ if (clazzBundle==NULL) {
+ ALOGD("can't find android/os/Bundle");
+ return NULL;
+ }
+ // sometimes the caller provides one for us to fill
+ if (mybundle == NULL) {
+ // create the bundle
+ jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V");
+ mybundle = env->NewObject(clazzBundle, constructID);
+ if (mybundle == NULL) {
+ return NULL;
+ }
+ }
+
+ // grab methods that we can invoke
+ jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V");
+ jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V");
+ jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V");
+ jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
+
+ // env, class, method, {parms}
+ //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint);
+
+ // iterate through my attributes
+ // -- get name, get type, get value
+ // -- insert appropriately into the bundle
+ for (size_t i = 0 ; i < item->mPropCount; i++ ) {
+ MediaAnalyticsItem::Prop *prop = &item->mProps[i];
+ // build the key parameter from prop->mName
+ jstring keyName = env->NewStringUTF(prop->mName);
+ // invoke the appropriate method to insert
+ switch (prop->mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ env->CallVoidMethod(mybundle, setIntID,
+ keyName, (jint) prop->u.int32Value);
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ env->CallVoidMethod(mybundle, setLongID,
+ keyName, (jlong) prop->u.int64Value);
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ env->CallVoidMethod(mybundle, setDoubleID,
+ keyName, (jdouble) prop->u.doubleValue);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ env->CallVoidMethod(mybundle, setStringID, keyName,
+ env->NewStringUTF(prop->u.CStringValue));
+ break;
+ default:
+ ALOGE("to_String bad item type: %d for %s",
+ prop->mType, prop->mName);
+ break;
+ }
+ }
+
+ return mybundle;
+}
+
+}; // namespace android
+
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
new file mode 100644
index 000000000000..d1742121277b
--- /dev/null
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
+#define _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <media/MediaAnalyticsItem.h>
+
+namespace android {
+
+class MediaMetricsJNI {
+public:
+ static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle);
+};
+
+}; // namespace android
+
+#endif // _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 216624e96ad2..c3461f0aa57c 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -23,6 +23,9 @@
#include "jni.h"
#include "JNIHelp.h"
+#include <unistd.h>
+#include <fcntl.h>
+
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -138,6 +141,28 @@ static jlong android_media_MediaMuxer_native_setup(
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
ALOGV("native_setup: fd %d", fd);
+ // It appears that if an invalid file descriptor is passed through
+ // binder calls, the server-side of the inter-process function call
+ // is skipped. As a result, the check at the server-side to catch
+ // the invalid file descritpor never gets invoked. This is to workaround
+ // this issue by checking the file descriptor first before passing
+ // it through binder call.
+ int flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ ALOGE("Fail to get File Status Flags err: %s", strerror(errno));
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid file descriptor");
+ return 0;
+ }
+
+ // fd must be in read-write mode or write-only mode.
+ if ((flags & (O_RDWR | O_WRONLY)) == 0) {
+ ALOGE("File descriptor is not in read-write mode or write-only mode");
+ jniThrowException(env, "java/io/IOException",
+ "File descriptor is not in read-write mode or write-only mode");
+ return 0;
+ }
+
MediaMuxer::OutputFormat fileFormat =
static_cast<MediaMuxer::OutputFormat>(format);
sp<MediaMuxer> muxer = new MediaMuxer(fd, fileFormat);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c52ed941af85..5e8135f5d4b2 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -23,6 +23,8 @@
#include <media/AudioResamplerPublic.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaPlayerInterface.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/stagefright/Utils.h> // for FOURCC definition
#include <stdio.h>
#include <assert.h>
#include <limits.h>
@@ -37,7 +39,9 @@
#include "utils/Errors.h" // for status_t
#include "utils/KeyedVector.h"
#include "utils/String8.h"
+#include "android_media_BufferingParams.h"
#include "android_media_MediaDataSource.h"
+#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
#include "android_media_SyncParams.h"
#include "android_media_Utils.h"
@@ -51,6 +55,90 @@
#include <binder/IServiceManager.h>
#include "android_util_Binder.h"
+
+// Modular DRM begin
+#include <media/drm/DrmAPI.h>
+
+#define FIND_CLASS(var, className) \
+var = env->FindClass(className); \
+LOG_FATAL_IF(! (var), "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
+
+#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
+LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
+
+#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
+LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
+
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+struct RequestFields {
+ jfieldID data;
+ jfieldID defaultUrl;
+ jfieldID requestType;
+};
+
+struct HashmapFields {
+ jmethodID init;
+ jmethodID get;
+ jmethodID put;
+ jmethodID entrySet;
+};
+
+struct SetFields {
+ jmethodID iterator;
+};
+
+struct IteratorFields {
+ jmethodID next;
+ jmethodID hasNext;
+};
+
+struct EntryFields {
+ jmethodID getKey;
+ jmethodID getValue;
+};
+
+struct KeyTypes {
+ jint kKeyTypeStreaming;
+ jint kKeyTypeOffline;
+ jint kKeyTypeRelease;
+};
+
+static KeyTypes gKeyTypes;
+
+struct KeyRequestTypes {
+ jint kKeyRequestTypeInitial;
+ jint kKeyRequestTypeRenewal;
+ jint kKeyRequestTypeRelease;
+};
+
+static KeyRequestTypes gKeyRequestTypes;
+
+struct StateExceptionFields {
+ jmethodID init;
+ jclass classId;
+};
+
+struct drm_fields_t {
+ RequestFields keyRequest;
+ HashmapFields hashmap;
+ SetFields set;
+ IteratorFields iterator;
+ EntryFields entry;
+ StateExceptionFields stateException;
+ jclass stringClassId;
+};
+
+static drm_fields_t gFields;
+
+// Modular DRM end
+
// ----------------------------------------------------------------------------
using namespace android;
@@ -69,6 +157,7 @@ struct fields_t {
};
static fields_t fields;
+static BufferingParams::fields_t gBufferingParamsFields;
static PlaybackParams::fields_t gPlaybackParamsFields;
static SyncParams::fields_t gSyncParamsFields;
@@ -343,6 +432,66 @@ android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsu
setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
}
+static jobject
+android_media_MediaPlayer_getDefaultBufferingParams(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ BufferingParams bp;
+ BufferingSettings &settings = bp.settings;
+ process_media_player_call(
+ env, thiz, mp->getDefaultBufferingSettings(&settings),
+ "java/lang/IllegalStateException", "unexpected error");
+ ALOGV("getDefaultBufferingSettings:{%s}", settings.toString().string());
+
+ return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static jobject
+android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ BufferingParams bp;
+ BufferingSettings &settings = bp.settings;
+ process_media_player_call(
+ env, thiz, mp->getBufferingSettings(&settings),
+ "java/lang/IllegalStateException", "unexpected error");
+ ALOGV("getBufferingSettings:{%s}", settings.toString().string());
+
+ return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static void
+android_media_MediaPlayer_setBufferingParams(JNIEnv *env, jobject thiz, jobject params)
+{
+ if (params == NULL) {
+ return;
+ }
+
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ BufferingParams bp;
+ bp.fillFromJobject(env, gBufferingParamsFields, params);
+ ALOGV("setBufferingParams:{%s}", bp.settings.toString().string());
+
+ process_media_player_call(
+ env, thiz, mp->setBufferingSettings(bp.settings),
+ "java/lang/IllegalStateException", "unexpected error");
+}
+
static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{
@@ -622,6 +771,33 @@ android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
return (jint) h;
}
+static jobject
+android_media_MediaPlayer_getMetrics(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return 0;
+ }
+
+ Parcel p;
+ int key = FOURCC('m','t','r','X');
+ status_t status = mp->getParameter(key, &p);
+ if (status != OK) {
+ ALOGD("getMetrics() failed: %d", status);
+ return (jobject) NULL;
+ }
+
+ MediaAnalyticsItem *item = new MediaAnalyticsItem;
+ item->readFromParcel(p);
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
static jint
android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
@@ -860,6 +1036,56 @@ android_media_MediaPlayer_native_init(JNIEnv *env)
env->DeleteLocalRef(clazz);
+ gBufferingParamsFields.init(env);
+
+ // Modular DRM
+ FIND_CLASS(clazz, "android/media/MediaDrm");
+ if (clazz) {
+ jfieldID field;
+ GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
+ gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
+ gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
+ gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
+
+ env->DeleteLocalRef(clazz);
+ } else {
+ ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
+ "get clazz android/media/MediaDrm");
+ }
+
+ FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
+ if (clazz) {
+ GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
+ GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
+
+ jfieldID field;
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
+ gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
+
+ env->DeleteLocalRef(clazz);
+ } else {
+ ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
+ "get clazz android/media/MediaDrm$KeyRequest");
+ }
+
+ FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
+ if (clazz) {
+ GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+ gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ env->DeleteLocalRef(clazz);
+ } else {
+ ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
+ "get clazz android/media/MediaDrm$MediaDrmStateException");
+ }
+
gPlaybackParamsFields.init(env);
gSyncParamsFields.init(env);
}
@@ -1033,6 +1259,441 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject
;
}
+/////////////////////////////////////////////////////////////////////////////////////
+// Modular DRM begin
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err)
+{
+ ALOGE("Illegal DRM state exception: %s (%d)", msg, err);
+
+ jobject exception = env->NewObject(gFields.stateException.classId,
+ gFields.stateException.init, static_cast<int>(err),
+ env->NewStringUTF(msg));
+ env->Throw(static_cast<jthrowable>(exception));
+}
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *msg = NULL)
+{
+ const char *drmMessage = "Unknown DRM Msg";
+
+ switch (err) {
+ case ERROR_DRM_UNKNOWN:
+ drmMessage = "General DRM error";
+ break;
+ case ERROR_DRM_NO_LICENSE:
+ drmMessage = "No license";
+ break;
+ case ERROR_DRM_LICENSE_EXPIRED:
+ drmMessage = "License expired";
+ break;
+ case ERROR_DRM_SESSION_NOT_OPENED:
+ drmMessage = "Session not opened";
+ break;
+ case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
+ drmMessage = "Not initialized";
+ break;
+ case ERROR_DRM_DECRYPT:
+ drmMessage = "Decrypt error";
+ break;
+ case ERROR_DRM_CANNOT_HANDLE:
+ drmMessage = "Unsupported scheme or data format";
+ break;
+ case ERROR_DRM_TAMPER_DETECTED:
+ drmMessage = "Invalid state";
+ break;
+ default:
+ break;
+ }
+
+ String8 vendorMessage;
+ if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
+ vendorMessage = String8::format("DRM vendor-defined error: %d", err);
+ drmMessage = vendorMessage.string();
+ }
+
+ if (err == BAD_VALUE) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ return true;
+ } else if (err == ERROR_DRM_NOT_PROVISIONED) {
+ jniThrowException(env, "android/media/NotProvisionedException", msg);
+ return true;
+ } else if (err == ERROR_DRM_RESOURCE_BUSY) {
+ jniThrowException(env, "android/media/ResourceBusyException", msg);
+ return true;
+ } else if (err == ERROR_DRM_DEVICE_REVOKED) {
+ jniThrowException(env, "android/media/DeniedByServerException", msg);
+ return true;
+ } else if (err == DEAD_OBJECT) {
+ jniThrowException(env, "android/media/MediaDrmResetException",
+ "mediaserver died");
+ return true;
+ } else if (err != OK) {
+ String8 errbuf;
+ if (drmMessage != NULL) {
+ if (msg == NULL) {
+ msg = drmMessage;
+ } else {
+ errbuf = String8::format("%s: %s", msg, drmMessage);
+ msg = errbuf.string();
+ }
+ }
+ throwDrmStateException(env, msg, err);
+ return true;
+ }
+ return false;
+}
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector)
+{
+ size_t length = vector.size();
+ jbyteArray result = env->NewByteArray(length);
+ if (result != NULL) {
+ env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
+ }
+ return result;
+}
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
+{
+ Vector<uint8_t> vector;
+ size_t length = env->GetArrayLength(byteArray);
+ vector.insertAt((size_t)0, length);
+ env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
+ return vector;
+}
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static String8 JStringToString8(JNIEnv *env, jstring const &jstr)
+{
+ String8 result;
+
+ const char *s = env->GetStringUTFChars(jstr, NULL);
+ if (s) {
+ result = s;
+ env->ReleaseStringUTFChars(jstr, s);
+ }
+ return result;
+}
+
+// TODO: investigate if these can be shared with their MediaDrm counterparts
+static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env,
+ jobject &hashMap, bool* pIsOK)
+{
+ jclass clazz = gFields.stringClassId;
+ KeyedVector<String8, String8> keyedVector;
+ *pIsOK = true;
+
+ jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
+ if (entrySet) {
+ jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
+ if (iterator) {
+ jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+ while (hasNext) {
+ jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
+ if (entry) {
+ jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
+ if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "HashMap key is not a String");
+ env->DeleteLocalRef(entry);
+ *pIsOK = false;
+ break;
+ }
+ jstring jkey = static_cast<jstring>(obj);
+
+ obj = env->CallObjectMethod(entry, gFields.entry.getValue);
+ if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "HashMap value is not a String");
+ env->DeleteLocalRef(entry);
+ *pIsOK = false;
+ break;
+ }
+ jstring jvalue = static_cast<jstring>(obj);
+
+ String8 key = JStringToString8(env, jkey);
+ String8 value = JStringToString8(env, jvalue);
+ keyedVector.add(key, value);
+
+ env->DeleteLocalRef(jkey);
+ env->DeleteLocalRef(jvalue);
+ hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+ }
+ env->DeleteLocalRef(entry);
+ }
+ env->DeleteLocalRef(iterator);
+ }
+ env->DeleteLocalRef(entrySet);
+ }
+ return keyedVector;
+}
+
+static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
+ jbyteArray uuidObj, jint mode)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (uuidObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
+
+ if (uuid.size() != 16) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "invalid UUID size, expected 16 bytes");
+ return;
+ }
+
+ status_t err = mp->prepareDrm(uuid.array(), mode);
+ if (err != OK) {
+ if (err == INVALID_OPERATION) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalStateException",
+ "The player is not prepared yet.");
+ } else if (err == ERROR_DRM_CANNOT_HANDLE) {
+ jniThrowException(
+ env,
+ "android/media/UnsupportedSchemeException",
+ "Failed to instantiate drm object.");
+ } else {
+ throwDrmExceptionAsNecessary(env, err, "Failed to prepare DRM scheme");
+ }
+ }
+}
+
+static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ status_t err = mp->releaseDrm();
+ if (err != OK) {
+ if (err == INVALID_OPERATION) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalStateException",
+ "The player is not prepared yet.");
+ }
+ }
+}
+
+static jobject android_media_MediaPlayer_getKeyRequest(JNIEnv *env, jobject thiz, jbyteArray jscope,
+ jstring jmimeType, jint jkeyType, jobject joptParams)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> scope;
+ if (jscope != NULL) {
+ scope = JByteArrayToVector(env, jscope);
+ }
+
+ String8 mimeType;
+ if (jmimeType != NULL) {
+ mimeType = JStringToString8(env, jmimeType);
+ }
+
+ DrmPlugin::KeyType keyType;
+ if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
+ keyType = DrmPlugin::kKeyType_Streaming;
+ } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
+ keyType = DrmPlugin::kKeyType_Offline;
+ } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
+ keyType = DrmPlugin::kKeyType_Release;
+ } else {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType");
+ return NULL;
+ }
+
+ KeyedVector<String8, String8> optParams;
+ if (joptParams != NULL) {
+ bool isOK;
+ optParams = HashMapToKeyedVector(env, joptParams, &isOK);
+ if (!isOK) {
+ return NULL;
+ }
+ }
+
+ Vector<uint8_t> request;
+ String8 defaultUrl;
+ DrmPlugin::KeyRequestType keyRequestType;
+ status_t err = mp->getKeyRequest(scope, mimeType, keyType, optParams, request, defaultUrl,
+ keyRequestType);
+
+ if (throwDrmExceptionAsNecessary(env, err, "Failed to get key request")) {
+ return NULL;
+ }
+
+ ALOGV("JNI getKeyRequest err %d request %d url %s keyReqType %d",
+ err, (int)request.size(), defaultUrl.string(), (int)keyRequestType);
+
+ // Fill out return obj
+ jclass clazz;
+ FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
+
+ jobject keyObj = NULL;
+
+ if (clazz) {
+ keyObj = env->AllocObject(clazz);
+ jbyteArray jrequest = VectorToJByteArray(env, request);
+ env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
+
+ jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+ env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
+
+ switch (keyRequestType) {
+ case DrmPlugin::kKeyRequestType_Initial:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeInitial);
+ break;
+ case DrmPlugin::kKeyRequestType_Renewal:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeRenewal);
+ break;
+ case DrmPlugin::kKeyRequestType_Release:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeRelease);
+ break;
+ default:
+ throwDrmStateException(env, "MediaPlayer/DRM plugin failure: unknown "
+ "key request type", ERROR_DRM_UNKNOWN);
+ break;
+ }
+ }
+
+ return keyObj;
+}
+
+static jbyteArray android_media_MediaPlayer_provideKeyResponse(JNIEnv *env, jobject thiz,
+ jbyteArray jreleaseKeySetId, jbyteArray jresponse)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ if (jresponse == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "key response is null");
+ return NULL;
+ }
+
+ Vector<uint8_t> releaseKeySetId;
+ if (jreleaseKeySetId != NULL) {
+ releaseKeySetId = JByteArrayToVector(env, jreleaseKeySetId);
+ }
+
+ Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+ Vector<uint8_t> keySetId;
+
+ status_t err = mp->provideKeyResponse(releaseKeySetId, response, keySetId);
+
+ if (throwDrmExceptionAsNecessary(env, err, "Failed to handle key response")) {
+ return NULL;
+ }
+ return VectorToJByteArray(env, keySetId);
+}
+
+static void android_media_MediaPlayer_restoreKeys(JNIEnv *env, jobject thiz, jbyteArray jkeySetId)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (jkeySetId == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType");
+ return;
+ }
+
+ Vector<uint8_t> keySetId;
+ keySetId = JByteArrayToVector(env, jkeySetId);
+
+ status_t err = mp->restoreKeys(keySetId);
+
+ ALOGV("JNI restoreKeys err %d ", err);
+ throwDrmExceptionAsNecessary(env, err, "Failed to restore keys");
+}
+
+static jstring android_media_MediaPlayer_getDrmPropertyString(JNIEnv *env, jobject thiz,
+ jstring jname)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ if (jname == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "property name String is null");
+ return NULL;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ String8 value;
+
+ status_t err = mp->getDrmPropertyString(name, value);
+
+ ALOGV("JNI getPropertyString err %d", err);
+
+ if (throwDrmExceptionAsNecessary(env, err, "Failed to get property")) {
+ return NULL;
+ }
+
+ return env->NewStringUTF(value.string());
+}
+
+static void android_media_MediaPlayer_setDrmPropertyString(JNIEnv *env, jobject thiz,
+ jstring jname, jstring jvalue)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (jname == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "property name String is null");
+ return;
+ }
+
+ if (jvalue == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "property value String is null");
+ return;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ String8 value = JStringToString8(env, jvalue);
+
+ status_t err = mp->setDrmPropertyString(name, value);
+
+ ALOGV("JNI setPropertyString err %d", err);
+ throwDrmExceptionAsNecessary(env, err, "Failed to set property");
+}
+// Modular DRM end
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -1046,12 +1707,16 @@ static const JNINativeMethod gMethods[] = {
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
+ {"getDefaultBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getDefaultBufferingParams},
+ {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
+ {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
{"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer_start},
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
+ {"getMetrics", "()Landroid/os/Bundle;", (void *)android_media_MediaPlayer_getMetrics},
{"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
{"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
{"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams},
@@ -1082,6 +1747,15 @@ static const JNINativeMethod gMethods[] = {
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
{"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
{"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},
+ // Modular DRM
+ { "_prepareDrm", "([BI)V", (void *)android_media_MediaPlayer_prepareDrm },
+ { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm },
+ { "_getKeyRequest", "([BLjava/lang/String;ILjava/util/Map;)" "Landroid/media/MediaDrm$KeyRequest;",
+ (void *)android_media_MediaPlayer_getKeyRequest },
+ { "_provideKeyResponse", "([B[B)[B", (void *)android_media_MediaPlayer_provideKeyResponse },
+ { "_getDrmPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaPlayer_getDrmPropertyString },
+ { "_setDrmPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_setDrmPropertyString },
+ { "_restoreKeys", "([B)V", (void *)android_media_MediaPlayer_restoreKeys },
};
// This function only registers the native methods
diff --git a/media/mca/effect/java/android/media/effect/package.html b/media/mca/effect/java/android/media/effect/package.html
index 8a210fd89f03..1d297ef8dd62 100644
--- a/media/mca/effect/java/android/media/effect/package.html
+++ b/media/mca/effect/java/android/media/effect/package.html
@@ -24,7 +24,7 @@ EffectContext.createWithCurrentGlContext()} from your OpenGL ES 2.0 context.</li
android.media.effect.EffectContext#getFactory EffectContext.getFactory()}, which returns an instance
of {@link android.media.effect.EffectFactory}.</li>
<li>Call {@link android.media.effect.EffectFactory#createEffect createEffect()}, passing it an
-effect name from @link android.media.effect.EffectFactory}, such as {@link
+effect name from {@link android.media.effect.EffectFactory}, such as {@link
android.media.effect.EffectFactory#EFFECT_FISHEYE} or {@link
android.media.effect.EffectFactory#EFFECT_VIGNETTE}.</li>
</ol>
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 355f52e1b7e4..f510b488548e 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -1,6 +1,8 @@
BASE_PATH := $(call my-dir)
LOCAL_PATH:= $(call my-dir)
+common_cflags := -Wall -Werror -Wunused -Wunreachable-code
+
include $(CLEAR_VARS)
# our source files
@@ -43,6 +45,23 @@ LOCAL_C_INCLUDES += \
LOCAL_MODULE := libandroid
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += $(common_cflags)
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Network library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libandroid_net
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES:= \
+ net.c \
+
+LOCAL_SHARED_LIBRARIES := \
+ libnetd_client \
+
+LOCAL_C_INCLUDES += \
+ frameworks/base/native/include \
+ bionic/libc/dns/include \
+ system/netd/include \
include $(BUILD_SHARED_LIBRARY)
diff --git a/native/android/hardware_buffer.cpp b/native/android/hardware_buffer.cpp
index 6a10cb587be2..e5e928dee2a7 100644
--- a/native/android/hardware_buffer.cpp
+++ b/native/android/hardware_buffer.cpp
@@ -26,10 +26,11 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <binder/Binder.h>
#include <binder/Parcel.h>
-#include <cutils/native_handle.h>
#include <binder/IServiceManager.h>
+#include <cutils/native_handle.h>
#include <gui/ISurfaceComposer.h>
#include <gui/IGraphicBufferAlloc.h>
+#include <hardware/gralloc1.h>
#include <ui/GraphicBuffer.h>
#include <utils/Flattenable.h>
#include <utils/Log.h>
@@ -89,11 +90,21 @@ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
return BAD_VALUE;
}
+ if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
+ ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB "
+ "format");
+ return BAD_VALUE;
+ }
+
status_t err;
- uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- desc->usage0, desc->usage1);
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ android_hardware_HardwareBuffer_convertToGrallocUsageBits(desc->usage0,
+ desc->usage1, &producerUsage, &consumerUsage);
sp<GraphicBuffer> gbuffer = allocator->createGraphicBuffer(desc->width,
- desc->height, format, desc->layers, usage, &err);
+ desc->height, format, desc->layers, producerUsage, consumerUsage,
+ std::string("AHardwareBuffer pid [") + std::to_string(getpid()) +
+ "]", &err);
if (err != NO_ERROR) {
return err;
}
@@ -125,7 +136,7 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
outDesc->layers = gbuffer->getLayerCount();
outDesc->usage0 =
android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- gbuffer->getUsage());
+ gbuffer->getUsage(), gbuffer->getUsage());
outDesc->usage1 = 0;
outDesc->format = android_hardware_HardwareBuffer_convertFromPixelFormat(
static_cast<uint32_t>(gbuffer->getPixelFormat()));
@@ -142,15 +153,19 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
return BAD_VALUE;
}
- uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- usage0, 0);
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage0, 0,
+ &producerUsage, &consumerUsage);
GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+ Rect bounds;
if (!rect) {
- return gBuffer->lockAsync(usage, outVirtualAddress, fence);
+ bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
} else {
- Rect bounds(rect->left, rect->top, rect->right, rect->bottom);
- return gBuffer->lockAsync(usage, bounds, outVirtualAddress, fence);
+ bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
}
+ return gBuffer->lockAsync(producerUsage, consumerUsage, bounds,
+ outVirtualAddress, fence);
}
int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
diff --git a/opengl/java/android/opengl/GLU.java b/opengl/java/android/opengl/GLU.java
index ed6455689e44..ef9bf16747a4 100644
--- a/opengl/java/android/opengl/GLU.java
+++ b/opengl/java/android/opengl/GLU.java
@@ -203,8 +203,8 @@ public class GLU {
* @param view the current view, {x, y, width, height}
* @param viewOffset the offset into the view array where the view vector
* data starts.
- * @param obj the output vector {objX, objY, objZ}, that returns the
- * computed object coordinates.
+ * @param obj the output vector {objX, objY, objZ, objW}, that returns the
+ * computed homogeneous object coordinates.
* @param objOffset the offset into the obj array where the obj vector data
* starts.
* @return A return value of GL10.GL_TRUE indicates success, a return value
diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml
new file mode 100644
index 000000000000..eb330a5d641b
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-af/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktiveer jou diens"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Geen datadiens nie"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tik om jou diens te aktiveer"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Geen diens nie – kontak asseblief jou diensverskaffer"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Koppel aan kontoleringsportaal …"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Netwerk-uitteltyd – wil jy dalk weer probeer?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Netwerk onbeskikbaar"</string>
+ <string name="quit" msgid="4392968039488794590">"Verlaat"</string>
+ <string name="wait" msgid="7902715035629500128">"Wag"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-am/strings.xml b/packages/CarrierDefaultApp/res/values-am/strings.xml
new file mode 100644
index 000000000000..fc62e8d1c081
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-am/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"አገልግሎትዎን ያግብሩ"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ምንም የውሂብ አገልግሎት የለም"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"አገልግሎትዎን ለማግበር መታ ያድርጉ"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"ምንም አገልግሎት የለም፣ እባክዎ የአገልግሎት አቅራቢዎን ያነጋግሩ"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"ከተያዥ መግቢያ ጋር በመገናኘት ላይ..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"አውታረ መረብ የእረፍት ጊዜ ወስዷል፣ እንደገና መሞከር ይፈልጋሉ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"አውታረ መረብ አይገኝም"</string>
+ <string name="quit" msgid="4392968039488794590">"አቁም"</string>
+ <string name="wait" msgid="7902715035629500128">"ይጠብቁ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml
new file mode 100644
index 000000000000..3903c35e35b6
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"تنشيط الخدمة"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ليست هناك خدمة بيانات"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"انقر لتنشيط الخدمة"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"ليست هناك خدمة، يرجى الاتصال بمقدم الخدمة"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"جارٍ الاتصال بالمدخل المقيد الوصول..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"انتهت مهلة الشبكة، هل ترغب في إعادة المحاولة؟"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"الشبكة غير متاحة"</string>
+ <string name="quit" msgid="4392968039488794590">"إنهاء"</string>
+ <string name="wait" msgid="7902715035629500128">"انتظار"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml
new file mode 100644
index 000000000000..90d7f09dde50
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-az/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Xidməti aktiv edin"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Data xidməti yoxdur"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Xidməti aktiv etmək üçün klikləyin"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Xidmət yoxdur, xidmət provayderi ilə əlaqə saxlayın"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Avtorizasiya portalına qoşulur..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Şəbəkə zaman aşımı, yenidən cəhd etmək istərdiniz?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Şəbəkə yoxdur"</string>
+ <string name="quit" msgid="4392968039488794590">"Tərk edin"</string>
+ <string name="wait" msgid="7902715035629500128">"Gözləyin"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000000..57f8bf59fa57
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivirajte uslugu"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Nema usluge prenosa podataka"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Dodirnite da biste aktivirali uslugu"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Nema usluge. Kontaktirajte dobavljača usluge"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Povezuje se sa ulaznim portalom…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Vremensko ograničenje mreže je isteklo. Želite li da probate ponovo?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Mreža nije dostupna"</string>
+ <string name="quit" msgid="4392968039488794590">"Zatvori"</string>
+ <string name="wait" msgid="7902715035629500128">"Čekaj"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml
new file mode 100644
index 000000000000..1f3032babd2d
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-be/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Актывуйце сэрвіс"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Няма сэрвісу перадачы даных"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Дакраніцеся, каб актываваць сэрвіс"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Няма абслугоўвання, звярніцеся да свайго пастаўшчыка паслуг"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Ідзе падключэнне да партала ўзаемадзеяння..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Час чакання сеткі скончыўся, хочаце паўтарыць спробу?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Сетка недаступная"</string>
+ <string name="quit" msgid="4392968039488794590">"Выйсці"</string>
+ <string name="wait" msgid="7902715035629500128">"Пачакаць"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bg/strings.xml b/packages/CarrierDefaultApp/res/values-bg/strings.xml
new file mode 100644
index 000000000000..b6bdd5da6cee
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-bg/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Активирайте услугата си"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Няма услуга за данни"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Докоснете, за да активирате услугата си"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Няма покритие. Моля, свържете се с доставчика си"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Установява се връзка с портал за удостоверяване..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Времето за изчакване на мрежата изтече. Искате ли да опитате отново?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Мрежата не е налице"</string>
+ <string name="quit" msgid="4392968039488794590">"Изход"</string>
+ <string name="wait" msgid="7902715035629500128">"Изчакване"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bn/strings.xml b/packages/CarrierDefaultApp/res/values-bn/strings.xml
new file mode 100644
index 000000000000..138a2b3d1884
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-bn/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"আপনার পরিষেবা সক্রিয় করুন"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ডেটা পরিষেবা উপলব্ধ নয়"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"আপনার পরিষেবা সক্রিয় করতে আলতো চাপুন"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"পরিষেবা উপলব্ধ নয়, অনুগ্রহ করে আপনার পরিষেবা প্রদানকারীর সঙ্গে যোগাযোগ করুন"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"অন্তরীণ পোর্টালের সঙ্গে সংযুক্ত করা হচ্ছে..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"নেটওয়ার্কের সময় সমাপ্ত হয়েছে, আপনি কি পুনরায় চেষ্টা করতে চান?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"নেটওয়ার্ক অনুপলব্ধ"</string>
+ <string name="quit" msgid="4392968039488794590">"প্রস্থান করুন"</string>
+ <string name="wait" msgid="7902715035629500128">"অপেক্ষা করুন"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
new file mode 100644
index 000000000000..b43e766685a4
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivirajte uslugu"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Nema mobilnog interneta"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Dodirnite da aktivirate uslugu"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Nema usluge. Obratite se pružaocu usluge."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Povezivanje na zaštitni portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Isteklo je vrijeme za odziv mreže. Želite li ponoviti?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Mreža nije dostupna"</string>
+ <string name="quit" msgid="4392968039488794590">"Odustani"</string>
+ <string name="wait" msgid="7902715035629500128">"Sačekaj"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml
new file mode 100644
index 000000000000..0730a01a4d78
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activa el servei"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"No hi ha servei de dades"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toca per activar el servei"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No hi ha servei. Contacta amb el proveïdor del servei."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"S\'està connectant al portal captiu…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"S\'ha esgotat el temps d\'espera de la xarxa. Vols tornar-ho a provar?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Xarxa no disponible"</string>
+ <string name="quit" msgid="4392968039488794590">"Surt"</string>
+ <string name="wait" msgid="7902715035629500128">"Espera"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml
new file mode 100644
index 000000000000..4056b05d2765
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivování služby"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Datová služba není dostupná"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Klepnutím službu aktivujete"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Služba není dostupná, kontaktujte poskytovatele"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Připojování ke captive portálu..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Časový limit sítě vypršel, zopakovat pokus?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Síť není dostupná"</string>
+ <string name="quit" msgid="4392968039488794590">"Ukončit"</string>
+ <string name="wait" msgid="7902715035629500128">"Počkat"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-da/strings.xml b/packages/CarrierDefaultApp/res/values-da/strings.xml
new file mode 100644
index 000000000000..83c8b8c84bdc
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-da/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivér din tjeneste"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ingen datatjeneste"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tryk for at aktivere din tjeneste"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Der er ingen tjeneste. Kontakt din tjenesteudbyder"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Opretter forbindelse til loginportal…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Timeout for netværket. Vil du prøve igen?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Netværket er ikke tilgængeligt"</string>
+ <string name="quit" msgid="4392968039488794590">"Afslut"</string>
+ <string name="wait" msgid="7902715035629500128">"Vent"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
new file mode 100644
index 000000000000..271356021c9d
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Dienst aktivieren"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Kein Datendienst"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Zum Aktivieren des Dienstes tippen"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Kein Dienst, kontaktiere bitte deinen Internetanbieter"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Verbindung mit Captive Portal wird hergestellt…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Zeitüberschreitung für Netzwerk – möchtest du es noch einmal versuchen?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Netzwerk nicht verfügbar"</string>
+ <string name="quit" msgid="4392968039488794590">"Beenden"</string>
+ <string name="wait" msgid="7902715035629500128">"Warten"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml
new file mode 100644
index 000000000000..6e9b2a4deeb5
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-el/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ενεργοποιήστε την υπηρεσία σας"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Δεν υπάρχει υπηρεσία δεδομένων"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Πατήστε για να ενεργοποιήσετε την υπηρεσία σας"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Η υπηρεσία δεν είναι διαθέσιμη. Επικοινωνήστε με τον παροχέα υπηρεσιών που χρησιμοποιείτε."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Σύνδεση στην πύλη υποδοχής…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Λήξη χρονικού ορίου δικτύου, θέλετε να δοκιμάσετε ξανά;"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Το δίκτυο δεν είναι διαθέσιμο"</string>
+ <string name="quit" msgid="4392968039488794590">"Έξοδος"</string>
+ <string name="wait" msgid="7902715035629500128">"Αναμονή"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..2e9060f098b7
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activate your service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"No data service"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tap to activate your service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No Service. Please contact your service provider"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connecting to captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Network timeout; would you like to retry?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Network unavailable"</string>
+ <string name="quit" msgid="4392968039488794590">"Exit"</string>
+ <string name="wait" msgid="7902715035629500128">"Wait"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..2e9060f098b7
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activate your service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"No data service"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tap to activate your service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No Service. Please contact your service provider"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connecting to captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Network timeout; would you like to retry?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Network unavailable"</string>
+ <string name="quit" msgid="4392968039488794590">"Exit"</string>
+ <string name="wait" msgid="7902715035629500128">"Wait"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..2e9060f098b7
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activate your service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"No data service"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tap to activate your service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No Service. Please contact your service provider"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connecting to captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Network timeout; would you like to retry?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Network unavailable"</string>
+ <string name="quit" msgid="4392968039488794590">"Exit"</string>
+ <string name="wait" msgid="7902715035629500128">"Wait"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..735b25573446
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activa tu servicio"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Sin servicio de datos"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Presiona para activar tu servicio"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No hay servicio, por lo que debes comunicarte con tu proveedor de servicios"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Conectando al portal cautivo…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Se agotó el tiempo de espera de la red, ¿quieres volver a intentarlo?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Red no disponible"</string>
+ <string name="quit" msgid="4392968039488794590">"Salir"</string>
+ <string name="wait" msgid="7902715035629500128">"Esperar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-es/strings.xml b/packages/CarrierDefaultApp/res/values-es/strings.xml
new file mode 100644
index 000000000000..49be628b2dbd
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-es/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activar el servicio"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Sin servicio de datos"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toca aquí para activar tu servicio"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Sin servicio. Ponte en contacto con el proveedor de servicios"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Conectando al portal cautivo…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Se ha agotado el tiempo de espera de la red. ¿Quieres volver a intentarlo?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Red no disponible"</string>
+ <string name="quit" msgid="4392968039488794590">"Salir"</string>
+ <string name="wait" msgid="7902715035629500128">"Esperar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-et/strings.xml b/packages/CarrierDefaultApp/res/values-et/strings.xml
new file mode 100644
index 000000000000..0cdf5bb5b57b
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-et/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktiveerige teenus"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Andmesideteenus puudub"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Puudutage teenuse aktiveerimiseks"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Teenus puudub. Võtke ühendust oma teenusepakkujaga"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Hõiveportaaliga ühendamine …"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Võrgu ajalõpp. Kas soovite uuesti proovida?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Võrk ei ole saadaval"</string>
+ <string name="quit" msgid="4392968039488794590">"Välju"</string>
+ <string name="wait" msgid="7902715035629500128">"Oodake"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml
new file mode 100644
index 000000000000..c1f7fa9ac142
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktibatu zerbitzua"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Datu-zerbitzua ez dago erabilgarri"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Sakatu zerbitzua aktibatzeko"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Zerbitzua ez dago erabilgarri. Jarri operadorearekin harremanetan."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Sare-zerbitzuaren atarira konektatzen…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Denbora-muga gainditu du sareak. Berriro saiatu nahi duzu?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Sarea ez dago erabilgarri"</string>
+ <string name="quit" msgid="4392968039488794590">"Irten"</string>
+ <string name="wait" msgid="7902715035629500128">"Itxaron"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml
new file mode 100644
index 000000000000..d7a67f684315
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"فعال کردن سرویس"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"سرویس داده وجود ندارد"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"برای فعال کردن سرویستان ضربه بزنید"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"سرویسی وجود ندارد، لطفاً با ارائه‌دهنده سرویس خود تماس بگیرید"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"درحال اتصال به درگاه مهمان…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"مهلت زمانی شبکه تمام شد، مایلید دوباره امتحان کنید؟"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"شبکه دردسترس نیست"</string>
+ <string name="quit" msgid="4392968039488794590">"خروج"</string>
+ <string name="wait" msgid="7902715035629500128">"منتظر بمانید"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fi/strings.xml b/packages/CarrierDefaultApp/res/values-fi/strings.xml
new file mode 100644
index 000000000000..8316e1c53659
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-fi/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ota yhteys käyttöön"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ei datayhteyttä"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Ota yhteys käyttöön napauttamalla."</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ei yhteyttä verkkoon. Ota yhteyttä palveluntarjoajaan."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Yhdistetään captive portal ‑palveluun…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Verkkoyhteys aikakatkaistiin. Yritetäänkö uudelleen?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Verkko ei ole käytettävissä"</string>
+ <string name="quit" msgid="4392968039488794590">"Lopeta"</string>
+ <string name="wait" msgid="7902715035629500128">"Odota"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000000..a2666cd7c7a7
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activez votre service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Aucun service de données"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Touchez pour activer votre service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Aucun service. Veuillez communiquer avec votre fournisseur de services."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connexion au portail captif en cours…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Expiration du délai sur le réseau. Voulez-vous réessayer?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Réseau non disponible"</string>
+ <string name="quit" msgid="4392968039488794590">"Quitter"</string>
+ <string name="wait" msgid="7902715035629500128">"Patienter"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml
new file mode 100644
index 000000000000..7a63bab7627e
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activer votre service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Aucun service de données"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Appuyez pour activer votre service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Aucun service. Veuillez contacter votre fournisseur de services"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connexion au portail captif..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Expiration du délai au niveau du réseau. Souhaitez-vous réessayer ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Réseau indisponible"</string>
+ <string name="quit" msgid="4392968039488794590">"Quitter"</string>
+ <string name="wait" msgid="7902715035629500128">"Attendre"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-gl/strings.xml b/packages/CarrierDefaultApp/res/values-gl/strings.xml
new file mode 100644
index 000000000000..ba18ee962fd3
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-gl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activa o servizo"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Non hai servizo de datos"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toca para activar o servizo"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Non hai servizo. Ponte en contacto co teu fornecedor de servizo"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Conectando co portal cativo..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Superouse o tempo de espera da rede. Queres tentalo de novo?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"A rede non está dispoñible"</string>
+ <string name="quit" msgid="4392968039488794590">"Saír"</string>
+ <string name="wait" msgid="7902715035629500128">"Esperar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml
new file mode 100644
index 000000000000..c6d7f9640782
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"કૅરિઅર ડિફૉલ્ટ ઍપ્લિકેશન"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"તમારી સેવા સક્રિય કરો"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"કોઈ ડેટા સેવા ઉપલબ્ધ નથી"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"તમારી સેવા સક્રિય કરવા માટે ટૅપ કરો"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"કોઈ સેવા ઉપલબ્ધ નથી, કૃપા કરીને તમારા સેવા પ્રદાતાનો સંપર્ક કરો"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"કૅપ્ટિવ પોર્ટલ સાથે કનેક્ટ થઈ રહ્યું છે..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"નેટવર્કનો સમય સમાપ્ત થયો, શું તમે ફરીથી પ્રયાસ કરશો?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"નેટવર્ક અનુપલબ્ધ"</string>
+ <string name="quit" msgid="4392968039488794590">"છોડી દો"</string>
+ <string name="wait" msgid="7902715035629500128">"રાહ જુઓ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml
new file mode 100644
index 000000000000..a1de4bc65f74
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"अपनी सेवा सक्रिय करें"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"कोई डेटा सेवा नहीं है"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"अपनी सेवा सक्रिय करने के लिए टैप करें"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"कोई सेवा नहीं है, कृपया आपको सेवा प्रदान करने वाले से संपर्क करें"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"कैप्टिव पोर्टल से कनेक्ट हो रहा है..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"नेटवर्क रुक गया है, क्या आप फिर से कोशिश करना चाहेंगे?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"नेटवर्क उपलब्ध नहीं है"</string>
+ <string name="quit" msgid="4392968039488794590">"बाहर निकलें"</string>
+ <string name="wait" msgid="7902715035629500128">"प्रतीक्षा करें"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml
new file mode 100644
index 000000000000..d5c05de63f49
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"Zadana aplikacija mobilnog operatera"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivirajte uslugu"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Podatkovna usluga nije dostupna"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Dodirnite da biste aktivirali uslugu"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Usluga nije dostupna. Obratite se davatelju usluga."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Povezivanje sa zaštitnim portalom..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Isteklo je vremensko ograničenje mreže. Želite li pokušati ponovo?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Mreža nije dostupna"</string>
+ <string name="quit" msgid="4392968039488794590">"Izlaz"</string>
+ <string name="wait" msgid="7902715035629500128">"Pričekajte"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
new file mode 100644
index 000000000000..c204ee0b102a
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"A szolgáltatás aktiválása"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Az adatszolgáltatás szünetel"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Koppintson a szolgáltatás aktiválásához"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"A szolgáltatás szünetel. Kérjük, vegye fel a kapcsolatot szolgáltatójával."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Kapcsolódás a hitelesítési portálhoz…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Hálózati időtúllépés. Megpróbálja újra?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"A hálózat nem áll rendelkezésre"</string>
+ <string name="quit" msgid="4392968039488794590">"Kilépés"</string>
+ <string name="wait" msgid="7902715035629500128">"Várakozás"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml
new file mode 100644
index 000000000000..ac5357424b19
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ակտիվացրեք ձեր ծառայությունը"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Տվյալների ծառայությունն անհասանելի է"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Հպեք՝ ծառայությունն ակտիվացնելու համար"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ծառայությունն անհասանելի է։ Դիմեք ձեր ծառայություններ մատուցողին"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Միանում է մուտքի էջին…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Ցանցի սպասման ժամանակը սպառվել է։ Փորձե՞լ կրկին։"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Ցանցն անհասանելի է"</string>
+ <string name="quit" msgid="4392968039488794590">"Դուրս գալ"</string>
+ <string name="wait" msgid="7902715035629500128">"Սպասել"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-in/strings.xml b/packages/CarrierDefaultApp/res/values-in/strings.xml
new file mode 100644
index 000000000000..15b6849e77fe
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-in/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"AplikasiDefaultOperator"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktifkan layanan"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Tidak ada layanan data"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tap untuk mengaktifkan layanan"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Tidak Ada Layanan, hubungi penyedia layanan"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Menyambungkan ke captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Waktu tunggu jaringan habis, ingin mencoba lagi?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Jaringan tidak tersedia"</string>
+ <string name="quit" msgid="4392968039488794590">"Keluar"</string>
+ <string name="wait" msgid="7902715035629500128">"Tunggu"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-is/strings.xml b/packages/CarrierDefaultApp/res/values-is/strings.xml
new file mode 100644
index 000000000000..fb6ca5707fcc
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-is/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Virkja þjónustuna"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ekkert gagnasamband"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Ýttu til að virkja þjónustuna"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ekkert samband, hafðu samband við þjónustuaðila"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Tengist innskráningarsíðu..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Tímamörk nettengingar runnu út, viltu reyna aftur?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Ekkert net til staðar"</string>
+ <string name="quit" msgid="4392968039488794590">"Hætta"</string>
+ <string name="wait" msgid="7902715035629500128">"Bíða"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-it/strings.xml b/packages/CarrierDefaultApp/res/values-it/strings.xml
new file mode 100644
index 000000000000..fca6eb97bea3
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-it/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Attiva il servizio"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Nessun servizio dati"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tocca per attivare il servizio"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Nessun servizio. Contatta il provider Internet."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connessione al captive portal…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Timeout di rete. Vuoi riprovare?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rete non disponibile"</string>
+ <string name="quit" msgid="4392968039488794590">"Esci"</string>
+ <string name="wait" msgid="7902715035629500128">"Attendi"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
new file mode 100644
index 000000000000..60b9168db336
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"הפעל את השירות"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"אין שירות נתונים"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"הקש כדי להפעיל את השירות"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"שירות הנתונים לא זמין. צור קשר עם ספק השירות."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"מתחבר לפורטל שבוי..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"הזמן הקצוב לתפוגת הרשת עבר. תרצה לנסות שוב?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"הרשת אינה זמינה"</string>
+ <string name="quit" msgid="4392968039488794590">"צא"</string>
+ <string name="wait" msgid="7902715035629500128">"המתן"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml
new file mode 100644
index 000000000000..2875577d30b8
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"携帯通信会社のデフォルト アプリ"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"サービスの有効化"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"データサービスがありません"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"サービスを有効にするにはタップします"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"サービスがありません。ご利用のサービス プロバイダにお問い合わせください"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"キャプティブ ポータルに接続しています…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ネットワークがタイムアウトしました。再試行しますか?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ネットワーク接続不可"</string>
+ <string name="quit" msgid="4392968039488794590">"終了"</string>
+ <string name="wait" msgid="7902715035629500128">"待機"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml
new file mode 100644
index 000000000000..c19157570798
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"თქვენი სერვისის გააქტიურება"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"მონაცემთა სერვისი არ არის"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"შეეხეთ თქვენი სერვისის გასააქტიურებლად"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"სერვისი არ არის — გთხოვთ, დაუკავშირდეთ სერვისის პროვაიდერს"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"მიმდინარეობს ავტორიზაციის პორტალთან დაკავშირება…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ქსელის დროის ლიმიტი ამოიწურა. გსურთ ხელახლა ცდა?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ქსელი მიუწვდომელია"</string>
+ <string name="quit" msgid="4392968039488794590">"გასვლა"</string>
+ <string name="wait" msgid="7902715035629500128">"მოცდა"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-kk/strings.xml b/packages/CarrierDefaultApp/res/values-kk/strings.xml
new file mode 100644
index 000000000000..2285fda48ce8
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-kk/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Қызметті іске қосу"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Деректер қызметі көрсетілмейді"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Қызметті іске қосу үшін түртіңіз"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Қызмет көрсетілмейді, қызмет провайдеріне хабарласыңыз"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Адаптивті порталға қосылуда…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Желі мерзімі аяқталды, әрекетті қайталайсыз ба?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Желі қолжетімді емес"</string>
+ <string name="quit" msgid="4392968039488794590">"Шығу"</string>
+ <string name="wait" msgid="7902715035629500128">"Күту"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml
new file mode 100644
index 000000000000..7a02a0fd601c
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-km/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"បើក​ដំណើរការ​សេវាកម្ម​របស់អ្នក"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"គ្មាន​សេវាកម្ម​ទិន្នន័យ​ទេ"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"ចុច​ដើម្បី​បើក​ដំណើរការ​សេវាកម្ម​របស់អ្នក"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"គ្មាន​សេវាកម្ម​ទេ សូម​ទាក់ទង​ក្រុមហ៊ុន​ផ្តល់​សេវាកម្ម​របស់អ្នក"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"កំពុង​ភ្ជាប់​ទៅ​ច្រក​ចូល​ប្រើ​បណ្តាញ..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"បណ្តាញ​អស់​ម៉ោង​ហើយ តើ​អ្នក​ចង់​ព្យាយាម​ម្តង​ទៀត​ដែរ​ទេ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"មិន​មាន​បណ្តាញ​ទេ"</string>
+ <string name="quit" msgid="4392968039488794590">"ចាកចេញ"</string>
+ <string name="wait" msgid="7902715035629500128">"រង់ចាំ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml
new file mode 100644
index 000000000000..42fe9a0bf7ea
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"ನಿಮ್ಮ ಸೇವೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ಯಾವುದೇ ಡೇಟಾ ಸೇವೆ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"ನಿಮ್ಮ ಸೇವೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"ಸೇವೆಯು ಲಭ್ಯವಿಲ್ಲ, ನಿಮಗೆ ಸೇವೆ ಒದಗಿಸುವವರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"ವೈ-ಫೈ ಪ್ರಾರಂಭ ಪೋರ್ಟಲ್‌ಗೆ ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ನೆಟ್‌ವರ್ಕ್‌ ಕಾಲಾವಧಿ ಮುಗಿದಿದೆ, ನೀವು ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="quit" msgid="4392968039488794590">"ತ್ಯಜಿಸಿ"</string>
+ <string name="wait" msgid="7902715035629500128">"ನಿರೀಕ್ಷಿಸಿ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml
new file mode 100644
index 000000000000..4cdcb91ae9e1
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"이동통신사 기본 앱"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"서비스 활성화"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"데이터 서비스를 이용할 수 없음"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"탭하여 서비스 활성화"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"서비스를 이용할 수 없습니다. 서비스 제공업체에 문의하세요."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"종속 포털에 연결 중..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"네트워크 제한 시간이 초과되었습니다. 다시 시도하시겠습니까?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"네트워크를 사용할 수 없음"</string>
+ <string name="quit" msgid="4392968039488794590">"종료"</string>
+ <string name="wait" msgid="7902715035629500128">"대기"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml
new file mode 100644
index 000000000000..54c95755aec1
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"ОператордунДемейкиКолдонмосу"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Кызматты жандырыңыз"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Мобилдик туташуу кызматы жок"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Кызматты жандыруу үчүн таптаңыз"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Байланыш жок, кызмат көрсөтүүчүңүзгө кайрылыңыз"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Кирүү бетине туташууда…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Тармактын күтүү убакыты аяктады, кайра аракет кыласызбы?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Тармак жеткиликтүү эмес"</string>
+ <string name="quit" msgid="4392968039488794590">"Чыгуу"</string>
+ <string name="wait" msgid="7902715035629500128">"Күтүү"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml
new file mode 100644
index 000000000000..205d9b699fa4
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activate your service"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"No data service"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tap to activate your service"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"No Service, please contact your service provider"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Connecting to captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Network timeout, would you like to retry?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Network unavailable"</string>
+ <string name="quit" msgid="4392968039488794590">"ອອກ"</string>
+ <string name="wait" msgid="7902715035629500128">"ລໍ​ຖ້າ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml
new file mode 100644
index 000000000000..61f6d59abe78
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Suaktyvinkite paslaugas"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Duomenų paslaugos neteikiamos"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Palieskite, kad suaktyvintumėte paslaugą"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Paslauga neteikiama. Susisiekite su paslaugos teikėju"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Prisijungiama prie fiksuotojo portalo..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Baigėsi skirtasis tinklo laikas. Ar norite bandyti dar kartą?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Tinklas nepasiekiamas"</string>
+ <string name="quit" msgid="4392968039488794590">"Baigti"</string>
+ <string name="wait" msgid="7902715035629500128">"Laukti"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lv/strings.xml b/packages/CarrierDefaultApp/res/values-lv/strings.xml
new file mode 100644
index 000000000000..1b6b90b04e75
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-lv/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivizēt pakalpojumu"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Nav datu pakalpojuma"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Pieskarieties, lai aktivizētu pakalpojumu"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Nav pakalpojuma. Lūdzu, sazinieties ar pakalpojuma sniedzēju."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Notiek savienojuma izveide ar caurlaides lapu..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Radās tīkla noildze. Vai vēlaties mēģināt vēlreiz?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Tīkls nav pieejams"</string>
+ <string name="quit" msgid="4392968039488794590">"Iziet"</string>
+ <string name="wait" msgid="7902715035629500128">"Gaidīt"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml
new file mode 100644
index 000000000000..066fb316aefd
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Активирајте ја услугата"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Нема услуга за подотоци"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Допрете за да ја активирате услугата"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Нема услуга, контактирајте со давателот на услуги"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Се поврзува на порталот за автентикација…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Истече времето на мрежата, дали сакате да се обидете повторно?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Мрежата е недостапна"</string>
+ <string name="quit" msgid="4392968039488794590">"Излези"</string>
+ <string name="wait" msgid="7902715035629500128">"Почекај"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml
new file mode 100644
index 000000000000..b72e877314da
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"നിങ്ങളുടെ സേവനം ‌ആക്റ്റി‌വേറ്റ് ‌ചെയ്യുക"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ഡാറ്റ ‌സേവനം ലഭ്യമല്ല"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"നിങ്ങളുടെ സേവനം ‌ആക്റ്റി‌വേറ്റ് ‌ചെയ്യാൻ ടാപ്പുചെയ്യുക"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"സേവനം ‌ലഭ്യമല്ല, നിങ്ങളുടെ ‌സേവന‌ദാതാവിനെ ‌ബന്ധപ്പെടുക"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"ക്യാപ്റ്റീവ് പോർട്ടലിലേയ്ക്ക് കണക്റ്റുചെയ്യുന്നു..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"നെറ്റ്‌വർക്ക് കാലഹരണപ്പെട്ടു, വീണ്ടും ശ്രമിക്കണോ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"നെറ്റ്‌വർക്ക് ലഭ്യമല്ല"</string>
+ <string name="quit" msgid="4392968039488794590">"പുറത്തുപോവുക"</string>
+ <string name="wait" msgid="7902715035629500128">"കാത്തിരിക്കുക"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml
new file mode 100644
index 000000000000..c262e8fc2010
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Үйлчилгээгээ идэвхжүүлнэ үү"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Дата үйлчилгээ алга"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Үйлчилгээгээ идэвхжүүлэхийн тулд товшино уу"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Үйлчилгээ алга. Үйлчилгээ үзүүлэгчтэйгээ холбогдоно уу"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Дамжих порталд холбогдож байна..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Сүлжээний хугацаа дууссан байна. Дахин оролдох уу?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Сүлжээ боломжгүй"</string>
+ <string name="quit" msgid="4392968039488794590">"Гарах"</string>
+ <string name="wait" msgid="7902715035629500128">"Хүлээх"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mr/strings.xml b/packages/CarrierDefaultApp/res/values-mr/strings.xml
new file mode 100644
index 000000000000..beff6752c431
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-mr/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"आपली सेवा सक्रिय करा"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"डेटा सेवा नाही"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"आपली सेवा सक्रिय करण्यासाठी टॅप करा"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"सेवा नाही, कृपया आपल्या सेवा प्रदात्याशी संपर्क साधा"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"कॅप्टिव्ह पोर्टलशी कनेक्ट करत आहे..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"नेटवर्क कालबाह्य झाले, आपण पुन्हा प्रयत्न करू इच्छिता का?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"नेटवर्क अनुपलब्ध"</string>
+ <string name="quit" msgid="4392968039488794590">"बाहेर पडा"</string>
+ <string name="wait" msgid="7902715035629500128">"प्रतीक्षा करा"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml
new file mode 100644
index 000000000000..eff78c6fbc0b
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"AplLalaiPembawa"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktifkan perkhidmatan anda"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Tiada perkhidmatan data"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Ketik untuk mengaktifkan perkhidmatan anda"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Tiada Perkhidmatan, sila hubungi penyedia perkhidmatan anda"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Menyambung ke portal terbolot…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Rangkaian tamat masa, adakah anda mahu mencuba semula?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rangkaian tidak tersedia"</string>
+ <string name="quit" msgid="4392968039488794590">"Keluar"</string>
+ <string name="wait" msgid="7902715035629500128">"Tunggu"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml
new file mode 100644
index 000000000000..b0e929edb095
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-my/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"ဝန်ဆောင်မှုကို စဖွင့်အသုံးပြုရန်"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ဒေတာချိတ်ဆက်မှုမရှိပါ"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"ဝန်ဆောင်မှုကို စဖွင့်အသုံးပြုရန် တို့ပါ"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"လိုင်းမရှိပါ။ သင့်ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"captive portal သို့ ချိတ်ဆက်နေသည်..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ချိတ်ဆက်မှု ပြတ်တောက်သွားပါသည်။ ထပ်လုပ်လိုပါသလား။"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ကွန်ရက်ချိတ်ဆက်မှု မရှိပါ"</string>
+ <string name="quit" msgid="4392968039488794590">"ထွက်ရန်"</string>
+ <string name="wait" msgid="7902715035629500128">"စောင့်ရန်"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml
new file mode 100644
index 000000000000..6f69e9afd9d3
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktiver tjenesten"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ingen datatjeneste"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Trykk for å aktivere tjenesten"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ingen dekning – ta kontakt med tjenesteleverandøren din."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Kobler til obligatorisk side …"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Tidsavbrudd for nettverk – vil du prøve på nytt?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Nettverket er utilgjengelig"</string>
+ <string name="quit" msgid="4392968039488794590">"Avslutt"</string>
+ <string name="wait" msgid="7902715035629500128">"Vent"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml
new file mode 100644
index 000000000000..aa5766bde89a
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"आफ्नो सेवालाई सक्रिय पार्नुहोस्‌"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"डेटा सेवा छैन"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"आफ्नो सेवालाई सक्रिय पार्न ट्याप गर्नुहोस्"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"सेवा उपलब्ध छैन,कृपया आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नुहोस्"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"क्याप्टिभ पोर्टलमा जडान हुँदैछ..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"नेटवर्कमा जडान हुने समय समाप्त भयो, के तपाईँ पुनः प्रयास गर्न चाहानुहुन्छ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"नेटवर्क उपलब्ध छैन"</string>
+ <string name="quit" msgid="4392968039488794590">"बाहिरिनुहोस्"</string>
+ <string name="wait" msgid="7902715035629500128">"पर्खनुहोस्"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-nl/strings.xml b/packages/CarrierDefaultApp/res/values-nl/strings.xml
new file mode 100644
index 000000000000..b7da335dec16
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-nl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"De service activeren"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Geen gegevensservice"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tik om de service te activeren"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Geen service. Neem contact op met je serviceprovider."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Verbinding maken met captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Time-out voor het netwerk. Wil je het opnieuw proberen?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Netwerk niet beschikbaar"</string>
+ <string name="quit" msgid="4392968039488794590">"Stoppen"</string>
+ <string name="wait" msgid="7902715035629500128">"Wachten"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pa/strings.xml b/packages/CarrierDefaultApp/res/values-pa/strings.xml
new file mode 100644
index 000000000000..a044edfa16c3
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-pa/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"ਆਪਣੀ ਸੇਵਾ ਨੂੰ ਸਰਗਰਮ ਕਰੋ"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ਕੋਈ ਡੈਟਾ ਸੇਵਾ ਨਹੀਂ"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"ਆਪਣੀ ਸੇਵਾ ਨੂੰ ਸਰਗਰਮ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"ਕੈਪਟਿਵ ਪੋਰਟਲ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ਨੈੱਟਵਰਕ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਗਿਆ, ਕੀ ਤੁਸੀਂ ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰਨਾ ਚਾਹੋਂਗੇ?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="quit" msgid="4392968039488794590">"ਛੱਡੋ"</string>
+ <string name="wait" msgid="7902715035629500128">"ਉਡੀਕ ਕਰੋ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pl/strings.xml b/packages/CarrierDefaultApp/res/values-pl/strings.xml
new file mode 100644
index 000000000000..2f10e5c8c027
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-pl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"Domyślna aplikacja operatora"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktywuj usługę"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Brak usługi transmisji danych"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Kliknij, by aktywować usługę"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Brak usługi. Skontaktuj się z operatorem."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Łączę z portalem przechwytującym..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Czas oczekiwania na sieć minął. Chcesz spróbować ponownie?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Sieć jest niedostępna"</string>
+ <string name="quit" msgid="4392968039488794590">"Zamknij"</string>
+ <string name="wait" msgid="7902715035629500128">"Czekaj"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000000..e730dc631d8e
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ative seu serviço"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Sem serviço de dados"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toque para ativar seu serviço"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Sem serviço. Entre em contato com seu provedor de serviços"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Conectando-se ao portal cativo…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Tempo limite de rede. Deseja tentar novamente?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rede indisponível"</string>
+ <string name="quit" msgid="4392968039488794590">"Sair"</string>
+ <string name="wait" msgid="7902715035629500128">"Esperar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..a2c10e96e169
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ativar o seu serviço"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Sem serviço de dados"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toque para ativar o seu serviço"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Sem serviço. Contacte o seu fornecedor de serviços"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"A ligar ao portal cativo…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"O limite de tempo da rede foi excedido. Pretende tentar novamente?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rede não disponível"</string>
+ <string name="quit" msgid="4392968039488794590">"Sair"</string>
+ <string name="wait" msgid="7902715035629500128">"Aguardar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml
new file mode 100644
index 000000000000..e730dc631d8e
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Ative seu serviço"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Sem serviço de dados"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Toque para ativar seu serviço"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Sem serviço. Entre em contato com seu provedor de serviços"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Conectando-se ao portal cativo…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Tempo limite de rede. Deseja tentar novamente?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rede indisponível"</string>
+ <string name="quit" msgid="4392968039488794590">"Sair"</string>
+ <string name="wait" msgid="7902715035629500128">"Esperar"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml
new file mode 100644
index 000000000000..234c410fe93a
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"AplicațiePrestabilităOperator"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Activați serviciul"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Fără serviciu de date"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Atingeți pentru a activa serviciul"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Fără serviciu. Contactați furnizorul de servicii."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Se conectează la portalul captiv..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Timpul limită pentru rețea a expirat. Doriți să încercați din nou?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rețea indisponibilă"</string>
+ <string name="quit" msgid="4392968039488794590">"Ieșiți"</string>
+ <string name="wait" msgid="7902715035629500128">"Așteptați"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml
new file mode 100644
index 000000000000..b038f0ffb40c
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Активируйте сервис"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Нет подключения"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Нажмите, чтобы активировать сервис"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Обратитесь к своему поставщику услуг Интернета."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Подключение к странице входа…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Время ожидания для сети истекло. Повторить попытку?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Сеть недоступна"</string>
+ <string name="quit" msgid="4392968039488794590">"Закрыть"</string>
+ <string name="wait" msgid="7902715035629500128">"Подождать"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-si/strings.xml b/packages/CarrierDefaultApp/res/values-si/strings.xml
new file mode 100644
index 000000000000..2f016b256cba
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-si/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"ඔබේ සේවාව සක්‍රිය කරන්න"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"දත්ත සේවාව නැත"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"ඔබේ සේවාව සක්‍රිය කිරීමට තට්ටු කරන්න"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"සේවාව නැත. කරුණාකර ඔබගේ සේවා සැපයුම්කරු අමතන්න"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"පිවිසුම් දොරටුව වෙත සබැඳෙමින්..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"ජාලය කාල නිමා විය, ඔබ යළි උත්සාහ කිරීමට කැමතිද?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"ජාලය ලබා ගත නොහැකිය"</string>
+ <string name="quit" msgid="4392968039488794590">"ඉවත් වන්න"</string>
+ <string name="wait" msgid="7902715035629500128">"රැඳී සිටින්න"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sk/strings.xml b/packages/CarrierDefaultApp/res/values-sk/strings.xml
new file mode 100644
index 000000000000..088e188997dc
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sk/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivujte službu"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Žiadna dátová služba"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Klepnutím aktivujete službu"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Žiadna služba, kontaktujte svojho poskytovateľa služieb"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Pripájanie k prihlasovaciemu portálu…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Vypršal časový limit siete. Chcete to skúsiť znova?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Sieť nie je k dispozícii"</string>
+ <string name="quit" msgid="4392968039488794590">"Ukončiť"</string>
+ <string name="wait" msgid="7902715035629500128">"Počkať"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml
new file mode 100644
index 000000000000..7ef9b7e22940
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"Privzeta aplikacija operaterja"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivirajte storitev"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ni storitve za prenos podatkov"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Dotaknite se, da aktivirate storitev"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ni signala. Obrnite se na ponudnika storitev."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Povezovanje s prestreznim portalom …"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Časovna omejitev omrežja je potekla. Želite poskusiti znova?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Omrežje ni na voljo"</string>
+ <string name="quit" msgid="4392968039488794590">"Prekini"</string>
+ <string name="wait" msgid="7902715035629500128">"Čakaj"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sq/strings.xml b/packages/CarrierDefaultApp/res/values-sq/strings.xml
new file mode 100644
index 000000000000..316fe1d11a81
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sq/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivizo shërbimin"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Nuk ka shërbim për të dhënat"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Trokit për të aktivizuar shërbimin"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Nuk ka shërbim, kontakto me ofruesin e shërbimit"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Po lidhet me portalin e izoluar..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Koha e pritjes së rrjetit përfundoi. Dëshiron të provosh sërish?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Rrjeti është i padisponueshëm"</string>
+ <string name="quit" msgid="4392968039488794590">"Dil"</string>
+ <string name="wait" msgid="7902715035629500128">"Prit"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml
new file mode 100644
index 000000000000..5c381f4a74f5
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Активирајте услугу"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Нема услуге преноса података"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Додирните да бисте активирали услугу"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Нема услуге. Контактирајте добављача услуге"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Повезује се са улазним порталом…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Временско ограничење мреже је истекло. Желите ли да пробате поново?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Мрежа није доступна"</string>
+ <string name="quit" msgid="4392968039488794590">"Затвори"</string>
+ <string name="wait" msgid="7902715035629500128">"Чекај"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sv/strings.xml b/packages/CarrierDefaultApp/res/values-sv/strings.xml
new file mode 100644
index 000000000000..ce218211c266
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sv/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Aktivera tjänsten"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Det finns ingen datatjänst"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Tryck för att aktivera tjänsten"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Det finns ingen tjänst. Kontakta internetleverantören."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Ansluter till infångstportal …"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Nätverkets tidsgräns nådd. Vill du försöka igen?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Nätverket är inte tillgängligt"</string>
+ <string name="quit" msgid="4392968039488794590">"Stäng"</string>
+ <string name="wait" msgid="7902715035629500128">"Vänta"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sw/strings.xml b/packages/CarrierDefaultApp/res/values-sw/strings.xml
new file mode 100644
index 000000000000..90ea0144e4a8
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-sw/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Anzisha huduma yako"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Hakuna huduma ya data"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Gonga ili uanzishe huduma yako"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Hakuna Huduma, tafadhali wasiliana na mtoa huduma wako"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Inaunganisha kwenye ukurasa wa mwanzo..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Mtandao haupatikani, ungependa kujaribu tena?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Mtandao haupatikani"</string>
+ <string name="quit" msgid="4392968039488794590">"Acha"</string>
+ <string name="wait" msgid="7902715035629500128">"Subiri"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ta/strings.xml b/packages/CarrierDefaultApp/res/values-ta/strings.xml
new file mode 100644
index 000000000000..bf836df3ce42
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ta/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"சேவையைச் செயல்படுத்தவும்"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"தரவுச் சேவை இல்லை"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"சேவையைச் செயல்படுத்த, தட்டவும்"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"சேவை இல்லை. உங்கள் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"கேப்டிவ் போர்டலுடன் இணைக்கிறது..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"நெட்வொர்க் நேரம் முடிந்தது, மீண்டும் முயல விரும்புகிறீர்களா?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"நெட்வொர்க் இல்லை"</string>
+ <string name="quit" msgid="4392968039488794590">"வெளியேறு"</string>
+ <string name="wait" msgid="7902715035629500128">"காத்திரு"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml
new file mode 100644
index 000000000000..70fe4999cfdb
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-te/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"మీ సేవని సక్రియం చేయండి"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"డేటా సేవ లేదు"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"మీ సేవని సక్రియం చేయడానికి నొక్కండి"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"సేవ లేదు, దయచేసి మీ సేవా ప్రదాతను సంప్రదించండి"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"క్యాప్టివ్ పోర్టల్‌కు కనెక్ట్ చేస్తోంది..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"నెట్‌వర్క్ గడువు సమయం ముగిసింది, మీరు మళ్లీ ప్రయత్నించాలనుకుంటున్నారా?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"నెట్‌వర్క్ అందుబాటులో లేదు"</string>
+ <string name="quit" msgid="4392968039488794590">"నిష్క్రమించు"</string>
+ <string name="wait" msgid="7902715035629500128">"వేచి ఉండండి"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml
new file mode 100644
index 000000000000..66526eac2071
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-th/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"เปิดใช้งานบริการของคุณ"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ไม่มีบริการข้อมูล"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"แตะเพื่อเปิดใช้งานบริการ"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"ไม่มีบริการ โปรดติดต่อผู้ให้บริการ"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"กำลังเชื่อมต่อแคพทีฟพอร์ทัล..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"หมดเวลาเชื่อมต่อเครือข่ายแล้ว ลองอีกครั้งไหม"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"เครือข่ายใช้ไม่ได้"</string>
+ <string name="quit" msgid="4392968039488794590">"ปิด"</string>
+ <string name="wait" msgid="7902715035629500128">"รอ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml
new file mode 100644
index 000000000000..d84495697998
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"I-activate ang iyong serbisyo"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Walang serbisyo sa data"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"I-tap upang i-activate ang iyong serbisyo"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Walang Serbisyo, mangyaring makipag-ugnayan sa iyong service provider"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Kumokonekta sa captive portal..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Nag-timeout ang network, gusto mo bang subukang muli?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Hindi available ang network"</string>
+ <string name="quit" msgid="4392968039488794590">"Umalis"</string>
+ <string name="wait" msgid="7902715035629500128">"Maghintay"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-tr/strings.xml b/packages/CarrierDefaultApp/res/values-tr/strings.xml
new file mode 100644
index 000000000000..31c781c47b90
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-tr/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"VarsayılanOperatörUygulaması"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Hizmetinizi etkinleştirin"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Veri hizmeti yok"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Hizmetinizi etkinleştirmek için dokunun"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Hizmet yok, lütfen servis sağlayıcınıza başvurun"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Giriş portalına bağlanıyor..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Ağ zaman aşımı, yeniden denemek istiyor musunuz?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Ağa ulaşılamıyor"</string>
+ <string name="quit" msgid="4392968039488794590">"Çık"</string>
+ <string name="wait" msgid="7902715035629500128">"Bekle"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-uk/strings.xml b/packages/CarrierDefaultApp/res/values-uk/strings.xml
new file mode 100644
index 000000000000..dfd1545a73c5
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-uk/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"Додаток оператора за умовчанням"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Активуйте з’єднання"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Немає мобільного Інтернету"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Торкніться, щоб активувати з’єднання"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Немає з’єднання. Зв’яжіться зі своїм постачальником послуг."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Під’єднання до адаптивного порталу…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Час очікування мережі минув. Повторити спробу?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Мережа недоступна"</string>
+ <string name="quit" msgid="4392968039488794590">"Вийти"</string>
+ <string name="wait" msgid="7902715035629500128">"Чекати"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
new file mode 100644
index 000000000000..3002d407aaa6
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"اپنی سروس فعال کریں"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"ڈیٹا سروس موجود نہیں"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"اپنی سروس فعال کرنے کے لیے تھپتھپائیں"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"سروس موجود نہیں، براہ کرم اپنے خدمت کے فراہم کنندہ سے رابطہ کریں"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"کیپٹو پورٹل سے منسلک ہو رہا ہے..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"نیٹ ورک ٹائم آؤٹ، کیا آپ دوبارہ کوشش کرنا چاہیں گے؟"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"نیٹ ورک غیر دستیاب ہے"</string>
+ <string name="quit" msgid="4392968039488794590">"چھوڑ دیں"</string>
+ <string name="wait" msgid="7902715035629500128">"انتظار کریں"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml
new file mode 100644
index 000000000000..92a0af02ae67
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Xizmatni faollashtiring"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Aloqa yo‘q"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Xizmatni faollashtirish uchun bosing"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Xizmat yo‘q. Xizmat ta’minotchisi bilan bog‘laning."</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Kirish sahifasida haqiqiylik tekshiruvi bor tarmoqqa ulanilmoqda…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Tarmoq uchun kutish vaqti tugadi. Qayta urinilsinmi?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Tarmoq mavjud emas"</string>
+ <string name="quit" msgid="4392968039488794590">"Chiqish"</string>
+ <string name="wait" msgid="7902715035629500128">"Kutish"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml
new file mode 100644
index 000000000000..06ea6f00cea0
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Kích hoạt dịch vụ của bạn"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Không có dịch vụ dữ liệu"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Nhấn để kích hoạt dịch vụ của bạn"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Không có dịch vụ, vui lòng liên hệ với nhà cung cấp dịch vụ của bạn"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Đang kết nối với cổng cố định..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Hết thời gian chờ mạng, bạn có muốn thử lại không?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Mạng không khả dụng"</string>
+ <string name="quit" msgid="4392968039488794590">"Thoát"</string>
+ <string name="wait" msgid="7902715035629500128">"Đợi"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000000..6734a31afd3c
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"运营商默认应用"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"启用您的服务"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"没有数据服务"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"点按即可启用您的服务"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"没有服务,请与您的服务提供商联系"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"正在连接到强制门户…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"网络超时,要重试吗?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"无法连接到网络"</string>
+ <string name="quit" msgid="4392968039488794590">"退出"</string>
+ <string name="wait" msgid="7902715035629500128">"等待"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..c74d543292d0
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"啟用服務"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"沒有數據服務"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"輕按即可啟用服務"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"沒有服務,請聯絡您的服務供應商"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"正在連接至強制網絡入口…"</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"網絡逾時,要再試一次嗎?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"無法使用網絡"</string>
+ <string name="quit" msgid="4392968039488794590">"結束"</string>
+ <string name="wait" msgid="7902715035629500128">"等待"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000000..ad0ea6bbcbb9
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"行動通訊業者預設應用程式"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"啟用服務"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"沒有數據服務"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"輕觸即可啟用服務"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"沒有服務,請與你的服務供應商聯絡"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"正在連線至網頁認證入口..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"網路逾時,你要重試嗎?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"無法連上網路"</string>
+ <string name="quit" msgid="4392968039488794590">"結束"</string>
+ <string name="wait" msgid="7902715035629500128">"等待"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zu/strings.xml b/packages/CarrierDefaultApp/res/values-zu/strings.xml
new file mode 100644
index 000000000000..12e8a7d214c2
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-zu/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="portal_notification_id" msgid="267536768510843288">"Sebenzisa isevisi yakho"</string>
+ <string name="no_data_notification_id" msgid="5216950045164991172">"Ayikho isevisi yedatha"</string>
+ <string name="portal_notification_detail" msgid="2860620550281695686">"Thepha ukuze usebenzise isevisi yakho"</string>
+ <string name="no_data_notification_detail" msgid="1757413358517680719">"Ayikho isevisi, sicela uxhumane nomhlinzeki wakho wesevisi"</string>
+ <string name="progress_dialogue_network_connection" msgid="4964125154591905581">"Ixhuma kuphothali yabathunjiweyo..."</string>
+ <string name="alert_dialogue_network_timeout" msgid="4515760047815901797">"Ukuphela kwesikhathi senethiwekhi, ungathanda ukuzama futhi?"</string>
+ <string name="alert_dialogue_network_timeout_title" msgid="3117252205484891837">"Inethiwekhi ayitholakali"</string>
+ <string name="quit" msgid="4392968039488794590">"Yeka"</string>
+ <string name="wait" msgid="7902715035629500128">"Linda"</string>
+</resources>
diff --git a/packages/CompanionDeviceManager/Android.mk b/packages/CompanionDeviceManager/Android.mk
new file mode 100644
index 000000000000..f730356e6947
--- /dev/null
+++ b/packages/CompanionDeviceManager/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CompanionDeviceManager
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
new file mode 100644
index 000000000000..3eede5454d6f
--- /dev/null
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2017 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.companiondevicemanager">
+
+ <permission
+ android:name="com.android.companiondevicemanager.permission.BIND"
+ android:protectionLevel="signature" />
+
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+ <application
+ android:allowClearUserData="true"
+ android:label="@string/app_label"
+ android:allowBackup="false"
+ android:supportsRtl="true">
+
+ <service
+ android:name=".DeviceDiscoveryService"
+ android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+ android:exported="true">
+ </service>
+
+ <activity
+ android:name=".DeviceChooserActivity"
+ android:theme="@*android:style/Theme.Dialog.NoFrame"
+ android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE">
+ <!--TODO include url scheme filter similar to PrintSpooler -->
+ <intent-filter>
+ <action android:name="android.companiondevice.START_DISCOVERY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2 b/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2
diff --git a/packages/CompanionDeviceManager/NOTICE b/packages/CompanionDeviceManager/NOTICE
new file mode 100644
index 000000000000..c5b1efa7aac7
--- /dev/null
+++ b/packages/CompanionDeviceManager/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/packages/CompanionDeviceManager/res/layout/device_chooser.xml b/packages/CompanionDeviceManager/res/layout/device_chooser.xml
new file mode 100644
index 000000000000..ee08582ba2df
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/device_chooser.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="0.1"
+ >
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ style="@*android:style/TextAppearance.Widget.Toolbar.Title"
+ />
+
+ <ListView
+ android:id="@+id/device_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/title"
+ android:layout_above="@+id/buttons"
+ style="@android:style/Widget.Material.Light.ListView"
+ />
+
+ <LinearLayout
+ android:id="@+id/buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:gravity="end"
+ >
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Cancel"
+ style="@android:style/Widget.Material.Light.Button.Borderless.Colored"
+ />
+ <Button
+ android:id="@+id/button_pair"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Pair"
+ style="@android:style/Widget.Material.Light.Button.Borderless.Colored"
+ />
+ </LinearLayout>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/dimens.xml b/packages/CompanionDeviceManager/res/values/dimens.xml
new file mode 100644
index 000000000000..da7b0d1447c1
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Padding applied on most UI elements -->
+ <dimen name="padding">12dp</dimen>
+
+</resources> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
new file mode 100644
index 000000000000..c4195b5090a3
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Title of the CompanionDeviceManager application. [CHAR LIMIT=50] -->
+ <string name="app_label">Companion Device Manager</string>
+
+ <!-- Title of the device selection dialog. -->
+ <string name="chooser_title">Pair with &lt;strong&gt;<xliff:g id="app_name" example="Android Wear">%1$s</xliff:g>&lt;/strong&gt; via Bluetooth?</string>
+
+</resources>
diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml
new file mode 100644
index 000000000000..465f8fc6d5ac
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <!--TODO-->
+ <!--<style name="Theme.ChooserActivity" parent="@*android:style/Theme.Dialog.NoFrame">-->
+ <!--&lt;!&ndash;<item name="android:windowBackground">@android:color/light_grey</item>&ndash;&gt;-->
+ <!--<item name="android:backgroundColor">@android:color/light_grey</item>-->
+ <!--</style>-->
+
+</resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
new file mode 100644
index 000000000000..c95f940807a9
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -0,0 +1,133 @@
+/*
+ * 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.companiondevicemanager;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothDevice;
+import android.companion.CompanionDeviceManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.text.Html;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class DeviceChooserActivity extends Activity {
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "DeviceChooserActivity";
+
+ private ListView mDeviceListView;
+ private View mPairButton;
+ private View mCancelButton;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent());
+
+ setContentView(R.layout.device_chooser);
+ setTitle(Html.fromHtml(getString(R.string.chooser_title, getCallingAppName()), 0));
+ getWindow().getDecorView().getRootView().setBackgroundColor(Color.LTGRAY); //TODO theme
+
+ if (getService().mDevicesFound.isEmpty()) {
+ Log.e(LOG_TAG, "About to show UI, but no devices to show");
+ }
+
+ final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter;
+ mDeviceListView = (ListView) findViewById(R.id.device_list);
+ mDeviceListView.setAdapter(adapter);
+ mDeviceListView.addFooterView(getProgressBar(), null, false);
+
+ mPairButton = findViewById(R.id.button_pair);
+ mPairButton.setOnClickListener((view) ->
+ onPairTapped(getService().mSelectedDevice));
+ adapter.registerDataSetObserver(new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ updatePairButtonEnabled();
+ }
+ });
+ updatePairButtonEnabled();
+ mCancelButton = findViewById(R.id.button_cancel);
+ mCancelButton.setOnClickListener((view) -> {
+ setResult(RESULT_CANCELED);
+ finish();
+ });
+ }
+
+ private CharSequence getCallingAppName() {
+ try {
+ final PackageManager packageManager = getPackageManager();
+ return packageManager.getApplicationLabel(
+ packageManager.getApplicationInfo(getService().mCallingPackage, 0));
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ final TextView titleView = (TextView) findViewById(R.id.title);
+ final int padding = getPadding(getResources());
+ titleView.setPadding(padding, padding, padding, padding);
+ titleView.setText(title);
+ }
+
+ //TODO put in resources xmls
+ private ProgressBar getProgressBar() {
+ final ProgressBar progressBar = new ProgressBar(this);
+ progressBar.setForegroundGravity(Gravity.CENTER_HORIZONTAL);
+ final int padding = getPadding(getResources());
+ progressBar.setPadding(padding, padding, padding, padding);
+ return progressBar;
+ }
+
+ static int getPadding(Resources r) {
+ return r.getDimensionPixelSize(R.dimen.padding);
+ //TODO
+// final float dp = r.getDisplayMetrics().density;
+// return (int)(12 * dp);
+ }
+
+ private void updatePairButtonEnabled() {
+ mPairButton.setEnabled(getService().mSelectedDevice != null);
+ }
+
+ private DeviceDiscoveryService getService() {
+ return DeviceDiscoveryService.sInstance;
+ }
+
+ protected void onPairTapped(BluetoothDevice selectedDevice) {
+ setResult(RESULT_OK,
+ new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice));
+ finish();
+ }
+
+ private void toast(String msg) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+ }
+} \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
new file mode 100644
index 000000000000..a3eec0dd5cb5
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -0,0 +1,273 @@
+/*
+ * 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.companiondevicemanager;
+
+import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayName;
+import static android.companion.BluetoothLEDeviceFilter.nullsafe;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.companion.AssociationRequest;
+import android.companion.BluetoothDeviceFilterUtils;
+import android.companion.BluetoothLEDeviceFilter;
+import android.companion.ICompanionDeviceManagerService;
+import android.companion.IOnAssociateCallback;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class DeviceDiscoveryService extends Service {
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "DeviceDiscoveryService";
+
+ static DeviceDiscoveryService sInstance;
+
+ private BluetoothAdapter mBluetoothAdapter;
+ private BluetoothLEDeviceFilter mFilter;
+ private ScanFilter mScanFilter;
+ private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
+ List<BluetoothDevice> mDevicesFound;
+ BluetoothDevice mSelectedDevice;
+ DevicesAdapter mDevicesAdapter;
+ IOnAssociateCallback mCallback;
+ String mCallingPackage;
+
+ private final ICompanionDeviceManagerService mBinder =
+ new ICompanionDeviceManagerService.Stub() {
+ @Override
+ public void startDiscovery(AssociationRequest request,
+ IOnAssociateCallback callback,
+ String callingPackage) throws RemoteException {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "startDiscovery() called with: filter = [" + request + "], callback = ["
+ + callback + "]");
+ }
+ mCallback = callback;
+ mCallingPackage = callingPackage;
+ DeviceDiscoveryService.this.startDiscovery(request);
+ }
+ };
+
+ private final ScanCallback mBLEScanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ final BluetoothDevice device = result.getDevice();
+ if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
+ onDeviceLost(device);
+ } else {
+ onDeviceFound(device);
+ }
+ }
+ };
+
+ private BluetoothLeScanner mBLEScanner;
+
+ private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final BluetoothDevice device = intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE);
+ if (!mFilter.matches(device)) return; // ignore device
+
+ if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
+ onDeviceFound(device);
+ } else {
+ onDeviceLost(device);
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (DEBUG) Log.i(LOG_TAG, "onBind(" + intent + ")");
+ return mBinder.asBinder();
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ if (DEBUG) Log.i(LOG_TAG, "onCreate()");
+
+ mBluetoothAdapter = getSystemService(BluetoothManager.class).getAdapter();
+ mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
+
+ mDevicesFound = new ArrayList<>();
+ mDevicesAdapter = new DevicesAdapter();
+
+ sInstance = this;
+ }
+
+ private void startDiscovery(AssociationRequest<?> request) {
+ //TODO support other protocols as well
+ mFilter = nullsafe((BluetoothLEDeviceFilter) request.getDeviceFilter());
+ mScanFilter = mFilter.getScanFilter();
+
+ reset();
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
+ intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
+
+ registerReceiver(mBluetoothDeviceFoundBroadcastReceiver, intentFilter);
+ mBluetoothAdapter.startDiscovery();
+
+ mBLEScanner.startScan(
+ Collections.singletonList(mScanFilter), mDefaultScanSettings, mBLEScanCallback);
+ }
+
+ private void reset() {
+ mDevicesFound.clear();
+ mSelectedDevice = null;
+ mDevicesAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ stopScan();
+ return super.onUnbind(intent);
+ }
+
+ private void stopScan() {
+ if (DEBUG) Log.i(LOG_TAG, "stopScan() called");
+ mBluetoothAdapter.cancelDiscovery();
+ mBLEScanner.stopScan(mBLEScanCallback);
+ unregisterReceiver(mBluetoothDeviceFoundBroadcastReceiver);
+ stopSelf();
+ }
+
+ private void onDeviceFound(BluetoothDevice device) {
+ if (mDevicesFound.contains(device)) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Considering device " + getDeviceDisplayName(device));
+ }
+
+ if (!mFilter.matches(device)) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Found device " + getDeviceDisplayName(device));
+ }
+ if (mDevicesFound.isEmpty()) {
+ onReadyToShowUI();
+ }
+ mDevicesFound.add(device);
+ mDevicesAdapter.notifyDataSetChanged();
+ }
+
+ //TODO also, on timeout -> call onFailure
+ private void onReadyToShowUI() {
+ try {
+ mCallback.onSuccess(PendingIntent.getActivity(
+ this, 0,
+ new Intent(this, DeviceChooserActivity.class),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_IMMUTABLE));
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void onDeviceLost(BluetoothDevice device) {
+ mDevicesFound.remove(device);
+ mDevicesAdapter.notifyDataSetChanged();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Lost device " + getDeviceDisplayName(device));
+ }
+ }
+
+ class DevicesAdapter extends ArrayAdapter<BluetoothDevice> {
+ private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth);
+
+ private Drawable icon(int drawableRes) {
+ Drawable icon = getResources().getDrawable(drawableRes, null);
+ icon.setTint(Color.DKGRAY);
+ return icon;
+ }
+
+ public DevicesAdapter() {
+ super(DeviceDiscoveryService.this, 0, mDevicesFound);
+ }
+
+ @Override
+ public View getView(
+ int position,
+ @Nullable View convertView,
+ @NonNull ViewGroup parent) {
+ TextView view = convertView instanceof TextView
+ ? (TextView) convertView
+ : newView();
+ bind(view, getItem(position));
+ return view;
+ }
+
+ private void bind(TextView textView, BluetoothDevice device) {
+ textView.setText(getDeviceDisplayName(device));
+ textView.setBackgroundColor(
+ device.equals(mSelectedDevice)
+ ? Color.GRAY
+ : Color.TRANSPARENT);
+ textView.setOnClickListener((view) -> {
+ mSelectedDevice = device;
+ notifyDataSetChanged();
+ });
+ }
+
+ //TODO move to a layout file
+ private TextView newView() {
+ final TextView textView = new TextView(DeviceDiscoveryService.this);
+ textView.setTextColor(Color.BLACK);
+ final int padding = DeviceChooserActivity.getPadding(getResources());
+ textView.setPadding(padding, padding, padding, padding);
+ textView.setCompoundDrawablesWithIntrinsicBounds(
+ BLUETOOTH_ICON, null, null, null);
+ textView.setCompoundDrawablePadding(padding);
+ return textView;
+ }
+ }
+}
diff --git a/packages/Keyguard/res/values-bn/strings.xml b/packages/Keyguard/res/values-bn/strings.xml
index 1a2a8dde99c1..64c01bb356e7 100644
--- a/packages/Keyguard/res/values-bn/strings.xml
+++ b/packages/Keyguard/res/values-bn/strings.xml
@@ -47,8 +47,8 @@
<string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"সিম কার্ডটি PUK কোড দিয়ে লক করা আছে৷"</string>
<string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"সিম কার্ড আনলক করা হচ্ছে…"</string>
<string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"পিন অঞ্চল"</string>
- <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM পিন অঞ্চল"</string>
- <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK অঞ্চল"</string>
+ <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"সিম পিন অঞ্চল"</string>
+ <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"সিম PUK অঞ্চল"</string>
<string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> এ পরবর্তী অ্যালার্ম সেট করা হয়েছে"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মুছুন"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -59,11 +59,11 @@
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"আপনার প্যাটার্ন আঁকুন"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"সিম পিন লিখুন"</string>
- <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য SIM পিন লিখুন"</string>
+ <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য সিম পিন লিখুন"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"পিন লিখুন"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"পাসওয়ার্ড লিখুন"</string>
<string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"সিম এখন অক্ষম করা হয়েছে৷ অবিরত থাকতে PUK কোডটি লিখুন৷ বিশদ বিবরণের জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" এখন অক্ষম করা হয়েছে৷ চালিয়ে যেতে PUK কোড লিখুন৷ বিস্তারিত জানার জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"সিম \"<xliff:g id="CARRIER">%1$s</xliff:g>\" এখন অক্ষম করা হয়েছে৷ চালিয়ে যেতে PUK কোড লিখুন৷ বিস্তারিত জানার জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
<string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"কাঙ্ক্ষিত পিন কোড লিখুন"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"কাঙ্ক্ষিত পিন কোড নিশ্চিত করুন"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"সিম কার্ড আনলক করা হচ্ছে…"</string>
@@ -91,13 +91,13 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ভুল সিম পিন কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
- <item quantity="one">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
- <item quantity="other">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+ <item quantity="one">ভুল সিম পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+ <item quantity="other">ভুল সিম পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIMটি ব্যবহারের অযোগ্য৷ আপনার ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
- <item quantity="one">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
- <item quantity="other">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+ <item quantity="one">ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+ <item quantity="other">ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
</plurals>
<string name="kg_password_pin_failed" msgid="6268288093558031564">"সিম পিন ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
<string name="kg_password_puk_failed" msgid="2838824369502455984">"সিম PUK ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index b98a2536c2d2..0fb741684e0c 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -58,7 +58,7 @@
<string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM-kort"</string>
<string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Indtast SIM-pinkoden for \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
@@ -105,13 +105,13 @@
<string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
<string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Skift indtastningsmetode"</string>
<string name="airplane_mode" msgid="3122107900897202805">"Flytilstand"</string>
- <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du skal indtaste et mønster efter genstart af enheden"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du skal angive et mønster efter genstart af enheden"</string>
<string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Der skal indtaste en pinkode efter genstart af enheden"</string>
<string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Du skal indtaste en adgangskode efter genstart af enheden"</string>
<string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Der kræves et mønster som ekstra beskyttelse"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Der kræves en pinkode som ekstra beskyttelse"</string>
<string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Der kræves en adgangskode som ekstra beskyttelse"</string>
- <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du skal indtaste et mønster, når du skifter profil"</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du skal angive et mønster, når du skifter profil"</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Du skal indtaste en pinkode, når du skifter profil"</string>
<string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Du skal indtaste en adgangskode, når du skifter profil"</string>
<string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"Enhedsadministratoren har låst enheden"</string>
diff --git a/packages/MtpDocumentsProvider/res/values-ml/strings.xml b/packages/MtpDocumentsProvider/res/values-ml/strings.xml
index f357f96822b2..49eb847b1173 100644
--- a/packages/MtpDocumentsProvider/res/values-ml/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-ml/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="6271216747302322594">"MTP ഹോസ്റ്റ്"</string>
- <string name="downloads_app_label" msgid="7120690641874849726">"ഡൗൺലോഡുകൾ"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ഡൗണ്‍ലോഡുകൾ"</string>
<string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
<string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ഉപകരണത്തിൽ നിന്ന് ഫയലുകൾ ആക്സസ്സ് ചെയ്യുന്നു"</string>
<string name="error_busy_device" msgid="3997316850357386589">"രണ്ടാമത്തെ ഉപകരണം തിരക്കിലാണ്. അത് ലഭ്യമാകുന്നത് വരെ നിങ്ങൾക്ക് ഫയലുകൾ കൈമാറാൻ കഴിയില്ല."</string>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 8b0e610c9af8..b8c10a6a3366 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -509,7 +509,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final DeviceToolkit toolkit =
new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
mDeviceToolkits.put(deviceId, toolkit);
- mIntentSender.sendUpdateNotificationIntent();
+ mIntentSender.sendUpdateNotificationIntent(device);
try {
mRootScanner.resume().await();
} catch (InterruptedException error) {
@@ -526,7 +526,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
closeDeviceInternal(deviceId);
}
mRootScanner.resume();
- mIntentSender.sendUpdateNotificationIntent();
+ mIntentSender.sendUpdateNotificationIntent(null);
}
MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index c8846ce3fc1e..664d3c99344b 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -19,13 +19,12 @@ package com.android.mtp;
import android.app.Notification;
import android.app.Service;
import android.app.NotificationManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
-import android.util.Log;
-
-import java.io.IOException;
+import android.service.notification.StatusBarNotification;
+import java.util.HashSet;
+import java.util.Set;
/**
* Service to manage lifetime of DocumentsProvider's process.
@@ -33,12 +32,10 @@ import java.io.IOException;
* starts to run when the first MTP device is opened, and stops when the last MTP device is closed.
*/
public class MtpDocumentsService extends Service {
- static final String ACTION_OPEN_DEVICE = "com.android.mtp.OPEN_DEVICE";
- static final String ACTION_CLOSE_DEVICE = "com.android.mtp.CLOSE_DEVICE";
static final String ACTION_UPDATE_NOTIFICATION = "com.android.mtp.UPDATE_NOTIFICATION";
static final String EXTRA_DEVICE = "device";
- NotificationManager mNotificationManager;
+ private NotificationManager mNotificationManager;
@Override
public IBinder onBind(Intent intent) {
@@ -67,39 +64,53 @@ public class MtpDocumentsService extends Service {
*/
private boolean updateForegroundState() {
final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
- int notificationId = 0;
- Notification notification = null;
- // TODO: Hide notification if the device has already been removed.
+ final Set<Integer> openedNotification = new HashSet<>();
+ boolean hasForegroundNotification = false;
+
+ final StatusBarNotification[] activeNotifications =
+ mNotificationManager.getActiveNotifications();
+
for (final MtpDeviceRecord record : provider.getOpenedDeviceRecordsCache()) {
- final String title = getResources().getString(
- R.string.accessing_notification_title,
- record.name);
- notificationId = record.deviceId;
- notification = new Notification.Builder(this)
- .setLocalOnly(true)
- .setContentTitle(title)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .build();
- mNotificationManager.notify(record.deviceId, notification);
+ openedNotification.add(record.deviceId);
+ if (!hasForegroundNotification) {
+ // Mark this service as foreground with the notification so that the process is not
+ // killed by the system while a MTP device is opened.
+ startForeground(record.deviceId, createNotification(this, record));
+ hasForegroundNotification = true;
+ } else {
+ // Only one notification can be shown as a foreground notification. We need to show
+ // the rest as normal notification.
+ mNotificationManager.notify(record.deviceId, createNotification(this, record));
+ }
}
- if (notification != null) {
- startForeground(notificationId, notification);
- return true;
- } else {
+ for (final StatusBarNotification notification : activeNotifications) {
+ if (!openedNotification.contains(notification.getId())) {
+ mNotificationManager.cancel(notification.getId());
+ }
+ }
+
+ if (!hasForegroundNotification) {
+ // There is no opened device.
stopForeground(true /* removeNotification */);
stopSelf();
return false;
}
+
+ return true;
}
- private static void logErrorMessage(Exception exp) {
- if (exp.getMessage() != null) {
- Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
- } else {
- Log.e(MtpDocumentsProvider.TAG, exp.toString());
- }
+ public static Notification createNotification(Context context, MtpDeviceRecord device) {
+ final String title = context.getResources().getString(
+ R.string.accessing_notification_title,
+ device.name);
+ return new Notification.Builder(context)
+ .setLocalOnly(true)
+ .setContentTitle(title)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setFlag(Notification.FLAG_NO_CLEAR, true)
+ .build();
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
index a1bb2c13d386..d8c3d357b563 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
@@ -16,6 +16,8 @@
package com.android.mtp;
+import android.annotation.Nullable;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,9 +32,22 @@ class ServiceIntentSender {
mContext = context;
}
- void sendUpdateNotificationIntent() {
+ /**
+ * Notify the change of opened device set.
+ * @param record If a new device is opened, pass the device record. If a device is closed, pass
+ * null.
+ */
+ void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {
final Intent intent = new Intent(MtpDocumentsService.ACTION_UPDATE_NOTIFICATION);
intent.setComponent(new ComponentName(mContext, MtpDocumentsService.class));
- mContext.startService(intent);
+ final NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ if (record != null) {
+ manager.startServiceInForeground(
+ intent,
+ record.deviceId,
+ MtpDocumentsService.createNotification(mContext, record));
+ } else {
+ mContext.startService(intent);
+ }
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
index d4a4a487d8ee..74dd429d8af5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
@@ -16,11 +16,13 @@
package com.android.mtp;
+import android.annotation.Nullable;
+
class TestServiceIntentSender extends ServiceIntentSender {
TestServiceIntentSender() {
super(null);
}
@Override
- void sendUpdateNotificationIntent() {}
+ void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {}
}
diff --git a/packages/SettingsLib/res/color/batterymeter_bolt_color.xml b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml
new file mode 100644
index 000000000000..34de5489a28b
--- /dev/null
+++ b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/batterymeter_charge_color.xml b/packages/SettingsLib/res/color/batterymeter_charge_color.xml
new file mode 100644
index 000000000000..15944c3a2a07
--- /dev/null
+++ b/packages/SettingsLib/res/color/batterymeter_charge_color.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorForeground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/batterymeter_frame_color.xml b/packages/SettingsLib/res/color/batterymeter_frame_color.xml
new file mode 100644
index 000000000000..34de5489a28b
--- /dev/null
+++ b/packages/SettingsLib/res/color/batterymeter_frame_color.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
new file mode 100644
index 000000000000..c8a80ac57c00
--- /dev/null
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.24" android:color="?android:attr/colorBackground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
new file mode 100644
index 000000000000..8dcfdbb8cf1e
--- /dev/null
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.47" android:color="?android:attr/colorBackground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
new file mode 100644
index 000000000000..34de5489a28b
--- /dev/null
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
new file mode 100644
index 000000000000..15944c3a2a07
--- /dev/null
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorForeground" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index b120ffe52529..dbfc5655d3f8 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Gebruik HDCP-kontrolering net vir DRM-inhoud"</item>
<item msgid="45075631231212732">"Gebruik altyd HDCP-kontrolering"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX-HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX-HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="5618929009984956469">"16 bis per voorbeeld"</item>
+ <item msgid="3412640499234627248">"24 bis per voorbeeld"</item>
+ <item msgid="121583001492929387">"32 bis per voorbeeld"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="4726688794884191540">"16 bis per voorbeeld"</item>
+ <item msgid="305344756485516870">"24 bis per voorbeeld"</item>
+ <item msgid="244568657919675099">"32 bis per voorbeeld"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Gebruik stelselkeuse (verstek)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Geoptimeer vir oudiogehalte (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Gebalanseerde oudio- en verbindinggehalte (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Geoptimeer vir verbindinggehalte (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Geoptimeer vir oudiogehalte"</item>
+ <item msgid="4327143584633311908">"Gebalanseerde oudio- en verbindinggehalte"</item>
+ <item msgid="4681409244565426925">"Geoptimeer vir verbindinggehalte"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Af"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 63fa08c6dead..c103b0b45c6d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Sellulêre data altyd aktief"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiveer absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-oudiokodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Kies Bluetooth-oudiokodek"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-oudiovoorbeeldkoers"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Kies Bluetooth-oudiokodek:\nVoorbeeldtempo"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-oudiobisse per voorbeeld"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Kies Bluetooth-oudiokodek:\nBis per voorbeeld"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth-oudiokanaalmodus"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Kies Bluetooth-oudiokodek:\nKanaalmodus"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-oudio-LDAC-kodek: Speelgehalte"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Kies Bluetooth-oudio-LDAC-kodek:\nSpeelgehalte"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Stroming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wanneer dit geaktiveer is, sal Wi-Fi meer aggressief wees om die dataverbinding na selfoon oor te dra wanneer die Wi-Fi-sein swak is"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"MGT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Voer wagwoord in om fabriekterugstelling in demonstrasiemodus uit te voer"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Volgende"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Wagwoord word benodig"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 5f35d32cce07..7fdc06a9d6e1 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ለDRM ይዘት ብቻ HDCP ምልከታን ተጠቀም"</item>
<item msgid="45075631231212732">"ሁልጊዜ የHDCP ምልከታ ተጠቀም"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="8895532488906185219">"44.1 ኪኸ"</item>
+ <item msgid="2909915718994807056">"48.0 ኪኸ"</item>
+ <item msgid="3347287377354164611">"88.2 ኪኸ"</item>
+ <item msgid="1234212100239985373">"96.0 ኪኸ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="4482862757811638365">"44.1 ኪኸ"</item>
+ <item msgid="354495328188724404">"48.0 ኪኸ"</item>
+ <item msgid="7329816882213695083">"88.2 ኪኸ"</item>
+ <item msgid="6967397666254430476">"96.0 ኪኸ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="5618929009984956469">"16 ቢት/ናሙና"</item>
+ <item msgid="3412640499234627248">"24 ቢት/ናሙና"</item>
+ <item msgid="121583001492929387">"32 ቢት/ናሙና"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="4726688794884191540">"16 ቢት/ናሙና"</item>
+ <item msgid="305344756485516870">"24 ቢት/ናሙና"</item>
+ <item msgid="244568657919675099">"32 ቢት/ናሙና"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="4106832974775067314">"ሞኖ"</item>
+ <item msgid="5571632958424639155">"ስቲሪዮ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="8900559293912978337">"ሞኖ"</item>
+ <item msgid="8883739882299884241">"ስቲሪዮ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ለኦዲዮ ጥራት ተብቷል (990 ኪቢ/ሴ / 909 ኪቢ/ሴ)"</item>
+ <item msgid="2921767058740704969">"ለኦዲዮ ጥራት አትባ (660 ኪቢ/ሴ / 606 ኪቢ/ሴ)"</item>
+ <item msgid="8860982705384396512">"ለግንኙነት ጥራት ተብቷል (330 ኪቢ/ሴ / 303 ኪቢ/ሴ)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ለኦዲዮ ጥራት ተብቷል"</item>
+ <item msgid="4327143584633311908">"የተመጣጠነ የኦዲዮ እና ግንኙነት ጥራት"</item>
+ <item msgid="4681409244565426925">"ለግንኙነት ጥራት ተብቷል"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ጠፍቷል"</item>
<item msgid="1593289376502312923">"64 ኪባ"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 8ecef6ef2bfd..772582706d91 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"የተንቀስቃሽ ስልክ ውሂብ ሁልጊዜ ንቁ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"የብሉቱዝ ኦዲዮ ኮዴክ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"የብሉቱዝ ኦዲዮ ኮዴክ ይምረጡ"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"የብሉቱዝ ኦዲዮ ናሙና ፍጥነት"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"የብሉቱዝ ኦዲዮ ኮዴክ ይምረጡ፦\nየናሙና ፍጥነት"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"የብሉቱዝ ኦዲዮ ቢት በናሙና"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"የብሉቱዝ ኦዲዮ ኮዴክ ይምረጡ፦\nቢት በናሙና"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"የብሉቱዝ ኦዲዮ ሰርጥ ሁነታ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"የብሉቱዝ ኦዲዮ ኮዴክ ይምረጡ፦\nየሰርጥ ሁነታ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"የብሉቱዝ ኦዲዮ LDAC ኮዴክ ይምረጡ፦ የመልሶ ማጫወት ጥራት"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"የብሉቱዝ ኦዲዮ LDAC ኮዴክ ይምረጡ፦\nየመልሶ ማጫወት ጥራት"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ዥረት፦ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ሲነቃ የWi‑Fi ምልክት ዝቅተኛ ሲሆን Wi‑Fi የውሂብ ግንኙነት ለተንቀሳቃሽ ማስረከብ ላይ ይበልጥ አስገዳጅ ይሆናል"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"ጂኤምቲ"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"የፋብሪካ ዳግም ማስጀመር በማሳያ ሁነታ ውስጥ ለማከናወን የይለፍ ቃል ያስገቡ"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ቀጣይ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"የይለፍ ቃል ያስፈልጋል"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index f7f771a9d797..a8976ad252b4 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"‏استخدام التحقق من HDCP لمحتوى DRM فقط"</item>
<item msgid="45075631231212732">"‏استخدام التحقق من HDCP دومًا"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="8895532488906185219">"44.1 كيلو هرتز"</item>
+ <item msgid="2909915718994807056">"48.0 كيلو هرتز"</item>
+ <item msgid="3347287377354164611">"88.2 كيلو هرتز"</item>
+ <item msgid="1234212100239985373">"96.0 كيلو هرتز"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="4482862757811638365">"44.1 كيلو هرتز"</item>
+ <item msgid="354495328188724404">"48.0 كيلو هرتز"</item>
+ <item msgid="7329816882213695083">"88.2 كيلو هرتز"</item>
+ <item msgid="6967397666254430476">"96.0 كيلو هرتز"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="5618929009984956469">"16 بت لكل عيّنة"</item>
+ <item msgid="3412640499234627248">"24 بت لكل عيّنة"</item>
+ <item msgid="121583001492929387">"32 بت لكل عيّنة"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="4726688794884191540">"16 بت لكل عيّنة"</item>
+ <item msgid="305344756485516870">"24 بت لكل عيّنة"</item>
+ <item msgid="244568657919675099">"32 بت لكل عيّنة"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="4106832974775067314">"أحادي"</item>
+ <item msgid="5571632958424639155">"استريو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"استخدام اختيار النظام (افتراضي)"</item>
+ <item msgid="8900559293912978337">"أحادي"</item>
+ <item msgid="8883739882299884241">"استريو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"تحسين جودة الصوت (٩٩٠ كيلوبت في الثانية / ٩٠٩ كيلوبت في الثانية)"</item>
+ <item msgid="2921767058740704969">"جودة متوازنة للصوت والاتصال (660 كيلوبت في الثانية/606 كيلوبت في الثانية)"</item>
+ <item msgid="8860982705384396512">"تحسين جودة الاتصال (٣٣٠ كيلوبت في الثانية / ٣٠٣ كيلوبت في الثانية)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"تحسين جودة الصوت"</item>
+ <item msgid="4327143584633311908">"جودة متوازنة للصوت والاتصال"</item>
+ <item msgid="4681409244565426925">"تحسين جودة الاتصال"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"إيقاف"</item>
<item msgid="1593289376502312923">"٦٤ كيلوبايت"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 4a1e916363ae..fa7e2534880f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"بيانات الجوّال نشطة دائمًا"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"تعطيل مستوى الصوت المطلق"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ترميز صوت بلوتوث"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"اختيار برنامج الترميز لصوت البلوتوث"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"معدّل عيّنة صوت بلوتوث"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"اختيار برنامج ترميز صوت البلوتوث:\nمعدل العينة"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"وحدات البت لكل عيّنة في صوت بلوتوث"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"اختيار برنامج ترميز صوت البلوتوث:\nوحدات بت لكل عينة"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"وضع قناة صوت بلوتوث"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"اختيار برنامج ترميز صوت البلوتوث:\nوضع القناة"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"‏برنامج ترميز LDAC لصوت البلوتوث: جودة التشغيل"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"‏اختيار برنامج ترميز LDAC لصوت البلوتوث:\nجودة التشغيل"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"البث: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏عند تمكينه، سيكون Wi-Fi أكثر حدة في تسليم اتصال البيانات إلى الشبكة الخلوية، وذلك عندما تكون إشارة WiFi منخفضة"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"غرينيتش"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"إدخال كلمة المرور لإعادة الضبط بحسب بيانات المصنع في الوضع التجريبي"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"التالي"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"يلزم توفر كلمة مرور"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index 9ad0c28eb2ea..7a147d520d8d 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Yalnız DRM məzmun oxumaq üçün HDCP istifadə edin"</item>
<item msgid="45075631231212732">"Həmişə HDCP yoxlama istifadə edin"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="5618929009984956469">"16 bit/nümunə"</item>
+ <item msgid="3412640499234627248">"24 bit/nümunə"</item>
+ <item msgid="121583001492929387">"32 bit/nümunə"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="4726688794884191540">"16 bit/nümunə"</item>
+ <item msgid="305344756485516870">"24 bit/nümunə"</item>
+ <item msgid="244568657919675099">"32 bit/nümunə"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Audio Keyfiyyəti üçün optimallaşdırıldı (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanslı Audio və Bağlantı Keyfiyyəti (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Bağlantı Keyfiyyəti üçün optimallaşdırıldı (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Audio Keyfiyyəti üçün optimallaşdırıldı"</item>
+ <item msgid="4327143584633311908">"Balanslı Audio və Bağlantı Keyfiyyəti"</item>
+ <item msgid="4681409244565426925">"Bağlantı Keyfiyyəti üçün optimallaşdırıldı"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Deaktiv"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index ac854c67a50a..70a8c49d6949 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil data həmişə aktivdir"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mütləq səs həcmi deaktiv edin"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth Audio Kodeki Seçin"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Nümunə Göstəricisi"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth Audio Kodekini Seçin:\nNümunə Dərəcəsi"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Hər Nümunə Üçün Bluetooth Audio Bit"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth Audio Kodekini Seçin:\nHər Nümunə üçün Bit"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Kanal Rejimi"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth Audio Kodekini Seçin:\nKanal Rejimi"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Kodeki:Oxutma Keyfiyyəti"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Audio LDAC Kodek:\nOxutma Keyfiyyəti Seçin"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Canlı yayım: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aktiv olanda, Wi‑Fi sianqlı zəif olan zaman, Mobil şəbəkə data bağlantısına nisbətən, Wi‑Fi daha aqressiv olacaq"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Demo rejimində sıfırlamaq üçün parol daxil edin"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Növbəti"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Parol tələb olunur"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index bde7f584c801..4498939a4064 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Koristi HDCP proveru samo za DRM sadržaj"</item>
<item msgid="45075631231212732">"Uvek koristi HDCP proveru"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="5618929009984956469">"16 bitova po uzorku"</item>
+ <item msgid="3412640499234627248">"24 bita po uzorku"</item>
+ <item msgid="121583001492929387">"32 bita po uzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="4726688794884191540">"16 bitova po uzorku"</item>
+ <item msgid="305344756485516870">"24 bita po uzorku"</item>
+ <item msgid="244568657919675099">"32 bita po uzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Koristi izbor sistema (podrazumevano)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizovano za kvalitet zvuka (990 kb/s/909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Ujednačen kvalitet zvuka i veze (660 kb/s/606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimizovano za kvalitet veze (330 kb/s/303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizovano za kvalitet zvuka"</item>
+ <item msgid="4327143584633311908">"Ujednačen kvalitet zvuka i veze"</item>
+ <item msgid="4681409244565426925">"Optimizovano za kvalitet veze"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Isključeno"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 62be8b29a954..0aa9524f7e9d 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Podaci za mobilne uređaje su uvek aktivni"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući glavno podešavanje jačine zvuka"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Izaberite Bluetooth audio kodek"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorkovanja za Bluetooth audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Izaberite Bluetooth audio kodek:\nbrzina uzorkovanja"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bitova po uzorku za Bluetooth audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Izaberite Bluetooth audio kodek:\nbitova po uzorku"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Režim kanala za Bluetooth audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Izaberite Bluetooth audio kodek:\nrežim kanala"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audio kodek LDAC: kvalitet reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Izaberite Bluetooth audio kodek LDAC:\nkvalitet reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strimovanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na Mobilnu, kada je Wi‑Fi signal slab"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite lozinku da biste obavili resetovanje na fabrička podešavanja u režimu demonstracije"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalje"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Potrebna je lozinka"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index 50842cf8a382..b2031cbc2567 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Выкарыстанне праверкі HDCP только для змесціва, абароненага DRM"</item>
<item msgid="45075631231212732">"Заўсёды выкарыстоўваць праверку HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="8895532488906185219">"44,1 кГц"</item>
+ <item msgid="2909915718994807056">"48,0 кГц"</item>
+ <item msgid="3347287377354164611">"88,2 кГц"</item>
+ <item msgid="1234212100239985373">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="4482862757811638365">"44,1 кГц"</item>
+ <item msgid="354495328188724404">"48,0 кГц"</item>
+ <item msgid="7329816882213695083">"88,2 кГц"</item>
+ <item msgid="6967397666254430476">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="5618929009984956469">"16 бітаў/сэмпл"</item>
+ <item msgid="3412640499234627248">"24 біты/сэмпл"</item>
+ <item msgid="121583001492929387">"32 біты/сэмпл"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="4726688794884191540">"16 бітаў/сэмпл"</item>
+ <item msgid="305344756485516870">"24 біты/сэмпл"</item>
+ <item msgid="244568657919675099">"32 біты/сэмпл"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="4106832974775067314">"Мона"</item>
+ <item msgid="5571632958424639155">"Стэрэа"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="8900559293912978337">"Мона"</item>
+ <item msgid="8883739882299884241">"Стэрэа"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Аптымізавана якасць гуку (990 кбіт/c / 909 кбіт/c)"</item>
+ <item msgid="2921767058740704969">"Збалансаваная якасць аўдыя і падключэння (660кбіт/c / 606 кбіт/c)"</item>
+ <item msgid="8860982705384396512">"Аптымізавана якасць падключэння (330 кбіт/c / 303 кбіт/c)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Аптымізавана якасць гуку"</item>
+ <item msgid="4327143584633311908">"Збалансаваная якасць аўдыя і падключэння"</item>
+ <item msgid="4681409244565426925">"Аптымізавана якасць падключэння"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Выкл."</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f50253bac650..876f125ea954 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Перадача даных мабільнай сувязі заўсёды актыўна"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодэк Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Выбраць аўдыякодэк Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частата дыскрэтызацыі Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Выбраць аўдыякодэк Bluetooth:\nчастата дыскрэтызацыі"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Біты на сэмпл для Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Выбраць аўдыякодэк Bluetooth:\nбіты на сэмпл"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Канальны рэжым Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Выбраць аўдыякодэк Bluetooth:\nканальны рэжым"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Аўдыякодэк Bluetooth LDAC: якасць прайгравання"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Выбраць аўдыякодэк Bluetooth LDAC:\nякасць прайгравання"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Перадача плынню: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Падвыс. узровень дэтал-цыі журнала Wi‑Fi у залежн. ад SSID RSSI у Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Калі ўкл., прылада будзе больш інтэнсіўна імкнуцца перайсці з падлуч. да Wi-Fi на падлуч. да маб. сеткі, калі сігнал Wi‑Fi слабы"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Каб выканаць скід да заводскіх налад у дэманстрацыйным рэжыме, увядзіце пароль"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Далей"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Патрабуецца пароль"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index c97e5f5fb67e..9bc32a313065 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Да се използва проверка с HDCP само за DRM съдържание"</item>
<item msgid="45075631231212732">"Винаги да се използва проверка с HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"Разширено аудиокодиране (AAC)"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"Разширено аудиокодиране (AAC)"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="8895532488906185219">"44,1 кХц"</item>
+ <item msgid="2909915718994807056">"48 кХц"</item>
+ <item msgid="3347287377354164611">"88,2 кХц"</item>
+ <item msgid="1234212100239985373">"96 кХц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="4482862757811638365">"44,1 кХц"</item>
+ <item msgid="354495328188724404">"48 кХц"</item>
+ <item msgid="7329816882213695083">"88,2 кХц"</item>
+ <item msgid="6967397666254430476">"96 кХц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="5618929009984956469">"16 бита/дискрет"</item>
+ <item msgid="3412640499234627248">"24 бита/дискрет"</item>
+ <item msgid="121583001492929387">"32 бита/дискрет"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="4726688794884191540">"16 бита/дискрет"</item>
+ <item msgid="305344756485516870">"24 бита/дискрет"</item>
+ <item msgid="244568657919675099">"32 бита/дискрет"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Оптимизирано за качество на звука (990 или 909 кб/сек)"</item>
+ <item msgid="2921767058740704969">"Балансирано качество на звука и връзката (660 или 606 кб/сек)"</item>
+ <item msgid="8860982705384396512">"Оптимизирано за качество на връзката (330 или 303 кб/сек)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Оптимизирано за качество на звука"</item>
+ <item msgid="4327143584633311908">"Балансирано качество на звука и връзката"</item>
+ <item msgid="4681409244565426925">"Оптимизирано за качество на връзката"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Изключено"</item>
<item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c0d43b2c75d5..351b4891b3cd 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Винаги активни клетъчни данни"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Деактивиране на пълната сила на звука"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек за Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Изберете аудиокодек за Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Честота на дискретизация за звука през Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Изберете аудиокодек за Bluetooth:\nЧестота на дискретизация"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Битове на дискрет за звука през Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Изберете аудиокодек за Bluetooth:\nБитове на дискрет"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим на канала на звука през Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Изберете аудиокодек за Bluetooth:\nРежим на канала"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек за звука през Bluetooth с технологията LDAC: Качество на възпроизвеждане"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изберете кодек за звука през Bluetooth с технологията LDAC:\nКачество на възпроизвеждане"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Поточно предаване: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"При активиране предаването на връзката за данни от Wi-Fi към мобилната мрежа ще е по-агресивно, когато Wi-Fi сигналът е слаб"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"Средно време по Гринуич (GMT)"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Въведете парола за възст. на фабр. настройки в демонстр. режим"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Напред"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Изисква се парола"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index faea551b0b82..b40bfd4662ba 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"শুধুমাত্র DRM সামগ্রীর জন্য HDCP চেক করা ব্যবহার করুন"</item>
<item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="8895532488906185219">"৪৪.১ kHz"</item>
+ <item msgid="2909915718994807056">"৪৮.০ kHz"</item>
+ <item msgid="3347287377354164611">"৮৮.২ kHz"</item>
+ <item msgid="1234212100239985373">"৯৬.০ kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="4482862757811638365">"৪৪.১ kHz"</item>
+ <item msgid="354495328188724404">"৪৮.০ kHz"</item>
+ <item msgid="7329816882213695083">"৮৮.২ kHz"</item>
+ <item msgid="6967397666254430476">"৯৬.০ kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="5618929009984956469">"১৬ বিট/নমুনা"</item>
+ <item msgid="3412640499234627248">"২৪ বিট/নমুনা"</item>
+ <item msgid="121583001492929387">"৩২ বিট/নমুনা"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="4726688794884191540">"১৬ বিট/নমুনা"</item>
+ <item msgid="305344756485516870">"২৪ বিট/নমুনা"</item>
+ <item msgid="244568657919675099">"৩২ বিট/নমুনা"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="4106832974775067314">"মোনো"</item>
+ <item msgid="5571632958424639155">"স্টিরিও"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+ <item msgid="8900559293912978337">"মোনো"</item>
+ <item msgid="8883739882299884241">"স্টিরিও"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"অডিও গুণমানের জন্য অপ্টিমাইজ করা হয়েছে (৯৯০kbps/৯০৯kbps)"</item>
+ <item msgid="2921767058740704969">"সন্তুলিত গুণমানের অডিও এবং সংযোগ (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"সংযোগের গুণমানের জন্য অপটিমাইজ করা হয়েছে (৩৩০kbps/৩০৩kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"অডিও গুণমানের জন্য অপ্টিমাইজ করা হয়েছে"</item>
+ <item msgid="4327143584633311908">"সন্তুলিত গুণমানের অডিও এবং সংযোগ"</item>
+ <item msgid="4681409244565426925">"সংযোগের গুণমানের জন্য অপটিমাইজ করা হয়েছে"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"বন্ধ আছে"</item>
<item msgid="1593289376502312923">"৬৪K"</item>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 380ee1cdfc40..08f72276ef61 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -53,7 +53,7 @@
<string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"পরিচিতি শেয়ার করার কাজে ব্যবহার করুন"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ইন্টারনেট সংযোগ শেয়ার করা হচ্ছে"</string>
<string name="bluetooth_profile_map" msgid="5465271250454324383">"বার্তা অ্যাক্সেস"</string>
- <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM -এর অ্যাক্সেস"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"সিম -এর অ্যাক্সেস"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিওতে সংযুক্ত রয়েছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিওতে সংযুক্ত"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত"</string>
@@ -65,7 +65,7 @@
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ডিভাইসের সাথে স্থানীয় ইন্টারনেট সংযোগ ভাগ করছে"</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ইন্টারনেট অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"মানচিত্রের জন্য ব্যবহার করুন"</string>
- <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"সিম -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"মিডিয়া অডিওয়ের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"সেলুলার ডেটা সর্বদাই সক্রিয় থাকে"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ব্লুটুথ অডিও কোডেক"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ব্লুটুথ অডিও কোডেক বেছে নিন"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ব্লুটুথ অডিওর নমুনা হার"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ব্লুটুথ অডিও কোডেক বেছে নিন:\nস্যাম্পল রেট"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"নমুনা প্রতি ব্লুটুথ অডিও বিট"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ব্লুটুথ অডিও কোডেক বেছে নিন:\nবিটস পার স্যাম্পল"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ব্লুটুথ অডিও চ্যানেল মোড"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ব্লুটুথ অডিও কোডেক বেছে নিন:\nচ্যানেল মোড"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ব্লুটুথ অডিও LDAC কোডেক: প্লেব্যাক গুণমান"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ব্লুটুথ অডিও LDAC কোডেক বেছে নিন:\nপ্লেব্যাক গুণমান"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"স্ট্রিমিং: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"সক্ষম করা থাকলে, নিম্নমানের ওয়াই-ফাই সিগন্যালের ক্ষেত্রে, সেলুলার-এ ডেটা সংযোগ প্রদান করতে ওয়াই-ফাই আরো বেশি শক্তিশালীভাবে কাজ করবে"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ডেমো মোডে ফ্যাক্টরি রিসেট করতে পাসওয়ার্ড দিন"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"পরবর্তী"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"পাসওয়ার্ড আবশ্যক"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 6c4cde3cc5fa..1c3d3bf75ff3 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Koristi HDCP provjeru samo za DRM sadržaj"</item>
<item msgid="45075631231212732">"Uvijek koristi HDCP provjeru"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="5618929009984956469">"16 bitova/uzorak"</item>
+ <item msgid="3412640499234627248">"24 bitova/uzorak"</item>
+ <item msgid="121583001492929387">"32 bitova/uzorak"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="4726688794884191540">"16 bitova/uzorak"</item>
+ <item msgid="305344756485516870">"24 bitova/uzorak"</item>
+ <item msgid="244568657919675099">"32 bitova/uzorak"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Koristi odabir sistema (Zadano)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizirano za kvalitet zvuka (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Uravnotežen kvalitet zvuka i veze (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizirano za kvalitet veze (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizirano za kvalitet zvuka"</item>
+ <item msgid="4327143584633311908">"Uravnotežen kvalitet zvuka i veze"</item>
+ <item msgid="4681409244565426925">"Optimizirano za kvalitet veze"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Isključeno"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index bb0e1b502583..aaf97136a2ef 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogućite apsolutnu jačinu zvuka"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Odaberite Bluetooth Audio kodek"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorkovanja za Bluetooth audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Odaberite Bluetooth Audio kodek:\nBrzina uzorka"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio bitovi po uzorku"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Odaberite Bluetooth Audio kodek:\nBita po uzorku"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način Bluetooth audio kanala"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Odaberite Bluetooth Audio kodek:\nNačin rada kanala"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC kodek: Kvalitet reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Odaberite Bluetooth Audio LDAC kodek:\nKvalitet reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Prijenos: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada je omogućeno, Wi-Fi će biti agresivniji u predavanju podatkovne veze mobilnoj, kada je Wi-Fi signal slab"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite lozinku da izvršite vraćanje na fabričke postavke u načinu demonstracije"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Naprijed"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Potrebna je lozinka"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index fb57ab4f54d4..1627ea65d0d5 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utilitza la comprovació HDCP només per a contingut DRM"</item>
<item msgid="45075631231212732">"Utilitza sempre la comprovació HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="5618929009984956469">"16 bits/mostra"</item>
+ <item msgid="3412640499234627248">"24 bits/mostra"</item>
+ <item msgid="121583001492929387">"32 bits/mostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="4726688794884191540">"16 bits/mostra"</item>
+ <item msgid="305344756485516870">"24 bits/mostra"</item>
+ <item msgid="244568657919675099">"32 bits/mostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estèreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Utilitza selecció del sistema (predeterminada)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estèreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimitzat per a la qualitat de l\'àudio (990 kbps / 909 kbps)"</item>
+ <item msgid="2921767058740704969">"Qualitat equilibrada de l\'àudio i la connexió (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimitzat per a la qualitat de la connexió (330 kbps / 303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimitzat per a la qualitat de l\'àudio"</item>
+ <item msgid="4327143584633311908">"Qualitat equilibrada de l\'àudio i la connexió"</item>
+ <item msgid="4681409244565426925">"Optimitzat per a la qualitat de la connexió"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"No"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 4571e49bdf0f..391782b9228a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dades mòbils sempre actives"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Còdec d\'àudio per Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selecciona el còdec d\'àudio per Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Velocitat de mostra d’àudio per Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selecciona el còdec d\'àudio per Bluetooth:\nFreqüència de mostratge"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per mostra de l\'àudio per Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selecciona el còdec d\'àudio per Bluetooth:\nBits per mostra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de canal de l\'àudio per Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selecciona el còdec d\'àudio per Bluetooth:\nMode de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Còdec LDAC d\'àudio per Bluetooth: qualitat de reproducció"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecciona el còdec LDAC d\'àudio per Bluetooth:\nQualitat de reproducció"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"S\'està reproduint en temps real: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si s\'activa, la Wi-Fi serà més agressiva en transferir la connexió de dades al mòbil, si el senyal de la Wi-Fi no és estable"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Introdueix la contrasenya per restablir les dades de fàbrica en mode de demostració"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Següent"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Contrasenya obligatòria"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index 8c96ac382751..b56fadc6f976 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Použít kontrolu HDCP pouze pro obsah DRM"</item>
<item msgid="45075631231212732">"Vždy používat kontrolu HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="5618929009984956469">"16 bitů / vzorek"</item>
+ <item msgid="3412640499234627248">"24 bitů / vzorek"</item>
+ <item msgid="121583001492929387">"32 bitů / vzorek"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="4726688794884191540">"16 bitů / vzorek"</item>
+ <item msgid="305344756485516870">"24 bitů / vzorek"</item>
+ <item msgid="244568657919675099">"32 bitů / vzorek"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimalizováno pro kvalitu zvuku (990 kb/s / 909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Vyvážená kvalita zvuku a připojení (660 kb/s / 606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimalizováno pro kvalitu připojení (330 kb/s / 303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimalizováno pro kvalitu zvuku"</item>
+ <item msgid="4327143584633311908">"Vyvážená kvalita zvuku a připojení"</item>
+ <item msgid="4681409244565426925">"Optimalizováno pro kvalitu připojení"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Vypnuto"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 36017e2c2b4e..dc5b36a8ad5c 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilní data jsou vždy aktivní"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázat absolutní hlasitost"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Vyberte zvukový kodek Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio – vzorkovací frekvence"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Vyberte zvukový kodek Bluetooth:\nVzorkovací frekvence"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio – počet bitů na vzorek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Vyberte zvukový kodek Bluetooth:\nPočet bitů na vzorek"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio – režim kanálu"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Vyberte zvukový kodek Bluetooth:\nRežim kanálu"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek Bluetooth Audio LDAC: Kvalita přehrávání"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vyberte kodek Bluetooth Audio LDAC:\nKvalita přehrávání"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamování: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Pokud je tato možnost zapnuta, bude síť Wi-Fi agresivnější při předávání datového připojení mobilní síti při slabém signálu Wi-Fi."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Chcete-li v ukázkovém režimu obnovit zařízení do továrního nastavení, zadejte heslo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Další"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Je třeba zadat heslo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 1b54d4a07e14..a35f1bb21fb2 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Brug kun HDCP-kontrol ved DRM-indhold"</item>
<item msgid="45075631231212732">"Brug altid HDCP-kontrol"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Brug systemvalg (standard)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Brug systemvalg (standard)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Brug systemvalg (standard)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Brug systemvalg (standard)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Brug systemvalg (standard)"</item>
+ <item msgid="5618929009984956469">"16 bit pr. eksempel"</item>
+ <item msgid="3412640499234627248">"24 bit pr. eksempel"</item>
+ <item msgid="121583001492929387">"32 bit pr. eksempel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Brug systemvalg (standard)"</item>
+ <item msgid="4726688794884191540">"16 bit pr. eksempel"</item>
+ <item msgid="305344756485516870">"24 bit pr. eksempel"</item>
+ <item msgid="244568657919675099">"32 bit pr. eksempel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Brug systemvalg (standard)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Brug systemvalg (standard)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimeret til lydkvalitet (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Afbalancer lyd- og forbindelseskvalitet (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimeret til forbindelseskvalitet (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimeret til lydkvalitet"</item>
+ <item msgid="4327143584633311908">"Afbalancer lyd- og forbindelseskvalitet"</item>
+ <item msgid="4681409244565426925">"Optimeret til forbindelseskvalitet"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Fra"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 2824b81d385f..8071c83203ae 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata altid aktiveret"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiver absolut lydstyrke"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-lydcodec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Vælg codec for Bluetooth-lyd"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Eksempelfrekvens for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Vælg codec for Bluetooth-lyd:\nSamplingfrekvens"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit pr. eksempel for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Vælg codec for Bluetooth-lyd:\nBits pr. sampling"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanaltilstand for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Vælg codec for Bluetooth-lyd:\nKanaltilstand"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-codec for Bluetooth-lyd: Afspilningskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vælg LDAC-codec for Bluetooth-lyd:\nAfspilningskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamer: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Når dette er aktiveret, gennemtvinges en overdragelse af dataforbindelsen fra Wi-Fi til mobilnetværk, når Wi-Fi-signalet er svagt"</string>
@@ -209,7 +202,7 @@
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
- <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kontrollér apps via USB"</string>
+ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificer apps via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollér apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Angiv adgangskode for at gendanne fabriksdata i demotilstand"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Næste"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Angiv en adgangskode"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index 796e58f13ac9..6e580d2f39fa 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP-Prüfung nur für DRM-Inhalte verwenden"</item>
<item msgid="45075631231212732">"HDCP-Prüfung immer verwenden"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="5618929009984956469">"16 Bits pro Sample"</item>
+ <item msgid="3412640499234627248">"24 Bits pro Sample"</item>
+ <item msgid="121583001492929387">"32 Bits pro Sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="4726688794884191540">"16 Bits pro Sample"</item>
+ <item msgid="305344756485516870">"24 Bits pro Sample"</item>
+ <item msgid="244568657919675099">"32 Bits pro Sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Für Audioqualität optimiert (990 kbit/s/909 kbit/s)"</item>
+ <item msgid="2921767058740704969">"Ausgeglichene Audio- und Verbindungsqualität (660 kbit/s/606 kbit/s)"</item>
+ <item msgid="8860982705384396512">"Für Verbindungsqualität optimiert (330 kbit/s/303 kbit/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Für Audioqualität optimiert"</item>
+ <item msgid="4327143584633311908">"Ausgeglichene Audio- und Verbindungsqualität"</item>
+ <item msgid="4681409244565426925">"Für Verbindungsqualität optimiert"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Aus"</item>
<item msgid="1593289376502312923">"64.000"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 632866ec7e73..8dd4c1db28f7 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile Datennutzung immer aktiviert"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Maximallautstärke deaktivieren"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-Audio-Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth-Audio-Codec auswählen"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-Audio-Abtastrate"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth-Audio-Codec auswählen:\nAbtastrate"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-Audio/Bits pro Sample"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth-Audio-Codec auswählen:\nBits pro Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modus des Bluetooth-Audiokanals"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth-Audio-Codec auswählen:\nKanalmodus"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-Audio-LDAC-Codec: Wiedergabequalität"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth-Audio-LDAC-Codec auswählen:\nWiedergabequalität"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Level für WLAN-Protokollierung erhöhen, in WiFi Picker pro SSID-RSSI anzeigen"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wenn diese Option aktiviert ist, ist WLAN bei schwachem Signal bei der Übergabe der Datenverbindung an den Mobilfunk aggressiver."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Passwort eingeben, um Gerät im Demomodus auf Werkseinstellungen zurückzusetzen"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Weiter"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Passwort erforderlich"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 857420ca55c7..2b69f12bf6c4 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Χρήση ελέγχου HDCP μόνο για περιεχόμενο DRM"</item>
<item msgid="45075631231212732">"Να χρησιμοποιείται πάντα έλεγχος HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="5618929009984956469">"16 bit/δείγμα"</item>
+ <item msgid="3412640499234627248">"24 bit/δείγμα"</item>
+ <item msgid="121583001492929387">"32 bit/δείγμα"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="4726688794884191540">"16 bit/δείγμα"</item>
+ <item msgid="305344756485516870">"24 bit/δείγμα"</item>
+ <item msgid="244568657919675099">"32 bit/δείγμα"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="4106832974775067314">"Μονοφωνικό"</item>
+ <item msgid="5571632958424639155">"Στερεοφωνικό"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+ <item msgid="8900559293912978337">"Μονοφωνικό"</item>
+ <item msgid="8883739882299884241">"Στερεοφωνικό"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Βελτιστοποιημένο για ποιότητα ήχου (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Ισορροπημένος ήχος και ποιότητα σύνδεσης (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Βελτιστοποιημένο για ποιότητα σύνδεσης (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Βελτιστοποιημένο για ποιότητα ήχου"</item>
+ <item msgid="4327143584633311908">"Ισορροπημένος ήχος και ποιότητα σύνδεσης"</item>
+ <item msgid="4681409244565426925">"Βελτιστοποιημένο για ποιότητα σύνδεσης"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Ανενεργό"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 67365a336f13..1ee6db8a4a57 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Απενεργοποίηση απόλυτης έντασης"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Κωδικοποιητής ήχου Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Επιλογή κωδικοποιητή ήχου Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Ρυθμός δειγματοληψίας ήχου Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Επιλογή κωδικοποιητή ήχου Bluetooth:\nΠοσοστό δείγματος"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit ανά δείγμα ήχου Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Επιλογή κωδικοποιητή ήχου Bluetooth:\nBit ανά δείγμα"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Λειτουργία καναλιού ήχου Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Επιλογή κωδικοποιητή ήχου Bluetooth:\nΛειτουργία καναλιού"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Κωδικοποιητής LDAC ήχου Bluetooth: Ποιότητα αναπαραγωγής"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Επιλογή κωδικοποιητή LDAC ήχου Bluetooth:\nΠοιότητα αναπαραγωγής"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Ροή: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Όταν είναι ενεργό, το Wi-Fi θα μεταβιβάζει πιο επιθετικά τη σύνδ.δεδομένων σε δίκτυο κινητής τηλ., όταν το σήμα Wi-Fi είναι χαμηλό"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Εισαγάγετε κωδικό πρόσβασης για επαναφορά εργοστασιακών ρυθμίσεων στη λειτουργία επίδειξης"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Επόμενο"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Απαιτείται κωδικός πρόσβασης"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 4758019a1ff6..ef4975cbc2af 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Use System Selection (Default)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Use System Selection (Default)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Use System Selection (Default)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Use System Selection (Default)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Use System Selection (Default)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Use System Selection (Default)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimised for Audio Quality (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanced Audio And Connection Quality (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimised for Connection Quality (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimised for Audio Quality"</item>
+ <item msgid="4327143584633311908">"Balanced Audio and Connection Quality"</item>
+ <item msgid="4681409244565426925">"Optimised for Connection Quality"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Off"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index bb8fc15b4a57..1f641d51eb32 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Select Bluetooth Audio Codec"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Select Bluetooth Audio Codec:\nSample Rate"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Select Bluetooth Audio Codec:\nBits Per Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Select Bluetooth Audio Codec:\nChannel Mode"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Codec: Playback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Select Bluetooth Audio LDAC Codec:\nPlayback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Password required"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 4758019a1ff6..ef4975cbc2af 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Use System Selection (Default)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Use System Selection (Default)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Use System Selection (Default)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Use System Selection (Default)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Use System Selection (Default)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Use System Selection (Default)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimised for Audio Quality (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanced Audio And Connection Quality (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimised for Connection Quality (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimised for Audio Quality"</item>
+ <item msgid="4327143584633311908">"Balanced Audio and Connection Quality"</item>
+ <item msgid="4681409244565426925">"Optimised for Connection Quality"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Off"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index bb8fc15b4a57..1f641d51eb32 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Select Bluetooth Audio Codec"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Select Bluetooth Audio Codec:\nSample Rate"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Select Bluetooth Audio Codec:\nBits Per Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Select Bluetooth Audio Codec:\nChannel Mode"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Codec: Playback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Select Bluetooth Audio LDAC Codec:\nPlayback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Password required"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 4758019a1ff6..ef4975cbc2af 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Use System Selection (Default)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Use System Selection (Default)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Use System Selection (Default)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Use System Selection (Default)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Use System Selection (Default)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Use System Selection (Default)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimised for Audio Quality (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanced Audio And Connection Quality (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimised for Connection Quality (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimised for Audio Quality"</item>
+ <item msgid="4327143584633311908">"Balanced Audio and Connection Quality"</item>
+ <item msgid="4681409244565426925">"Optimised for Connection Quality"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Off"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index bb8fc15b4a57..1f641d51eb32 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Select Bluetooth Audio Codec"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Select Bluetooth Audio Codec:\nSample Rate"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Select Bluetooth Audio Codec:\nBits Per Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Select Bluetooth Audio Codec:\nChannel Mode"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Codec: Playback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Select Bluetooth Audio LDAC Codec:\nPlayback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Password required"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 4df4952c351c..f5f67fbce48c 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Usar comprobación HDCP para contenido DRM solamente"</item>
<item msgid="45075631231212732">"Siempre utilizar comprobación HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="5618929009984956469">"16 bits/muestra"</item>
+ <item msgid="3412640499234627248">"24 bits/muestra"</item>
+ <item msgid="121583001492929387">"32 bits/muestra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="4726688794884191540">"16 bits/muestra"</item>
+ <item msgid="305344756485516870">"24 bits/muestra"</item>
+ <item msgid="244568657919675099">"32 bits/muestra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizado para la calidad de audio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Calidad de audio y conexión equilibrada (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizado para la calidad de conexión (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizado para la calidad de audio"</item>
+ <item msgid="4327143584633311908">"Calidad de audio y conexión equilibrada"</item>
+ <item msgid="4681409244565426925">"Optimizado para calidad de conexión"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desactivado"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 9d9a087f7d0f..25ee5a836356 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec del audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Seleccionar códec del audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de muestreo del audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Seleccionar códec del audio Bluetooth:\nVelocidad de la muestra"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por muestra del audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Seleccionar códec del audio Bluetooth:\nBits por muestra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal del audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Seleccionar códec del audio Bluetooth:\nModo de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Códec del audio Bluetooth LDAC: calidad de reproducción"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleccionar códec del audio Bluetooth LDAC:\nCalidad de reproducción"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmitiendo: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más intensa al transferir la conexión de datos al celular (si la señal Wi‑Fi es débil)."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Ingresa contraseña y restablece en demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Siguiente"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Contraseña obligatoria"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index bf492c73c1a0..d5155c9e4a33 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utilizar comprobación de HDCP solo para contenido DRM"</item>
<item msgid="45075631231212732">"Utilizar siempre comprobación de HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="5618929009984956469">"16 bits por muestra"</item>
+ <item msgid="3412640499234627248">"24 bits por muestra"</item>
+ <item msgid="121583001492929387">"32 bits por muestra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="4726688794884191540">"16 bits por muestra"</item>
+ <item msgid="305344756485516870">"24 bits por muestra"</item>
+ <item msgid="244568657919675099">"32 bits por muestra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usar preferencia del sistema (predeter.)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizado para la calidad del audio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Equilibrar la calidad del audio y de la conexión (660/606&amp;nbsp;kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizado para la calidad de la conexión (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Se ha optimizado para la calidad del audio"</item>
+ <item msgid="4327143584633311908">"Equilibrar la calidad del audio y la de la conexión"</item>
+ <item msgid="4681409244565426925">"Se ha optimizado para la calidad de la conexión"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"No"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 2e4be1c084de..9d98096319a7 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selecciona el códec de audio por Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Porcentaje de muestreo de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selecciona el códec de audio por Bluetooth:\nFrecuencia de muestreo"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits de audio por Bluetooth por muestra"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selecciona el códec de audio por Bluetooth:\nBits por muestra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selecciona el códec de audio por Bluetooth:\nModo de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Selecciona el códec LDAC por Bluetooth: calidad de reproducción"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecciona el códec LDAC de audio por Bluetooth:\nCalidad de reproducción"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Escribe una contraseña para restablecer datos de fábrica en modo demostración"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Siguiente"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Contraseña obligatoria"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index ca60dfaf9f4c..07fe687e873f 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Kasuta HDCP-kontrolli ainult DRM-sisu korral"</item>
<item msgid="45075631231212732">"Kasuta alati HDCP-kontrollimist"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="5618929009984956469">"16 bitti diskreedi kohta"</item>
+ <item msgid="3412640499234627248">"24 bitti diskreedi kohta"</item>
+ <item msgid="121583001492929387">"32 bitti diskreedi kohta"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="4726688794884191540">"16 bitti diskreedi kohta"</item>
+ <item msgid="305344756485516870">"24 bitti diskreedi kohta"</item>
+ <item msgid="244568657919675099">"32 bitti diskreedi kohta"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Helikvaliteedi jaoks optimeeritud (990/909 kbit/s)"</item>
+ <item msgid="2921767058740704969">"Tasakaalustatud heli- ja ühenduskvaliteet (660/606 kbit/s)"</item>
+ <item msgid="8860982705384396512">"Ühenduskvaliteedi jaoks optimeeritud (330/303 kbit/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Helikvaliteedi jaoks optimeeritud"</item>
+ <item msgid="4327143584633311908">"Tasakaalustatud heli- ja ühenduskvaliteet"</item>
+ <item msgid="4681409244565426925">"Ühenduskvaliteedi jaoks optimeeritud"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Väljas"</item>
<item msgid="1593289376502312923">"64 000"</item>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index c51e2eb0a942..507bd204fff8 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilne andmeside on alati aktiivne"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Keela absoluutne helitugevus"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetoothi heli kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Valige Bluetoothi helikodek"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetoothi heli diskreetimissagedus"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Valige Bluetoothi helikodek:\ndiskreetimissagedus"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetoothi heli bitte diskreedi kohta"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Valige Bluetoothi helikodek:\nbitte diskreetimise kohta"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetoothi heli kanalirežiim"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Valige Bluetoothi helikodek:\nkanalirežiim"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetoothi LDAC-helikodek: taasesituskvaliteet"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Valige Bluetoothi LDAC-helikodek:\ntaasesituskvaliteet"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Voogesitus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kui see on lubatud, siis püüab WiFi nõrga WiFi-signaali korral agressiivsemalt anda andmeside ühenduse üle mobiilsele andmesidele"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Sisestage parool, et demorežiimis tehaseseadetele lähtestada"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Järgmine"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Parool on kohustuslik"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 807d562a5d66..e4bcf4824432 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Erabili HDCP egiaztapena DRM edukirako soilik"</item>
<item msgid="45075631231212732">"Erabili beti HDCP egiaztapena"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="5618929009984956469">"16 bit lagin bakoitzeko"</item>
+ <item msgid="3412640499234627248">"24 bit lagin bakoitzeko"</item>
+ <item msgid="121583001492929387">"32 bit lagin bakoitzeko"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="4726688794884191540">"16 bit lagin bakoitzeko"</item>
+ <item msgid="305344756485516870">"24 bit lagin bakoitzeko"</item>
+ <item msgid="244568657919675099">"32 bit lagin bakoitzeko"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="4106832974775067314">"Monoa"</item>
+ <item msgid="5571632958424639155">"Estereoa"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="8900559293912978337">"Monoa"</item>
+ <item msgid="8883739882299884241">"Estereoa"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Audioaren kalitatea areagotzeko optimizatua (990 Kb/s / 909 Kb/s)"</item>
+ <item msgid="2921767058740704969">"Audioaren eta konexioaren kalitate orekatua (660 Kb/s / 606 Kb/s)"</item>
+ <item msgid="8860982705384396512">"Konexioaren kalitatea areagotzeko optimizatua (330 Kb/s / 303 Kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Audioaren kalitatea areagotzeko optimizatua"</item>
+ <item msgid="4327143584633311908">"Orekatu audioaren eta konexioaren kalitateak"</item>
+ <item msgid="4681409244565426925">"Konexioaren kalitatea areagotzeko optimizatua"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desaktibatuta"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 98177d2fa53d..d8b2496fffaf 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mugikorreko datuak beti aktibo"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desgaitu bolumen absolutua"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth bidezko audioaren kodeka"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Hautatu Bluetooth audioaren kodeka"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth bidezko audioaren lagin-abiadura"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Hautatu Bluetooth audioaren LDAC kodeka:\nlaginaren abiadura"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth bidezko audioaren lagin bakoitzeko bit kopurua"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Hautatu Bluetooth audioaren kodeka:\nlagin bakoitzeko bitak"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth bidezko audioaren kanalaren modua"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Hautatu Bluetooth audioaren kodeka:\nkanal modua"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audioaren LDAC kodeka: erreprodukzioaren kalitatea"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Hautatu Bluetooth audioaren LDAC kodeka:\nerreprodukzioaren kalitatea"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Igortzean: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago Wi-Fi sareetan saioa hasterakoan. Erakutsi sarearen identifikatzailea eta seinalearen indarra Wi‑Fi sareen hautagailuan."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aukera hori gaituz gero, gailua errazago aldatuko da datu mugikorren konexiora Wi-Fi seinalea ahultzen dela nabaritutakoan"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Idatzi pasahitza jatorrizko ezarpenak demo moduan berrezartzeko"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Hurrengoa"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Pasahitza behar da"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 293639c184cf..3c0867103996 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"‏استفاده از بررسی HDCP فقط برای محتوای DRM"</item>
<item msgid="45075631231212732">"‏همیشه از بررسی HDCP استفاده شود"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="8895532488906185219">"۴۴٫۱ کیلوهرتز"</item>
+ <item msgid="2909915718994807056">"۴۸٫۰ کیلوهرتز"</item>
+ <item msgid="3347287377354164611">"۸۸٫۲ کیلوهرتز"</item>
+ <item msgid="1234212100239985373">"۹۶٫۰ کیلوهرتز"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="4482862757811638365">"۴۴٫۱ کیلوهرتز"</item>
+ <item msgid="354495328188724404">"۴۸٫۰ کیلوهرتز"</item>
+ <item msgid="7329816882213695083">"۸۸٫۲ کیلوهرتز"</item>
+ <item msgid="6967397666254430476">"۹۶٫۰ کیلوهرتز"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="5618929009984956469">"۱۶ بیت در هر نمونه"</item>
+ <item msgid="3412640499234627248">"۲۴ بیت در هر نمونه"</item>
+ <item msgid="121583001492929387">"۳۲ بیت در هر نمونه"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="4726688794884191540">"۱۶ بیت در هر نمونه"</item>
+ <item msgid="305344756485516870">"۲۴ بیت در هر نمونه"</item>
+ <item msgid="244568657919675099">"۳۲ بیت در هر نمونه"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="4106832974775067314">"مونو"</item>
+ <item msgid="5571632958424639155">"استریو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="8900559293912978337">"مونو"</item>
+ <item msgid="8883739882299884241">"استریو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"بهینه‌شده برای کیفیت صوت (۹۹۰ کیلوبیت در ثانیه/۹۰۹ کیلوبیت در ثانیه)"</item>
+ <item msgid="2921767058740704969">"کیفیت متعادل صوت و اتصال (۶۶۰ کیلوبیت در ثانیه/۶۰۶ کیلوبیت در ثانیه)"</item>
+ <item msgid="8860982705384396512">"بهینه‌شده برای کیفیت اتصال (۳۳۰ کیلوبیت در ثانیه/۳۰۳ کیلوبیت در ثانیه)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"بهینه‌شده برای کیفیت صوت"</item>
+ <item msgid="4327143584633311908">"کیفیت متعادل صوت و اتصال"</item>
+ <item msgid="4681409244565426925">"بهینه‌شده برای کیفیت اتصال"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"خاموش"</item>
<item msgid="1593289376502312923">"۶۴ هزار"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 9f0b63991c61..e529ac7ad447 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"داده سلولی همیشه فعال"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"غیرفعال کردن میزان صدای مطلق"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"کدک بلوتوث صوتی"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"انتخاب کدک صوتی بلوتوث"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"سرعت نمونه بلوتوث صوتی"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"انتخاب کدک صوتی بلوتوث:\nنرخ نمونه"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"بیت‌های بلوتوث صوتی در هر نمونه"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"انتخاب کدک صوتی بلوتوث:\nبیت در نمونه"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"حالت کانال بلوتوث‌ صوتی"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"انتخاب کدک صوتی بلوتوث:\nحالت کانال"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"‏کدک LDAC صوتی بلوتوث: کیفیت پخش"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"‏انتخاب کدک LDAC صوتی بلوتوث:\nکیفیت پخش"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"پخش جریانی: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینه‌ها برای گواهینامه نمایش بی‌سیم"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏افزایش سطح گزارش‌گیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخاب‌کننده Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏وقتی فعال است، در شرایط پایین بودن سیگنال، Wi‑Fi برای واگذار کردن اتصال داده به شبکه سلولی فعال‌تر خواهد بود."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"برای انجام بازنشانی کارخانه‌ای در حالت نمایشی، گذرواژه را وارد کنید"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"بعدی"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"وارد کردن گذرواژه الزامی است"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 2808bf24f4e0..00d967e9ee91 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Käytä HDCP-tarkistusta vain DRM-suojatulle sisällölle"</item>
<item msgid="45075631231212732">"Käytä aina HDCP-tarkistusta"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="5618929009984956469">"16 bittiä/näyte"</item>
+ <item msgid="3412640499234627248">"24 bittiä/näyte"</item>
+ <item msgid="121583001492929387">"32 bittiä/näyte"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="4726688794884191540">"16 bittiä/näyte"</item>
+ <item msgid="305344756485516870">"24 bittiä/näyte"</item>
+ <item msgid="244568657919675099">"32 bittiä/näyte"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimoi äänenlaatu (990 kb/s / 909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Tasapainoinen yhteyden ja äänenlaadun optimointi (660 kb/s / 606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimoi yhteyden laatu (330 kb/s / 303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimoi äänenlaatu"</item>
+ <item msgid="4327143584633311908">"Tasapainoinen yhteyden ja äänenlaadun optimointi"</item>
+ <item msgid="4681409244565426925">"Optimoi yhteyden laatu"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Ei käytössä"</item>
<item msgid="1593289376502312923">"64 kt"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 7f78001ba067..0c28710d0835 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilidata on aina käytössä"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-äänen koodekki"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Valitse Bluetooth-äänen koodekki"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-ääninäytteen siirtonopeus"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Valitse Bluetooth-äänen koodekki:\nSiirtonopeus"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-äänen bittiä/näyte-arvo"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Valitse Bluetooth-äänen koodekki:\nBittiä/näyte"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth-äänen kanavatila"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Valitse Bluetooth-äänen koodekki:\nKanavatila"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-äänen LDAC-koodekki: Toiston laatu"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Valitse Bluetooth-äänen LDAC-koodekki:\nToiston laatu"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Striimaus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kun asetus on käytössä, Wi-Fi siirtää datayhteyden aggressiivisemmin matkapuhelinverkolle, jos Wi-Fi-signaali on heikko."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Palauta tehdasasetukset antamalla salasana"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Seuraava"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Salasana vaaditaan"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 7c403bf48a50..19f3c83aed69 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utiliser la vérification HDCP uniquement pour le contenu GDN"</item>
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="5618929009984956469">"16 bits par échantillon"</item>
+ <item msgid="3412640499234627248">"24 bits par échantillon"</item>
+ <item msgid="121583001492929387">"32 bits par échantillon"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="4726688794884191540">"16 bits par échantillon"</item>
+ <item msgid="305344756485516870">"24 bits par échantillon"</item>
+ <item msgid="244568657919675099">"32 bits par échantillon"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stéréo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Utiliser sélect. du système (par défaut)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stéréo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimisé pour la qualité audio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Qualité audio et de la connexion équilibrée (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimisé pour la qualité de connexion (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimisé pour la qualité audio"</item>
+ <item msgid="4327143584633311908">"Qualité audio et de la connexion équilibrée"</item>
+ <item msgid="4681409244565426925">"Optimisé pour la qualité de connexion"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Désactivé"</item>
<item msgid="1593289376502312923">"64 ko"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cd0ab2514832..ca8f4623ac37 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Données cellulaires toujours actives"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Sélectionner le codec audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taux d\'échantillonnage pour l\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Sélectionner le codec audio Bluetooth :\nTaux d\'échantillonnage"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits par échantillon pour l\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Sélectionner le codec audio Bluetooth :\nBits par échantillon"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de canal pour l\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Sélectionner le codec audio Bluetooth :\nMode de chaîne"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec audio Bluetooth LDAC : qualité de lecture"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Sélectionner le codec audio Bluetooth LDAC :\nQualité de lecture"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Diffusion : <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification d\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données cellulaires est forcé lorsque le signal Wi-Fi est faible"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Entrez m. passe pour réinit. en mode démo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Suivant"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Mot de passe obligatoire"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index c63275f1c2c6..e020328002d8 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utiliser la vérification HDCP uniquement pour le contenu DRM"</item>
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="5618929009984956469">"16 bits par échantillon"</item>
+ <item msgid="3412640499234627248">"24 bits par échantillon"</item>
+ <item msgid="121583001492929387">"32 bits par échantillon"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="4726688794884191540">"16 bits par échantillon"</item>
+ <item msgid="305344756485516870">"24 bits par échantillon"</item>
+ <item msgid="244568657919675099">"32 bits par échantillon"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stéréo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stéréo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimisée pour la qualité audio (990/909 kbit/s)"</item>
+ <item msgid="2921767058740704969">"Qualité audio et de la connexion équilibrée (660/606 kbit/s)"</item>
+ <item msgid="8860982705384396512">"Optimisée pour la qualité de la connexion (330/303 kbit/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimisée pour la qualité audio"</item>
+ <item msgid="4327143584633311908">"Qualité audio et de la connexion équilibrée"</item>
+ <item msgid="4681409244565426925">"Optimisée pour la qualité de la connexion"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Désactivé"</item>
<item msgid="1593289376502312923">"64 Ko"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 8587e280bc38..05c9e93ac115 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Données mobiles toujours actives"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Sélectionner le codec audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taux d\'échantillonnage audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Sélectionner le codec audio Bluetooth :\nTaux d\'échantillonnage"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Nombre de bits par échantillon pour l\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Sélectionner le codec audio Bluetooth :\nBits par échantillon"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de chaîne de l\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Sélectionner le codec audio Bluetooth :\nMode de chaîne"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec audio Bluetooth LDAC : qualité de lecture"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Sélectionner le codec audio Bluetooth LDAC :\nQualité de lecture"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Diffusion : <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données mobiles est forcé en cas de signal Wi-Fi faible."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Saisir mot de passe pour rétablir conf. d\'usine en mode démo."</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Suivant"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Veuillez saisir le mot de passe"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index 2a89199f4ba9..c90927193ee9 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utiliza a comprobación HDCP só para contido DRM"</item>
<item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usar selección sistema (predeterminado)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usa selección sistema (predeterminado)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usar selección sistema (predeterminado)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usa selección sistema (predeterminado)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usar selección sistema (predeterminado)"</item>
+ <item msgid="5618929009984956469">"16 bits/mostra"</item>
+ <item msgid="3412640499234627248">"24 bits/mostra"</item>
+ <item msgid="121583001492929387">"32 bits/mostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usa selección sistema (predeterminado)"</item>
+ <item msgid="4726688794884191540">"16 bits/mostra"</item>
+ <item msgid="305344756485516870">"24 bits/mostra"</item>
+ <item msgid="244568657919675099">"32 bits/mostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usar selección sistema (predeterminado)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usa selección sistema (predeterminado)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizado para a calidade do audio (990 kb/s ou 909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Calidade equilibrada do audio e da conexión (660 kb/s ou 606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimizado para a calidade da conexión (330 kb/s ou 303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizado para a calidade do audio"</item>
+ <item msgid="4327143584633311908">"Calidade equilibrada do audio e da conexión"</item>
+ <item msgid="4681409244565426925">"Optimizado para a calidade da conexión"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desactivado"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 682057546b9c..5de9407b7d15 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móbiles sempre activados"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactivar volume absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Seleccionar códec de audio por Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de mostraxe de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Seleccionar códec de audio por Bluetooth:\nfrecuencia de mostraxe"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por mostra de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Seleccionar códec de audio por Bluetooth:\nbits por mostra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canle de audio por Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Seleccionar códec de audio por Bluetooth:\nmodo de canle"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Códec LDAC de audio por Bluetooth: calidade de reprodución"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleccionar códec LDAC de audio por Bluetooth:\ncalidade de reprodución"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Reprodución en tempo real: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nivel de rexistro da wifi, mostrar por SSID RSSI no selector de wifi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Cando está activada esta función, a wifi será máis agresiva ao entregar a conexión de datos ao móbil, cando o sinal wifi é feble"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Insire contrasinal para restablec. en demostración"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Seguinte"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"O contrasinal é obrigatorio"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index d41cfbcd2312..6eb4321653b6 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ફક્ત DRM સામગ્રી માટે HDCP તપાસનો ઉપયોગ કરો"</item>
<item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="5618929009984956469">"16 બિટ/નમૂનો"</item>
+ <item msgid="3412640499234627248">"24 બિટ/નમૂનો"</item>
+ <item msgid="121583001492929387">"32 બિટ/નમૂનો"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="4726688794884191540">"16 બિટ/નમૂનો"</item>
+ <item msgid="305344756485516870">"24 બિટ/નમૂનો"</item>
+ <item msgid="244568657919675099">"32 બિટ/નમૂનો"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="4106832974775067314">"મૉનો"</item>
+ <item msgid="5571632958424639155">"સ્ટીરિઓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+ <item msgid="8900559293912978337">"મૉનો"</item>
+ <item msgid="8883739882299884241">"સ્ટીરિઓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ઑડિઓની ગુણવત્તા (990 kbps/909 kbps) માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+ <item msgid="2921767058740704969">"સંતુલિત ઑડિઓ અને કનેક્શનની ગુણવત્તા (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"કનેક્શનની ગુણવત્તા (330 kbps/303 kbps) માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ઑડિઓની ગુણવત્તા માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+ <item msgid="4327143584633311908">"સંતુલિત ઑડિઓ અને કનેક્શનની ગુણવત્તા"</item>
+ <item msgid="4681409244565426925">"કનેક્શનની ગુણવત્તા માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"બંધ"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 8e68ab0b06da..2697419466e6 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"સેલ્યુલર ડેટા હંમેશા સક્રિય"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth ઑડિઓ કોડેક"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth ઑડિઓ LDAC કોડેક પસંદ કરો"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth ઑડિઓ નમૂના દર"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth ઑડિઓ LDAC કોડેક પસંદ કરો:\nનમૂના દર"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"નમૂના દીઠ Bluetooth ઑડિઓ બિટ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth ઑડિઓ કોડેક પસંદ કરો:\nનમૂના દીઠ બિટ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth ઑડિઓ ચેનલ મોડ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth ઑડિઓ કોડેક પસંદ કરો:\nચૅનલ મોડ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth ઑડિઓ LDAC કોડેક: પ્લેબૅક ગુણવત્તા"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth ઑડિઓ LDAC કોડેક પસંદ કરો:\nપ્લેબૅક ગુણવત્તા"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"સ્ટ્રીમિંગ: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi લોગિંગ સ્તર વધારો, Wi‑Fi પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"જ્યારે સક્ષમ હોય, ત્યારે Wi‑Fi સિગ્નલ ઓછા હોવા પર, સેલ્યુલર પર ડેટા કનેક્શન મોકલવામાં વધુ આક્રમક હશે"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ડેમો મોડમાં ફેક્ટરી રીસેટ પાસવર્ડ દાખલ કરો"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"આગલું"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"પાસવર્ડ આવશ્યક છે"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 489e8e712e42..d0c12c8c99e2 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP जांच का उपयोग केवल DRM सामग्री के लिए करें"</item>
<item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="5618929009984956469">"16 बिट/नमूना"</item>
+ <item msgid="3412640499234627248">"24 बिट/नमूना"</item>
+ <item msgid="121583001492929387">"32 बिट/नमूना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="4726688794884191540">"16 बिट/नमूना"</item>
+ <item msgid="305344756485516870">"24 बिट/नमूना"</item>
+ <item msgid="244568657919675099">"32 बिट/नमूना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="4106832974775067314">"मोनो"</item>
+ <item msgid="5571632958424639155">"स्टीरियो"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+ <item msgid="8900559293912978337">"मोनो"</item>
+ <item msgid="8883739882299884241">"स्टीरियो"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ऑडियो की गुणवत्ता के लिए अनुकूलित किया गया (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"संतुलित ऑडियो और कनेक्शन गुणवत्ता (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"कनेक्शन की गुणवत्ता के लिए अनुकूलित किया गया (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ऑडियो की गुणवत्ता के लिए अनुकूलित किया गया"</item>
+ <item msgid="4327143584633311908">"संतुलित ऑडियो और कनेक्शन गुणवत्ता"</item>
+ <item msgid="4681409244565426925">"कनेक्शन की गुणवत्ता के लिए अनुकूलित किया गया"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"बंद"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index fd01c6b48bf7..f0cb2e3110f1 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा हमेशा सक्रिय"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"पूर्ण वॉल्यूम अक्षम करें"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडियो कोडेक"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ब्लूटूथ ऑडियो कोडेक चुनें"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लूटूथ ऑडियो नमूना दर"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ब्लूटूथ ऑडियो कोडेक चुनें:\nनमूना दर"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ब्लूटूथ ऑडियो बिट प्रति नमूना"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ब्लूटूथ ऑडियो कोडेक चुनें:\nबिट प्रति नमूना"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लूटूथ ऑडियो चैनल मोड"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ब्लूटूथ ऑडियो कोडेक चुनें:\nचैनल मोड"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ब्लूटूथ ऑडियो LDAC कोडेक: प्लेबैक क्वालिटी"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ब्लूटूथ ऑडियो LDAC कोडेक चुनें:\nप्लेबैक क्वालिटी"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"स्ट्रीम हो रहा है: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस दिखाई देने के लिए प्रमाणन विकल्प दिखाएं"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाई-फ़ाई प्रवेश स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"इसके सक्षम होने पर, जब वाई-फ़ाई संकेत कमज़ोर हों तो वाई-फ़ाई, डेटा कनेक्शन को सेल्यूलर पर अधिक बलपूर्वक भेजेगा"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोड में फ़ैक्टरी रीसेट के लिए पासवर्ड डालें"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 8415bee18fcc..9224adfc1556 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Upotrebljavaj HDCP provjeru samo za DRM sadržaj"</item>
<item msgid="45075631231212732">"Uvijek upotrebljavaj HDCP provjeru"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="5618929009984956469">"16 bitova po uzorku"</item>
+ <item msgid="3412640499234627248">"24 bita po uzorku"</item>
+ <item msgid="121583001492929387">"32 bita po uzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="4726688794884191540">"16 bitova po uzorku"</item>
+ <item msgid="305344756485516870">"24 bita po uzorku"</item>
+ <item msgid="244568657919675099">"32 bita po uzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizirano za kvalitetu audioreprodukcije (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Uravnotežena kvaliteta audioreprodukcije i veze (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizirano za kvalitetu veze (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizirano za kvalitetu audioreprodukcije"</item>
+ <item msgid="4327143584633311908">"Uravnotežena kvaliteta audioreprodukcije i veze"</item>
+ <item msgid="4681409244565426925">"Optimizirano za kvalitetu veze"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Isključeno"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 21fdce52ad08..8313ca1216dc 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu glasnoću"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek za Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Odaberi kodek za Bluetooth Audio"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorka za Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Odaberi kodek za Bluetooth Audio:\nbrzina uzorkovanja"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bitovi po uzorku za Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Odaberi kodek za Bluetooth Audio:\nbitovi po uzorku"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način kanala za Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Odaberi kodek za Bluetooth Audio:\nnačin kanala"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek za Bluetooth Audio LDAC: kvaliteta reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Odaberi kodek za Bluetooth Audio LDAC:\nkvaliteta reprodukcije"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strujanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ako je omogućeno, Wi-Fi će aktivno prebacivati podatkovnu vezu mobilnoj mreži kada je Wi-Fi signal slab."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite zaporku za resetiranje u demo načinu"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalje"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Potrebna je zaporka"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 9f314ac4f8fb..db5aae872f83 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Csak DRM-tartalomhoz használjon HDCP ellenőrzést"</item>
<item msgid="45075631231212732">"Mindig használjon HDCP ellenőrzést"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="5618929009984956469">"16 bit/minta"</item>
+ <item msgid="3412640499234627248">"24 bit/minta"</item>
+ <item msgid="121583001492929387">"32 bit/minta"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="4726688794884191540">"16 bit/minta"</item>
+ <item msgid="305344756485516870">"24 bit/minta"</item>
+ <item msgid="244568657919675099">"32 bit/minta"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="4106832974775067314">"Monó"</item>
+ <item msgid="5571632958424639155">"Sztereó"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Rendszerérték (alapértelmezett)"</item>
+ <item msgid="8900559293912978337">"Monó"</item>
+ <item msgid="8883739882299884241">"Sztereó"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimális hangminőség (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Kiegyensúlyozott hang- és kapcsolatminőség (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimális kapcsolatminőség (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimális hangminőség"</item>
+ <item msgid="4327143584633311908">"Kiegyensúlyozott hang- és kapcsolatminőség"</item>
+ <item msgid="4681409244565426925">"Optimális kapcsolatminőség"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Ki"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 63c38d020abd..15417d657419 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"A mobilhálózati adatforgalom mindig aktív"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Abszolút hangerő funkció letiltása"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hang – Kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth hangkodek kiválasztása"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth hang – mintavételezési gyakoriság"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth hangkodek kiválasztása:\nmintavételi gyakoriság"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth hang – bit/minta"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth hangkodek kiválasztása:\nbit/minta"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth hang – Csatornamód"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth hangkodek kiválasztása:\ncsatornamód"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC hangkodek: lejátszási minőség"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth LDAC hangkodek kiválasztása:\nlejátszási minőség"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamelés: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ha engedélyezi, a Wi-Fi agresszívebben fogja átadni az adatkapcsolatot a mobilhálózatnak gyenge Wi-Fi-jel esetén"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Írja be a jelszót a visszaállításhoz"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Következő"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Jelszó szükséges"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 057399e52e7b..8925f32ea728 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Օգտագործել HDCP-ը` միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
<item msgid="45075631231212732">"Միշտ օգտագործել HDCP ստուգումը"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="8895532488906185219">"44,1 կՀց"</item>
+ <item msgid="2909915718994807056">"48,0 կՀց"</item>
+ <item msgid="3347287377354164611">"88,2 կՀց"</item>
+ <item msgid="1234212100239985373">"96,0 կՀց"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="4482862757811638365">"44,1 կՀց"</item>
+ <item msgid="354495328188724404">"48,0 կՀց"</item>
+ <item msgid="7329816882213695083">"88,2 կՀց"</item>
+ <item msgid="6967397666254430476">"96,0 կՀց"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="5618929009984956469">"16 բիթ/նմուշ"</item>
+ <item msgid="3412640499234627248">"24 բիթ/նմուշ"</item>
+ <item msgid="121583001492929387">"32 բիթ/նմուշ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="4726688794884191540">"16 բիթ/նմուշ"</item>
+ <item msgid="305344756485516870">"24 բիթ/նմուշ"</item>
+ <item msgid="244568657919675099">"32 բիթ/նմուշ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="4106832974775067314">"Մոնո"</item>
+ <item msgid="5571632958424639155">"Ստերեո"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="8900559293912978337">"Մոնո"</item>
+ <item msgid="8883739882299884241">"Ստերեո"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Օպտիմալացված ձայնի որակի համար (990 կբ/վ / 909 կբ/վ)"</item>
+ <item msgid="2921767058740704969">"Ձայնի և կապի հավասարակշռված որակ (660 կբ/վ / 606 կբ/վ)"</item>
+ <item msgid="8860982705384396512">"Օպտիմալացված կապի որակի համար (330 կբ/վ / 303 կբ/վ)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Օպտիմալացված ձայնի որակի համար"</item>
+ <item msgid="4327143584633311908">"Ձայնի և կապի հավասարակշռված որակ"</item>
+ <item msgid="4681409244565426925">"Օպտիմալացված կապի որակի համար"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Անջատված է"</item>
<item msgid="1593289376502312923">"64ԿԲ"</item>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b4efac17c48e..c75220ff1e08 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Բջջային տվյալները՝ միշտ ակտիվացրած"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth աուդիո կոդեկ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Ընտրեք Bluetooth աուդիո կոդեկը"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth աուդիոյի Ընդհատավորման հաճախականությունը"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Ընտրեք Bluetooth աուդիո կոդեկը՝\nընդհատավորման հաճախականություն"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth աուդիո, բիթ / նմուշ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Ընտրեք Bluetooth աուդիո կոդեկը՝\nբիթ/նմուշ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth աուդիո կապուղու ռեժիմը"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Ընտրեք Bluetooth աուդիո կոդեկը՝\nկապուղու ռեժիմ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth աուդիո LDAC կոդեկ՝ նվագարկման որակ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Ընտրեք Bluetooth աուդիո LDAC կոդեկը՝\nնվագարկման որակ"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Հեռարձակում՝ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի հավաստագրման ընտրանքները"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Եթե այս գործառույթը միացված է, Wi‑Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից անցումը բջջային ինտերնետին ավելի կտրուկ կլինի"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Մուտքագրեք գաղտնաբառը՝ ցուցադրական ռեժիմում գործարանային վերակայում կատարելու համար"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Հաջորդը"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Պահանջվում է գաղտնաբառ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 1ccf99369d30..fae09d0a693a 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Gunakan pemeriksaan HDCP untuk konten DRM saja"</item>
<item msgid="45075631231212732">"Selalu gunakan pemeriksaan HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="5618929009984956469">"16 bit/sampel"</item>
+ <item msgid="3412640499234627248">"24 bit/sampel"</item>
+ <item msgid="121583001492929387">"32 bit/sampel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="4726688794884191540">"16 bit/sampel"</item>
+ <item msgid="305344756485516870">"24 bit/sampel"</item>
+ <item msgid="244568657919675099">"32 bit/sampel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Dioptimalkan untuk Kualitas Audio (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Kualitas Audio dan Sambungan Seimbang (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Dioptimalkan untuk Kualitas Sambungan for Connection Quality (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Dioptimalkan untuk Kualitas Audio"</item>
+ <item msgid="4327143584633311908">"Kualitas Audio dan Sambungan Seimbang"</item>
+ <item msgid="4681409244565426925">"Dioptimalkan untuk Kualitas Sambungan"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Nonaktif"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index a2f13ae683df..186b79c0f2de 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -140,10 +140,10 @@
<string name="choose_profile" msgid="8229363046053568878">"Pilih Profil"</string>
<string name="category_personal" msgid="1299663247844969448">"Pribadi"</string>
<string name="category_work" msgid="8699184680584175622">"Kantor"</string>
- <string name="development_settings_title" msgid="215179176067683667">"Opsi pengembang"</string>
- <string name="development_settings_enable" msgid="542530994778109538">"Aktifkan opsi pengembang"</string>
+ <string name="development_settings_title" msgid="215179176067683667">"Opsi developer"</string>
+ <string name="development_settings_enable" msgid="542530994778109538">"Aktifkan opsi developer"</string>
<string name="development_settings_summary" msgid="1815795401632854041">"Menyetel opsi untuk pengembangan apl"</string>
- <string name="development_settings_not_available" msgid="4308569041701535607">"Opsi pengembang tidak tersedia untuk pengguna ini"</string>
+ <string name="development_settings_not_available" msgid="4308569041701535607">"Opsi developer tidak tersedia untuk pengguna ini"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"Setelan VPN tidak tersedia untuk pengguna ini"</string>
<string name="tethering_settings_not_available" msgid="6765770438438291012">"Setelan Penambatan tidak tersedia untuk pengguna ini"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"Setelan Nama Titik Akses tidak tersedia untuk pengguna ini"</string>
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data seluler selalu aktif"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Nonaktifkan volume absolut"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Pilih Codec Audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frekuensi Sampel Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Pilih Codec Audio Bluetooth:\nFrekuensi Sampel"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit Per Sampel Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Pilih Codec Audio Bluetooth:\nBit Per Sampel"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode Channel Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Pilih Codec Audio Bluetooth:\nMode Channel"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC Audio Bluetooth: Kualitas Pemutaran"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pilih Codec LDAC Audio Bluetooth:\nKualitas Pemutaran"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jika diaktifkan, Wi-Fi akan menjadi lebih agresif dalam mengalihkan sambungan data ke Seluler saat sinyal Wi-Fi lemah"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Masukkan sandi untuk mengembalikan ke setelan pabrik dalam mode demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Berikutnya"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Perlu sandi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index 94ce95780df1..7062632dfded 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Nota HDCP-athugun aðeins fyrir höfundarréttarvarið efni"</item>
<item msgid="45075631231212732">"Nota alltaf HDCP-eftirlit"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="5618929009984956469">"16 bitar/úrtak"</item>
+ <item msgid="3412640499234627248">"24 bitar/úrtak"</item>
+ <item msgid="121583001492929387">"32 bitar/úrtak"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="4726688794884191540">"16 bitar/úrtak"</item>
+ <item msgid="305344756485516870">"24 bitar/úrtak"</item>
+ <item msgid="244568657919675099">"32 bitar/úrtak"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="4106832974775067314">"Einóma"</item>
+ <item msgid="5571632958424639155">"Víðóma"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Nota val kerfisins (sjálfgefið)"</item>
+ <item msgid="8900559293912978337">"Einóma"</item>
+ <item msgid="8883739882299884241">"Víðóma"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Fínstillt fyrir hljóðgæði (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Jafnvægi á milli gæða hljóðs og tengingar (660 kbps / 606 kbps)"</item>
+ <item msgid="8860982705384396512">"Fínstillt fyrir gæði tengingar (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Fínstillt fyrir hljóðgæði"</item>
+ <item msgid="4327143584633311908">"Jafnvægi á milli gæða hljóðs og tengingar"</item>
+ <item msgid="4681409244565426925">"Fínstillt fyrir gæði tengingar"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Slökkt"</item>
<item msgid="1593289376502312923">"64 k"</item>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index f50f97e29c54..844a3b4ea83d 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Alltaf kveikt á farsímagögnum"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slökkva á samstillingu hljóðstyrks"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hljóðkóðari"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Velja Bluetooth-hljóðkóðara"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth hljóðtökutíðni"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Velja hljóðkóðara Bluetooth:\ntökutíðni"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth hljóðbitar í úrtaki"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Velja hljóðkóðara Bluetooth:\nbitar í úrtaki"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hljóðrásarstilling Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Velja hljóðkóðara Bluetooth:\nstilling rásar"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC-hljóðkóðari: gæði spilunar"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Velja Bluetooth LDAC-hljóðkóðara:\ngæði spilunar"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streymi: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Þegar þetta er virkt mun Wi-Fi ganga harðar fram í að færa gagnatenginguna yfir til símkerfisins þegar Wi-Fi merkið er lélegt"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Sláðu inn aðgangsorð til að framkvæma núllstillingu í sýnisútgáfu"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Áfram"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Aðgangsorðs krafist"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index d5ca891cf313..85904b586798 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Usa la verifica HDCP solo per contenuti DRM"</item>
<item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="5618929009984956469">"16 bit/campione"</item>
+ <item msgid="3412640499234627248">"24 bit/campione"</item>
+ <item msgid="121583001492929387">"32 bit/campione"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="4726688794884191540">"16 bit/campione"</item>
+ <item msgid="305344756485516870">"24 bit/campione"</item>
+ <item msgid="244568657919675099">"32 bit/campione"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usa selezione di sistema (predefinita)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Ottimizzato per qualità audio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Audio bilanciato e qualità di connessione (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Ottimizzato per qualità di connessione (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Ottimizzato per qualità audio"</item>
+ <item msgid="4327143584633311908">"Audio bilanciato e qualità di connessione"</item>
+ <item msgid="4681409244565426925">"Ottimizzato per qualità di connessione"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Off"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 14f41fa31e46..7e3fd486c0b0 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dati cellulare sempre attivi"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disattiva volume assoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Seleziona il codec audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frequenza di campionamento audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Seleziona il codec audio Bluetooth:\nFrequenza di campionamento"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit per campione dell\'audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Seleziona il codec audio Bluetooth:\nBit per campione"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modalità canale audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Seleziona il codec audio Bluetooth:\nModalità canale"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC audio Bluetooth: qualità di riproduzione"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleziona il codec LDAC audio Bluetooth:\nQualità di riproduzione"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta il livello di registrazione Wi-Fi, mostrando il SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando questa impostazione è attivata, il Wi-Fi sarà più aggressivo nel passare la connessione dati al cellulare, quando il segnale Wi-Fi è basso"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Inserisci la password per eseguire il ripristino dei dati di fabbrica in modalità demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Avanti"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Password obbligatoria"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 94af5f1b9798..2cf333ffec19 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"‏השתמש בבדיקת HDCP עבור תוכן DRM בלבד"</item>
<item msgid="45075631231212732">"‏תמיד השתמש בבדיקת HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"השתמש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="8895532488906185219">"44.1 קילו-הרץ"</item>
+ <item msgid="2909915718994807056">"48.0 קילו-הרץ"</item>
+ <item msgid="3347287377354164611">"88.2 קילו-הרץ"</item>
+ <item msgid="1234212100239985373">"96.0 קילו-הרץ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"השתמש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="4482862757811638365">"44.1 קילו-הרץ"</item>
+ <item msgid="354495328188724404">"48.0 קילו-הרץ"</item>
+ <item msgid="7329816882213695083">"88.2 קילו-הרץ"</item>
+ <item msgid="6967397666254430476">"96.0 קילו-הרץ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="5618929009984956469">"16 סיביות לדגימה"</item>
+ <item msgid="3412640499234627248">"24 סיביות לדגימה"</item>
+ <item msgid="121583001492929387">"32 סיביות לדגימה"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"השתמש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="4726688794884191540">"16 סיביות לדגימה"</item>
+ <item msgid="305344756485516870">"24 סיביות לדגימה"</item>
+ <item msgid="244568657919675099">"32 סיביות לדגימה"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="4106832974775067314">"מונו"</item>
+ <item msgid="5571632958424639155">"סטריאו"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"השתמש בבחירת המערכת (ברירת המחדל)"</item>
+ <item msgid="8900559293912978337">"מונו"</item>
+ <item msgid="8883739882299884241">"סטריאו"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"‏אופטימיזציה להשגת איכות אודיו מרבית (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"‏איזון בין איכות החיבור לאיכות אודיו (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"‏אופטימיזציה להשגת איכות חיבור מרבית (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"אופטימיזציה להשגת איכות אודיו מרבית"</item>
+ <item msgid="4327143584633311908">"אזן בין איכות החיבור לאיכות אודיו"</item>
+ <item msgid="4681409244565426925">"אופטימיזציה להשגת איכות חיבור מרבית"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"כבוי"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 5b26091c14f7..3e1bfdb6ac4e 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"נתונים סלולריים פעילים תמיד"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"השבת עוצמת קול מוחלטת"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"‏Codec אודיו ל-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"‏בחירת ‏Codec אודיו ל-Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"‏קצב דגימה של אודיו ל-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"‏בחירת Codec אודיו ל-Bluetooth‏:\nקצב דגימה"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"‏מספר סיביות לדגימה באודיו ל-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"‏בחירת codec אודיו ל-Bluetooth:‏\nסיביות לדגימה"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"‏מצב של ערוץ אודיו ל-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"‏בחירת codec אודיו ל-Bluetooth:‏\nמצב ערוץ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"‏Codec אודיו LDAC ל-Bluetooth: איכות נגינה"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"‏בחירת Codec אודיו LDAC ל-Bluetooth:‏\nאיכות נגינה"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"סטרימינג: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"‏הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏כשתכונה זו מופעלת, Wi-Fi יתנהג בצורה אגרסיבית יותר בעת העברת חיבור הנתונים לרשת הסלולרית כשאות ה-Wi-Fi חלש."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"הזן סיסמה כדי לבצע איפוס להגדרות היצרן במצב הדגמה"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"הבא"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"דרושה סיסמה"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index c8599d25ba05..748bbab8ed68 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRMコンテンツにのみHDCPチェックを使用する"</item>
<item msgid="45075631231212732">"HDCPチェックを常に使用する"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="5618929009984956469">"16 ビット / サンプル"</item>
+ <item msgid="3412640499234627248">"24 ビット / サンプル"</item>
+ <item msgid="121583001492929387">"32 ビット / サンプル"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="4726688794884191540">"16 ビット / サンプル"</item>
+ <item msgid="305344756485516870">"24 ビット / サンプル"</item>
+ <item msgid="244568657919675099">"32 ビット / サンプル"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="4106832974775067314">"モノラル"</item>
+ <item msgid="5571632958424639155">"ステレオ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="8900559293912978337">"モノラル"</item>
+ <item msgid="8883739882299884241">"ステレオ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"音質重視で最適化(990 kbps / 909 kbps)"</item>
+ <item msgid="2921767058740704969">"音質と接続の品質のバランスを確保(660 kbps / 606 kbps)"</item>
+ <item msgid="8860982705384396512">"接続の品質重視で最適化(330 kbps / 303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"音質重視で最適化"</item>
+ <item msgid="4327143584633311908">"音質と接続の品質のバランスを確保"</item>
+ <item msgid="4681409244565426925">"接続の品質重視で最適化"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"OFF"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 72f45959333a..06602e302f96 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"モバイルデータを常にON"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"絶対音量を無効にする"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth オーディオ コーデック"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth オーディオ コーデックを選択"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth オーディオ サンプルレート"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth オーディオ コーデックを選択:\nサンプルレート"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"サンプルあたりの Bluetooth オーディオ ビット"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth オーディオ コーデックを選択:\nサンプルあたりのビット"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth オーディオ チャンネル モード"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth オーディオ コーデックを選択:\nチャンネル モード"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth オーディオ LDAC コーデック: 再生音質"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth オーディオ LDAC コーデックを選択:\n再生音質"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ストリーミング: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ワイヤレスディスプレイ認証のオプションを表示"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fiログレベルを上げて、Wi-Fi選択ツールでSSID RSSIごとに表示します"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"有効にすると、Wi-Fiの電波強度が弱い場合は強制的にモバイルデータ接続に切り替わるようになります"</string>
@@ -362,4 +355,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"デモモードで初期状態にリセットするには、パスワードを入力してください"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"次へ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"パスワード必須"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index 60779fe891ce..a630af2e095b 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP შემოწმების გამოყენება მხოლოდ DRM კონტენტის შემთხვევაში"</item>
<item msgid="45075631231212732">"ყოველთვის გამოიყენე HDCP შემოწმება"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="8895532488906185219">"44,1 კჰც"</item>
+ <item msgid="2909915718994807056">"48,0 კჰც"</item>
+ <item msgid="3347287377354164611">"88,2 კჰც"</item>
+ <item msgid="1234212100239985373">"96,0 კჰც"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="4482862757811638365">"44,1 კჰც"</item>
+ <item msgid="354495328188724404">"48,0 კჰც"</item>
+ <item msgid="7329816882213695083">"88,2 კჰც"</item>
+ <item msgid="6967397666254430476">"96,0 კჰც"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="5618929009984956469">"16 ბიტი/ნიმუში"</item>
+ <item msgid="3412640499234627248">"24 ბიტი/ნიმუში"</item>
+ <item msgid="121583001492929387">"32 ბიტი/ნიმუში"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="4726688794884191540">"16 ბიტი/ნიმუში"</item>
+ <item msgid="305344756485516870">"24 ბიტი/ნიმუში"</item>
+ <item msgid="244568657919675099">"32 ბიტი/ნიმუში"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="4106832974775067314">"მონო"</item>
+ <item msgid="5571632958424639155">"სტერეო"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+ <item msgid="8900559293912978337">"მონო"</item>
+ <item msgid="8883739882299884241">"სტერეო"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"აუდიოს ხარისხისთვის ოპტიმიზებული (990/909 კბიტი/წმ)"</item>
+ <item msgid="2921767058740704969">"აუდიოსა და კავშირის დაბალანსებული ხარისხი (660/606 კბიტი/წმ)"</item>
+ <item msgid="8860982705384396512">"კავშირის ხარისხისთვის ოპტიმიზებული (330/303 კბიტი/წმ)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"აუდიოს ხარისხისთვის ოპტიმიზებული"</item>
+ <item msgid="4327143584633311908">"აუდიოსა და კავშირის დაბალანსებული ხარისხი"</item>
+ <item msgid="4681409244565426925">"კავშირის ხარისხისთვის ოპტიმიზებული"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"გამორთული"</item>
<item msgid="1593289376502312923">"64 კბაიტი"</item>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 058562eb60fd..6838fbc93513 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ფიჭური მონაცემები ყოველთვის აქტიურია"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth აუდიოს კოდეკი"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"აირჩიეთ Bluetooth აუდიოს კოდეკი"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth აუდიოს დისკრეტიზაციის სიხშირე"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"აირჩიეთ Bluetooth აუდიოს კოდეკის\nდისკრეტიზაციის სიხშირე"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth აუდიოს ბიტების რაოდენობა ნიმუშზე"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"აირჩიეთ Bluetooth აუდიოს კოდეკის\nბიტების რაოდენობა ნიმუშზე"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth აუდიოს არხის რეჟიმი"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"აირჩიეთ Bluetooth აუდიოს კოდეკის\nარხის რეჟიმი"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth აუდიოს LDAC კოდეკის დაკვრის ხარისხი"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"აირჩიეთ Bluetooth აუდიოს LDAC კოდეკის\nდაკვრის ხარისხი"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"სტრიმინგი: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"თუ ჩართულია, Wi‑Fi სიგნალის შესუსტების შემთხვევაში Wi-Fi უფრო აქტიურად შეეცდება გადაიყვანოს ინტერნეტ-კავშირი მობილურ ინტერნეტზე"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"შეიყვანეთ პაროლი დემო-რეჟიმში ქარხნულ მდგომარეობაზე დასაბრუნებლად"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"შემდეგი"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"საჭიროა პაროლი"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index f74360691f0b..9c6e0821e81c 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP (кең жолақты сандық мазмұн қорғау) тексеруді DRM (авторлық құқықты техникалық қорғау) мазмұны үшін ғана қолданыңыз"</item>
<item msgid="45075631231212732">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="8895532488906185219">"44,1 кГц"</item>
+ <item msgid="2909915718994807056">"48,0 кГц"</item>
+ <item msgid="3347287377354164611">"88,2 кГц"</item>
+ <item msgid="1234212100239985373">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="4482862757811638365">"44,1 кГц"</item>
+ <item msgid="354495328188724404">"48,0 кГц"</item>
+ <item msgid="7329816882213695083">"88,2 кГц"</item>
+ <item msgid="6967397666254430476">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="5618929009984956469">"16 бит/үлгі"</item>
+ <item msgid="3412640499234627248">"24 бит/үлгі"</item>
+ <item msgid="121583001492929387">"32 бит/үлгі"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="4726688794884191540">"16 бит/үлгі"</item>
+ <item msgid="305344756485516870">"24 бит/үлгі"</item>
+ <item msgid="244568657919675099">"32 бит/үлгі"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Жүйені таңдау (әдепкі)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Аудиомазмұн сапасы бойынша оңтайландырылды (990 кбит/сек не 909 кбит/сек)"</item>
+ <item msgid="2921767058740704969">"Теңгерілген аудиомазмұн мен байланыс сапасы (660 кб/сек не 606 кб/сек)"</item>
+ <item msgid="8860982705384396512">"Байланыс сапасы бойынша оңтайландырылды (330 кбит/сек не 303 кбит/сек)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Аудиомазмұн сапасы үшін оңтайландырылды"</item>
+ <item msgid="4327143584633311908">"Теңгерілген аудиомазмұн мен байланыс сапасы"</item>
+ <item msgid="4681409244565426925">"Байланыс сапасы бойынша оңтайландырылды"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Өшірулі"</item>
<item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 69610fa1f1f9..9372dbde51d4 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Ұялы деректер әрқашан белсенді"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұн кодегі"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth аудиокодегін таңдау"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудиомазмұны бойынша үлгі жиілігі"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth аудиокодегін таңдау:\nдискреттеу жылдамдығы"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth аудиомазмұны бойынша әр үлгіге келетін биттер саны"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth аудиокодегін таңдау:\nбит/үлгі"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудиомазмұны бойынша арна режимі"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth аудиокодегін таңдау:\nарна режимі"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC аудиокодегі: ойнату сапасы"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth LDAC аудиокодегін таңдау:\nойнату сапасы"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляция: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi жур. тір. дең. арт., Wi‑Fi желісін таңдағышта әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wi‑Fi сигналы әлсіз болғанда, деректер байланысы мәжбүрлі түрде ұялы желіге ауысады"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Демо режимде зауыттық мәндерге қайтару үшін құпия сөзді енгізу"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Келесі"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Құпия сөз қажет"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index 470112adf28f..87009e97dbf6 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ប្រើ​ការ​ពិនិត្យ HDCP សម្រាប់​តែ​មាតិកា DRM ប៉ុណ្ណោះ"</item>
<item msgid="45075631231212732">"ប្រើ​ការ​ពិនិត្យ HDCP ជា​និច្ច"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="5618929009984956469">"16 ប៊ីត​/​គំរូ"</item>
+ <item msgid="3412640499234627248">"24 ប៊ីត​/​គំរូ"</item>
+ <item msgid="121583001492929387">"32 ប៊ីត​/​គំរូ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="4726688794884191540">"16 ប៊ីត​/​គំរូ"</item>
+ <item msgid="305344756485516870">"24 ប៊ីត​/​គំរូ"</item>
+ <item msgid="244568657919675099">"32 ប៊ីត​/​គំរូ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="4106832974775067314">"ម៉ូ​ណូ"</item>
+ <item msgid="5571632958424639155">"ស្តេរ៉េអូ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ប្រើ​ការ​ជ្រើសរើស​ប្រព័ន្ធ (លំនាំ​ដើម)"</item>
+ <item msgid="8900559293912978337">"ម៉ូ​ណូ"</item>
+ <item msgid="8883739882299884241">"ស្តេរ៉េអូ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"បាន​បង្កើន​ប្រសិទ្ធភាព​​សម្រាប់​គុណភាព​សំឡេង (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"សំឡេង​ដែល​មាន​តុល្យភាព និង​គុណភាព​នៃ​ការ​ត​ភ្ជាប់ (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"បាន​បង្កើន​ប្រសិទ្ធភាព​សម្រាប់​គុណភាព​​នៃ​ការ​ត​ភ្ជាប់ (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"បាន​បង្កើន​ប្រសិទ្ធភាពសម្រាប់​​គុណភាព​សំឡេង"</item>
+ <item msgid="4327143584633311908">"សំឡេង​ដែល​មាន​តុល្យភាព និង​គុណភាព​នៃ​ការ​តភ្ជាប់"</item>
+ <item msgid="4681409244565426925">"បាន​បង្កើន​ប្រសិទ្ធភាព​​សម្រាប់គុណភាព​នៃ​ការ​ត​ភ្ជាប់"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"បិទ"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 205f01b18747..22360c7f4771 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ទិន្នន័យចល័តសកម្មជានិច្ច"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"កូឌិក​សំឡេង​ប៊្លូធូស"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ជ្រើសរើស​កូឌិក​សំឡេង​ប៊្លូធូស"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"អត្រា​គំរូ​សំឡេង​ប៊្លូធូស"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ជ្រើសរើស​កូឌិក​សំឡេង​ប៊្លូធូស៖\nអត្រា​គំរូ"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"កម្រិត​ប៊ីត​ក្នុង​មួយ​គំរូ​នៃ​សំឡេង​ប៊្លូធូស"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ជ្រើសរើស​កូឌិក​សំឡេង​ប៊្លូធូស៖\nកម្រិត​ប៊ីត​ក្នុង​មួយ​គំរូ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"មុខ​ងារ​រលកសញ្ញា​សំឡេង​ប៊្លូធូស"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ជ្រើសរើស​កូឌិក​សំឡេង​ប៊្លូធូស៖\nប្រភេទសំឡេង"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"កូឌិកប្រភេទ LDAC នៃសំឡេង​ប៊្លូធូស៖ គុណភាព​ចាក់​សំឡេង"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ជ្រើសរើស​កូឌិក​ប្រភេទ​ LDAC នៃសំឡេង​ប៊្លូធូស៖\nគុណភាព​ចាក់​សំឡេង"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"កំពុង​ចាក់៖ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញ​ជម្រើស​សម្រាប់​វិញ្ញាបនបត្រ​បង្ហាញ​ឥត​ខ្សែ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"បង្កើនកម្រិតកំណត់ហេតុវ៉ាយហ្វាយបង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើស​វ៉ាយហ្វាយ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ពេល​បាន​បើក វ៉ាយហ្វាយ​នឹង​កាន់តែ​បង្ខំ​ក្នុង​ការ​បញ្ជូន​ការ​ភ្ជាប់​ទិន្នន័យ​ទៅ​បណ្ដាញ​ចល័ត នៅ​ពេល​សញ្ញា​វ៉ាយហ្វាយ​យឺត"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"បញ្ចូល​ពាក្យ​សម្ងាត់ ដើម្បី​កំណត់ឧបករណ៍​​ឡើង​វិញ​ដូចពេលចេញ​ពី​រោងចក្រ នៅក្នុង​មុខងារ​សាកល្បង"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"បន្ទាប់"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"តម្រូវ​ឲ្យ​មានពាក្យ​សម្ងាត់"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index d26f95aa5078..c729b42eedcb 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM ವಿಷಯಗಳಿಗೆ ಮಾತ್ರ HDCP ಪರೀಕ್ಷಿಸುವಿಕೆಯನ್ನು ಬಳಸು"</item>
<item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="5618929009984956469">"16 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ <item msgid="3412640499234627248">"24 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ <item msgid="121583001492929387">"32 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="4726688794884191540">"16 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ <item msgid="305344756485516870">"24 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ <item msgid="244568657919675099">"32 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="4106832974775067314">"ಮೊನೊ"</item>
+ <item msgid="5571632958424639155">"ಸ್ಟೀರಿಯೊ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="8900559293912978337">"ಮೊನೊ"</item>
+ <item msgid="8883739882299884241">"ಸ್ಟೀರಿಯೊ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ಆಡಿಯೋ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ (990kbps/909kbps) ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+ <item msgid="2921767058740704969">"ಸಂತುಲಿತ ಆಡಿಯೊ ಮತ್ತು ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟ (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ (330kbps/303kbps) ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ಆಡಿಯೊ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್‌ ಮಾಡಲಾಗಿದೆ"</item>
+ <item msgid="4327143584633311908">"ಸಂತುಲಿತ ಆಡಿಯೊ ಮತ್ತು ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟ"</item>
+ <item msgid="4681409244565426925">"ಸಂಪರ್ಕ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ಆಫ್"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index e43883e91f8e..3cf5f8e0a954 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ ಕೋಡೆಕ್ ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಮಾದರಿ ದರ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೋ ಕೋಡೆಕ್:\nಮಾದರಿ ದರ ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ ಬಿಟ್ಸ್‌‌ನ ಪ್ರತಿ ಮಾದರಿ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೋ ಕೋಡೆಕ್‌:\nಬಿಟ್ಸ್ ಪ್ರತಿ ಮಾದರಿ ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಚಾನೆಲ್ ಮೋಡ್"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೋ ಕೋಡೆಕ್:\nಚಾನೆಲ್ ಮೋಡ್ ಆಯ್ಕೆ ಮಾಡಿ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ LDAC ಕೋಡೆಕ್: ಪ್ಲೇಬ್ಯಾಕ್ ಗುಣಮಟ್ಟ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ LDAC ಕೋಡೆಕ್:\nಪ್ಲೇಬ್ಯಾಕ್‌ ಗುಣಮಟ್ಟ ಆಯ್ಕೆ ಮಾಡಿ"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ಸ್ಟ್ರೀಮಿಂಗ್: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ವೈರ್‌ಲೆಸ್‌‌‌ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ಸಕ್ರಿಯಗೊಂಡರೆ, Wi‑Fi ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದ್ದರೂ ಕೂಡ, ಸೆಲ್ಯುಲರ್‌ಗೆ ಡೇಟಾ ಸಂಪರ್ಕವನ್ನು ಹಸ್ತಾಂತರಿಸುವಲ್ಲಿ Wi‑Fi ಹೆಚ್ಚು ಆಕ್ರಮಣಕಾರಿಯಾಗಿರುತ್ತದೆ"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್‌ಗೆ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ಮುಂದೆ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"ಪಾಸ್‌ವರ್ಡ್ ಅಗತ್ಯವಿದೆ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index 3c8424ac2ebe..460f94707e18 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM 콘텐츠에 대해서만 HDCP 확인 사용"</item>
<item msgid="45075631231212732">"항상 HDCP 확인 사용"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"시스템 설정 사용(기본)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"시스템 설정 사용(기본)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"시스템 설정 사용(기본)"</item>
+ <item msgid="8895532488906185219">"44.1kHz"</item>
+ <item msgid="2909915718994807056">"48.0kHz"</item>
+ <item msgid="3347287377354164611">"88.2kHz"</item>
+ <item msgid="1234212100239985373">"96.0kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"시스템 설정 사용(기본)"</item>
+ <item msgid="4482862757811638365">"44.1kHz"</item>
+ <item msgid="354495328188724404">"48.0kHz"</item>
+ <item msgid="7329816882213695083">"88.2kHz"</item>
+ <item msgid="6967397666254430476">"96.0kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"시스템 설정 사용(기본)"</item>
+ <item msgid="5618929009984956469">"16비트/샘플"</item>
+ <item msgid="3412640499234627248">"24비트/샘플"</item>
+ <item msgid="121583001492929387">"32비트/샘플"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"시스템 설정 사용(기본)"</item>
+ <item msgid="4726688794884191540">"16비트/샘플"</item>
+ <item msgid="305344756485516870">"24비트/샘플"</item>
+ <item msgid="244568657919675099">"32비트/샘플"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"시스템 설정 사용(기본)"</item>
+ <item msgid="4106832974775067314">"모노"</item>
+ <item msgid="5571632958424639155">"스테레오"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"시스템 설정 사용(기본)"</item>
+ <item msgid="8900559293912978337">"모노"</item>
+ <item msgid="8883739882299884241">"스테레오"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"오디오 품질(990kbps/909kbps)에 최적화됨"</item>
+ <item msgid="2921767058740704969">"오디오 및 연결 품질의 균형 유지(660Kbps/606Kbps)"</item>
+ <item msgid="8860982705384396512">"연결 품질(330kbps/303kbps)에 최적화됨"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"오디오 품질에 최적화됨"</item>
+ <item msgid="4327143584633311908">"오디오 및 연결 품질의 균형 유지"</item>
+ <item msgid="4681409244565426925">"연결 품질에 최적화됨"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"사용 안함"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 0a8c7274598e..3fbf4cdb5e19 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"모바일 데이터 항상 활성화"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"절대 볼륨 사용 안함"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"블루투스 오디오 코덱"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"블루투스 오디오 코덱 선택"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"블루투스 오디오 샘플링 비율"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"블루투스 오디오 코덱 선택:\n샘플링 비율"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"블루투스 오디오 샘플당 비트"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"블루투스 오디오 코덱 선택:\n샘플당 비트"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"블루투스 오디오 채널 모드"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"블루투스 오디오 코덱 선택:\n채널 모드"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"블루투스 오디오 LDAC 코덱: 재생 품질"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"블루투스 오디오 LDAC 코덱 선택:\n재생 품질"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"스트리밍: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시합니다."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"사용 설정하면 Wi-Fi 신호가 약할 때 데이터 연결을 Wi-Fi에서 데이터 네트워크로 더욱 적극적으로 핸드오버합니다."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"데모 모드에서 초기화하려면 비밀번호 입력"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"다음"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"비밀번호 입력 필요"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index 724d0c7fdd14..4d1a685806ea 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP текшерүү DRM мазмунуна гана колдонулсун"</item>
<item msgid="45075631231212732">"Ар дайым HDCP текшерүү колдонулсун"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="8895532488906185219">"44,1 кГц"</item>
+ <item msgid="2909915718994807056">"48,0 кГц"</item>
+ <item msgid="3347287377354164611">"88,2 кГц"</item>
+ <item msgid="1234212100239985373">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="4482862757811638365">"44,1 кГц"</item>
+ <item msgid="354495328188724404">"48,0 кГц"</item>
+ <item msgid="7329816882213695083">"88,2 кГц"</item>
+ <item msgid="6967397666254430476">"96,0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="5618929009984956469">"16 бит/үлгү"</item>
+ <item msgid="3412640499234627248">"24 бит/үлгү"</item>
+ <item msgid="121583001492929387">"32 бит/үлгү"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="4726688794884191540">"16 бит/үлгү"</item>
+ <item msgid="305344756485516870">"24 бит/үлгү"</item>
+ <item msgid="244568657919675099">"32 бит/үлгү"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Тутум тандаганды колдонуу (демейки)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Аудионун сапатын оптималдаштыруу (990кб/сек./909кб/сек.)"</item>
+ <item msgid="2921767058740704969">"Теңделген аудио жана туташуу сапаты (660кб/сек./606кб/сек.)"</item>
+ <item msgid="8860982705384396512">"Туташуунун сапатын оптималдаштыруу (330кб/сек./303кб/сек.)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Аудионун сапатын оптималдаштыруу"</item>
+ <item msgid="4327143584633311908">"Теңделген аудио жана туташуу сапаты"</item>
+ <item msgid="4681409244565426925">"Туташуунун сапатын оптималдаштыруу"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Өчүк"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 1a8aee3e415a..6608ae520502 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Уюлдук дайындар ар дайым активдүү"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth аудио кодегин тандаңыз"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудио үлгүсүнүн ылдамдыгы"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth аудио кодегин тандаңыз:\nҮлгү жыштыгы"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Бир үлгүдөгү Bluetooth аудио биттери"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth аудио кодегин тандаңыз:\nБир үлгүдөгү биттер"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудио каналынын режими"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth аудио кодегин тандаңыз:\nКанал режими"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth аудио LDAC кодеги: Ойнотуу сапаты"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth аудио LDAC кодегин тандаңыз:\nОйнотуу сапаты"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляция: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi Кармагычта Wi‑Fi протокол деңгээлин жогорулатуу жана ар бир SSID RSSI үчүн көрсөтүү."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Иштетилгенде, Wi-Fi байланышы үзүл-кесил болуп жатканда, Wi-Fi дайындарды уюктук операторго өжөрлүк менен өткөрөт."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Демо режиминде демейки жөндөөлөргө кайтаруу үчүн сырсөздү киргизиңиз"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Кийинки"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Сырсөз талап кылынат"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index 4b14eeb1ca82..67b59437c65b 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ໃຊ້ການກວດສອບ HDCP ສຳລັບເນື້ອຫາ DRM ເທົ່ານັ້ນ"</item>
<item msgid="45075631231212732">"ໃຊ້ການກວດສອບ HDCP ສະເໝີ"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Use System Selection (Default)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Use System Selection (Default)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Use System Selection (Default)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Use System Selection (Default)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Use System Selection (Default)"</item>
+ <item msgid="4106832974775067314">"ໂທນດຽວ"</item>
+ <item msgid="5571632958424639155">"ສະເຕຣິໂອ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Use System Selection (Default)"</item>
+ <item msgid="8900559293912978337">"ໂທນດຽວ"</item>
+ <item msgid="8883739882299884241">"ສະເຕຣິໂອ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ປັບແຕ່ງສຳລັບຄຸນນະພາບສຽງ (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanced Audio And Connection Quality (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"ປັບແຕ່ງສຳລັບຄຸນນະພາບການເຊື່ອມຕໍ່ (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ປັບແຕ່ງສຳລັບຄຸນນະພາບສຽງ"</item>
+ <item msgid="4327143584633311908">"Balanced Audio And Connection Quality"</item>
+ <item msgid="4681409244565426925">"ປັບແຕ່ງສຳລັບຄຸນນະພາບການເຊື່ອມຕໍ່"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ປິດ"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 569c0ce56979..9c493f290a7a 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ຂໍ້​ມູນ​ມື​ຖື​ເປີດ​ຢູ່​ສະ​ເໝີ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Select Bluetooth Audio Codec"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Select Bluetooth Audio Codec:\nSample Rate"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Select Bluetooth Audio Codec:\nBits Per Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Select Bluetooth Audio Codec:\nChannel Mode"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC Codec: Playback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Select Bluetooth Audio LDAC Codec:\nPlayback Quality"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ເພີ່ມ​ລະ​ດັບ​ການ​ເກັບ​ປະ​ຫວັດ Wi‑Fi, ສະ​ແດງ​ຕໍ່ SSID RSSI ​ໃນ​ Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ເມື່ອ​ເປີດ​ນຳ​ໃຊ້​ແລ້ວ, ເຄືອ​ຂ່າຍ Wi-Fi ຈະ​ຖືກ​ປ່ຽນ​ໄປ​ໃຊ້​ເຄືອ​ຂ່າຍ​ໂທ​ລະ​ສັບ​ແທນ​ຫາກ​ສັນ​ຍານ Wi-Fi ອ່ອນ"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ຕໍ່ໄປ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"​ຕ້ອງ​ໃສ່​ລະ​ຫັດ​ຜ່ານ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index deed74f3a0cd..48fa9362b4e3 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Taikyti HDCP tikrinimą tik DRM turiniui"</item>
<item msgid="45075631231212732">"Visada naudoti HDCP tikrinimą"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="5618929009984956469">"16 bitų pavyzdyje"</item>
+ <item msgid="3412640499234627248">"24 bitai pavyzdyje"</item>
+ <item msgid="121583001492929387">"32 bitai pavyzdyje"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="4726688794884191540">"16 bitų pavyzdyje"</item>
+ <item msgid="305344756485516870">"24 bitai pavyzdyje"</item>
+ <item msgid="244568657919675099">"32 bitai pavyzdyje"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="4106832974775067314">"Monofoninis garsas"</item>
+ <item msgid="5571632958424639155">"Stereofoninis garsas"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="8900559293912978337">"Monofoninis garsas"</item>
+ <item msgid="8883739882299884241">"Stereofoninis garsas"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizuota garso kokybė (990 Kb/s; 909 Kb/s)"</item>
+ <item msgid="2921767058740704969">"Subalansuotą garso ir ryšio kokybė (660 kbps / 606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizuota ryšio kokybė (330 Kb/s; 303 Kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizuota garso kokybė"</item>
+ <item msgid="4327143584633311908">"Subalansuota garso ir ryšio kokybė"</item>
+ <item msgid="4681409244565426925">"Optimizuota ryšio kokybė"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Išjungta"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 28329ccb4b42..3090d30bcec8 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Korinio ryšio duomenys visada aktyvūs"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Išjungti didžiausią garsą"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"„Bluetooth“ garso kodekas"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Pasirinkite „Bluetooth“ garso kodeką"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"„Bluetooth“ garso pavyzdžio dažnis"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Pasirinkite „Bluetooth“ garso kodekas:\nimties dydis"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"„Bluetooth“ garso įrašo bitų skaičius pavyzdyje"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Pasirinkite „Bluetooth“ garso kodeką:\nbitų skaičius viename pavyzdyje"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"„Bluetooth“ garso kanalo režimas"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Pasirinkite „Bluetooth“ garso kodeką:\n kanalo režimas"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"„Bluetooth“ garso LDAC kodekas: atkūrimo kokybė"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pasirinkite „Bluetooth“ garso LDAC kodeką:\natkūrimo kokybė"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Srautinis perdavimas: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jei įgalinta ši parinktis, „Wi‑Fi“ agresyviau perduos duomenų ryšį į mobiliojo ryšio tinklą, kai „Wi‑Fi“ signalas bus silpnas"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Įv. slapt. ir atk. gam. nust. dem. rež."</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Kitas"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Būtina nurodyti slaptažodį"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index cf8b2c92bd6a..16dc9813609d 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Izmantot HDCP pārbaudi tikai DRM saturam"</item>
<item msgid="45075631231212732">"Vienmēr izmantot HDCP pārbaudi"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="5618929009984956469">"16 biti iztvērumā"</item>
+ <item msgid="3412640499234627248">"24 biti iztvērumā"</item>
+ <item msgid="121583001492929387">"32 biti iztvērumā"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="4726688794884191540">"16 biti iztvērumā"</item>
+ <item msgid="305344756485516870">"24 biti iztvērumā"</item>
+ <item msgid="244568657919675099">"32 biti iztvērumā"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Audio kvalitātes optimizēšana (990 Kb/s/909 Kb/s)"</item>
+ <item msgid="2921767058740704969">"Samērīga audio un savienojuma kvalitāte (660 Kb/s/606 Kb/s)"</item>
+ <item msgid="8860982705384396512">"Savienojuma kvalitātes optimizēšana (330 Kb/s/303 Kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Audio kvalitātes optimizēšana"</item>
+ <item msgid="4327143584633311908">"Samērīga audio un savienojuma kvalitāte"</item>
+ <item msgid="4681409244565426925">"Savienojuma kvalitātes optimizēšana"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Izslēgts"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index b64216a7deae..d782e89b4821 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Vienmēr aktīvs mobilo datu savienojums"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Atspējot absolūto skaļumu"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeks"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Atlasīt Bluetooth audio kodeku"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth audio iztveršanas ātrums"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Atlasīt Bluetooth audio kodeku:\niztveršanas ātrums"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio bitu skaits iztvērumā"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Atlasīt Bluetooth audio kodeku:\nbitu skaits iztvērumā"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth audio kanāla režīms"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Atlasīt Bluetooth audio kodeku:\nkanāla režīms"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audio LDAC kodeks: atskaņošanas kvalitāte"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Atlasīt Bluetooth audio LDAC kodeku:\natskaņošanas kvalitāte"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Straumēšana: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ja opcija ir iespējota un Wi‑Fi signāls ir vājš, datu savienojuma pāreja no Wi-Fi uz mobilo tīklu tiks veikta agresīvāk."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Iev. paroli, lai atiest. rūpnīcas iest. dem. režīmā"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Tālāk"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Nepieciešama parole"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index 72124f7cc101..e334467744c3 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Користи ХДЦП проверка само за ДРМ содржина"</item>
<item msgid="45075631231212732">"Секогаш користи ХДЦП проверка"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Користи избор на системот (стандардно)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Користи избор на системот (стандардно)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Користи избор на системот (стандардно)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Користи избор на системот (стандардно)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Користи избор на системот (стандардно)"</item>
+ <item msgid="5618929009984956469">"16 бита/семпл"</item>
+ <item msgid="3412640499234627248">"24 бита/семпл"</item>
+ <item msgid="121583001492929387">"32 бита/семпл"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Користи избор на системот (стандардно)"</item>
+ <item msgid="4726688794884191540">"16 бита/семпл"</item>
+ <item msgid="305344756485516870">"24 бита/семпл"</item>
+ <item msgid="244568657919675099">"32 бита/семпл"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Користи избор на системот (стандардно)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Користи избор на системот (стандардно)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Оптимизирано за квалитет на аудиото (990 кб/с - 909 кб/с)"</item>
+ <item msgid="2921767058740704969">"Балансиран квалитет на звукот и врската (660 kb/s/606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Оптимизирано за квалитет на врската (330 кб/с - 303 кб/с)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Оптимизирано за квалитет на аудиото"</item>
+ <item msgid="4327143584633311908">"Балансиран квалитет на звукот и врската"</item>
+ <item msgid="4681409244565426925">"Оптимизирано за квалитет на врската"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Исклучено"</item>
<item msgid="1593289376502312923">"64.000"</item>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index df106ed43d7e..0662c8fbf569 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Мобилниот интернет е секогаш активен"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек за аудио преку Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Изберете кодек за аудио преку Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Стапка на семпл преку Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Изберете кодек за аудио преку Bluetooth:\nСтапка на примерок"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Аудио бит-по-семпл преку Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Изберете кодек за аудио преку Bluetooth:\nБитови/примерок"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим на канал за аудио преку Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Изберете кодек за аудио преку Bluetooth:\nРежим на канал"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек за LDAC-аудио преку Bluetooth: квалитет на репродукција"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изберете кодек за LDAC-аудио преку Bluetooth:\nКвалитет на репродукција"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Емитување: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Кога е вклучено, Wi-Fi ќе биде поагресивно при предавање на поврзувањето со податоци на мобилната мрежа при слаб сигнал на Wi-Fi."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Внесете лозинка за фаб. ресет. во демо"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Следно"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Потребна е лозинка"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index 38ba63aba70a..e79a567287a2 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM ഉള്ളടക്കത്തിനുമാത്രമായി HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
<item msgid="45075631231212732">"എല്ലായ്‌പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="5618929009984956469">"16 ബിറ്റ്/സാമ്പിൾ"</item>
+ <item msgid="3412640499234627248">"24 ബിറ്റ്/സാമ്പിൾ"</item>
+ <item msgid="121583001492929387">"32 ബിറ്റ്/സാമ്പിൾ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="4726688794884191540">"16 ബിറ്റ്/സാമ്പിൾ"</item>
+ <item msgid="305344756485516870">"16 ബിറ്റ്/സാമ്പിൾ"</item>
+ <item msgid="244568657919675099">"32 ബിറ്റ്/സാമ്പിൾ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="4106832974775067314">"മോണോ"</item>
+ <item msgid="5571632958424639155">"സ്റ്റീരിയോ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+ <item msgid="8900559293912978337">"മോണോ"</item>
+ <item msgid="8883739882299884241">"സ്റ്റീരിയോ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ശബ്‌ദനിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"സന്തുലിതമായ ‌ഓഡിയോ/കണക്ഷൻ നിലവാരം (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"കണക്ഷൻ നിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ശബ്‌ദനിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു"</item>
+ <item msgid="4327143584633311908">"സന്തുലിതമായ ‌ഓഡിയോ/കണക്ഷൻ നിലവാരം"</item>
+ <item msgid="4681409244565426925">"കണക്ഷൻ നിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ഓഫ്"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index f61b71dbab48..b23862524d74 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"സെല്ലുലാർ ഡാറ്റ എല്ലായ്‌പ്പോഴും സജീവം"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth ഓഡിയോ കോഡെക്"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth ഓഡിയോ കോഡെക് തിരഞ്ഞെടുക്കുക"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth ഓഡിയോ സാമ്പിൾ നിരക്ക്"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth ഓഡിയോ കോഡെക് തിരഞ്ഞെടുക്കുക:\nസാമ്പിൾ നിരക്ക്"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"പ്രതി സാമ്പിളിലെ Bluetooth ഓഡിയോ ബിറ്റ് നി"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth ഓഡിയോ കോഡെക് തിരഞ്ഞെടുക്കുക:\nബിറ്റ്‌/സാമ്പിൾ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth ഓഡിയോ ചാനൽ മോഡ്"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth ഓഡിയോ കോഡെക് തിരഞ്ഞെടുക്കുക:\nചാനൽ മോഡ്"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth ഓഡിയോ LDAC കോഡെക്: പ്ലേബാക്ക് ‌നിലവാരം"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth ഓഡിയോ LDAC കോഡെക് തിരഞ്ഞെടുക്കുക:\nപ്ലേബാക്ക് ‌നിലവാരം"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"സ്ട്രീമിംഗ്: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"വയർലെസ് ഡിസ്‌പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്‌ഷനുകൾ ദൃശ്യമാക്കുക"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"പ്രവർത്തനക്ഷമമായിരിക്കുമ്പോൾ, വൈഫൈ സിഗ്‌നൽ കുറവായിരിക്കുന്ന സമയത്ത് സെല്ലുലാറിലേക്ക് ഡാറ്റ കണക്ഷൻ മുഖേന കൈമാറുന്നതിൽ വൈഫൈ കൂടുതൽ പ്രവർത്തനക്ഷമമാകും"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ഡെമോ ‌മോഡിൽ ഫാക്ടറി റീസെറ്റിന് പാസ്‌വേഡ് നൽകുക"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"അടുത്തത്"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"പാസ്‌വേഡ് ആവശ്യമാണ്"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index f4d1ca3ca6fc..bb6131039dc6 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP шалгахыг зөвхөн DRM контентэд ашиглах"</item>
<item msgid="45075631231212732">"Байнга HDCP шалгахыг ашиглах"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="8895532488906185219">"44.1 кГц"</item>
+ <item msgid="2909915718994807056">"48.0 кГц"</item>
+ <item msgid="3347287377354164611">"88.2 кГц"</item>
+ <item msgid="1234212100239985373">"96.0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="4482862757811638365">"44.1 кГц"</item>
+ <item msgid="354495328188724404">"48.0 кГц"</item>
+ <item msgid="7329816882213695083">"88.2 кГц"</item>
+ <item msgid="6967397666254430476">"96.0 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="5618929009984956469">"16 бит/жишээ"</item>
+ <item msgid="3412640499234627248">"24 бит/жишээ"</item>
+ <item msgid="121583001492929387">"32 бит/жишээ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="4726688794884191540">"16 бит/жишээ"</item>
+ <item msgid="305344756485516870">"24 бит/жишээ"</item>
+ <item msgid="244568657919675099">"32 бит/жишээ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Аудио чанарт тааруулсан (990кб/цаг/909кб/цаг)"</item>
+ <item msgid="2921767058740704969">"Аудио, холболтын чанарыг тэнцүүлсэн (660кб/цаг/606кб/цаг)"</item>
+ <item msgid="8860982705384396512">"Холболтын чанарт тааруулсан (330кб/цаг/303кб/цаг)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Аудио чанарт тааруулсан"</item>
+ <item msgid="4327143584633311908">"Аудио, холболтын чанарыг тэнцүүлсэн"</item>
+ <item msgid="4681409244565426925">"Холболтын чанарт тааруулсан"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Идэвхгүй"</item>
<item msgid="1593289376502312923">"64000"</item>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 940e0b03ed50..68f3df5f14d4 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Үүрэн холбооны датаг үргэлж идэвхтэй байлгана"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодлогч"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth аудио кодлогч сонгох"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудио жишээний үнэлгээ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth аудио кодлогч сонгох:\nЖишээний хэмжээ"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Жишээ тутмын Bluetooth аудионы бит"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth аудио кодлогч сонгох:\nЖишээ бүрт бит"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудио сувгийн горим"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth аудио кодлогч сонгох:\nСувгийн горим"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Аудио LDAC Кодлогч: Тоглуулагчийн чанар"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Аудио LDAC Кодлогч сонгох:\nТоглуулагчийн чанар"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Дамжуулж байна: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Идэвхжүүлсэн үед Wi‑Fi дохио сул бол дата холболтыг Үүрэн рүү шилжүүлэхдээ илүү идэвхтэй байх болно"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"Гринвичийн цаг"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Үйлдвэрийн тохиргоог демо горимд ажиллуулахын тулд нууц үг оруулна уу"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Дараагийн"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Нууц үг шаардлагатай"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index d8c8dafb6a2e..e83b1f9c1efd 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"केवळ DRM सामग्रीसाठी HDCP तपासणी वापरा"</item>
<item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="5618929009984956469">"16 बिट/नमुना"</item>
+ <item msgid="3412640499234627248">"24 बिट/नमुना"</item>
+ <item msgid="121583001492929387">"32 बिट/नमुना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="4726688794884191540">"16 बिट/नमुना"</item>
+ <item msgid="305344756485516870">"24 बिट/नमुना"</item>
+ <item msgid="244568657919675099">"32 बिट/नमुना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="4106832974775067314">"मोनो"</item>
+ <item msgid="5571632958424639155">"स्टिरिओ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+ <item msgid="8900559293912978337">"मोनो"</item>
+ <item msgid="8883739882299884241">"स्टिरिओ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ऑडिओ गुणवत्ता (990kbps/909kbps) साठी ऑप्टिमाइझ केली"</item>
+ <item msgid="2921767058740704969">"संतुलित ऑडिओ आणि कनेक्शन गुणवत्ता (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"कनेक्शन गुणवत्ता (330kbps/303kbps) साठी ऑप्टिमाइझ केली"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ऑडिओ गुणवत्तेसाठी ऑप्टिमाइझ केले"</item>
+ <item msgid="4327143584633311908">"संतुलित ऑडिओ आणि कनेक्शन गुणवत्ता"</item>
+ <item msgid="4681409244565426925">"कनेक्शन गुणवत्तेसाठी ऑप्टिमाइझ केले"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"बंद"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 6c012c834907..243885f1cc43 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा नेहमी सक्रिय"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"संपूर्ण आवाज अक्षम करा"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडिओ कोडेक"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ब्लूटुथ ऑडिओ कोडेक निवडा"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लूटूथ ऑडिओ नमुना दर"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ब्लूटुथ ऑडिओ कोडेक निवडा:\nनमुना दर"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"प्रति नमुना ब्लूटुथ ऑडिओ बिट"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ब्लूटुथ ऑडिओ कोडेक निवडा:\nबिट प्रति नमुना"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लूटूथ ऑडिओ चॅनेल मोड"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ब्लूटुथ ऑडिओ कोडेक निवडा:\nचॅनेल मोड"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ब्लूटुथ ऑडिओ LDAC कोडेक: प्लेबॅक गुणवत्ता"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ब्लूटुथ ऑडिओ LDAC कोडेक निवडा:\nप्लेबॅक गुणवत्ता"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"धारावाहिक: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस प्रदर्शन प्रमाणिकरणासाठी पर्याय दर्शवा"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाय-फाय लॉगिंग स्‍तर वाढवा, वाय-फाय निवडकामध्‍ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"सक्षम केल्यास, वाय-फाय सिग्‍नल निम्‍न असताना, वाय-फाय डेटा कनेक्‍शन सेल्‍युलरवर बळपूर्वक स्विच करेल."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी संकेतशब्द प्रविष्ट करा"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"पुढील"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"संकेतशब्द आवश्यक"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index 5feff378d0cc..886dd44f4d15 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Gunakan penyemakan HDCP untuk kandungan DRM sahaja"</item>
<item msgid="45075631231212732">"Sentiasa gunakan penyemakan HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="5618929009984956469">"16 bit/sampel"</item>
+ <item msgid="3412640499234627248">"24 bit/sampel"</item>
+ <item msgid="121583001492929387">"32 bit/sampel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="4726688794884191540">"16 bit/sampel"</item>
+ <item msgid="305344756485516870">"24 bit/sampel"</item>
+ <item msgid="244568657919675099">"32 bit/sampel"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Gunakan Pilihan Sistem (Lalai)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Dioptimumkan untuk Kualiti Audio (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Audio Seimbang dan Kualiti Sambungan (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Dioptimumkan untuk Kualiti Sambungan (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Dioptimumkan untuk Kualiti Audio"</item>
+ <item msgid="4327143584633311908">"Audio Seimbang dan Kualiti Sambungan"</item>
+ <item msgid="4681409244565426925">"Dioptimumkan untuk Kualiti Sambungan"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Mati"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index acaab9de10ad..234f4cfee2e2 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data selular sentiasa aktif"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Lumpuhkan kelantangan mutlak"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Pilih Codec Audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Kadar Sampel Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Pilih Codec Audio Bluetooth:\nKadar Sampel"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit Per Sampel Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Pilih Codec Audio Bluetooth:\nBit Per Sampel"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mod Saluran Audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Pilih Codec Audio Bluetooth:\nMod Saluran"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC Audio Bluetooth: Kualiti Main Balik"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Pilih Codec LDAC Audio Bluetooth:\nKualiti Main Balik"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Penstriman: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Apabila didayakan, Wi-Fi akan menjadi lebih agresif dalam menyerahkan sambungan data ke Selular, apabila isyarat Wi-Fi rendah"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Mskkn kta laluan utk ttpn sml kilang dlm mod demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Seterusnya"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Kata laluan diperlukan"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index 9e71ae5fd6bf..c30bd20b112f 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRMအကြောင်းအရာအတွက် HDCPစစ်ဆေးခြင်းကိုသုံးမည်"</item>
<item msgid="45075631231212732">"HDCP checkingအားအမြဲသုံးပါ"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="8895532488906185219">"၄၄.၁ kHz"</item>
+ <item msgid="2909915718994807056">"၄၈.၀ kHz"</item>
+ <item msgid="3347287377354164611">"၈၈.၂ kHz"</item>
+ <item msgid="1234212100239985373">"၉၆.၀ kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="4482862757811638365">"၄၄.၁ kHz"</item>
+ <item msgid="354495328188724404">"၄၈.၀ kHz"</item>
+ <item msgid="7329816882213695083">"၈၈.၂ kHz"</item>
+ <item msgid="6967397666254430476">"၉၆.၀ kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="5618929009984956469">"၁၆ bits/နမူနာ"</item>
+ <item msgid="3412640499234627248">"၂၄ bits/နမူနာ"</item>
+ <item msgid="121583001492929387">"၃၂ bits/နမူနာ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="4726688794884191540">"၁၆ bits/နမူနာ"</item>
+ <item msgid="305344756485516870">"၂၄ bits/နမူနာ"</item>
+ <item msgid="244568657919675099">"၃၂ bits/နမူနာ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="4106832974775067314">"မိုနို"</item>
+ <item msgid="5571632958424639155">"စတီရီယို"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="8900559293912978337">"မိုနို"</item>
+ <item msgid="8883739882299884241">"စတီရီယို"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"အသံအရည်အသွေးကို ပိုကောင်းအောင် ပြုလုပ်ထားသည် (၉၉၀kbps/၉၀၉kbps)"</item>
+ <item msgid="2921767058740704969">"အသံနှင့် ချိတ်ဆက်မှု အရည်အသွေးကို မျှတအောင် ချိန်ဆပေးသည် (၆၆၀kbps/၆၀၆kbps)"</item>
+ <item msgid="8860982705384396512">"ချိတ်ဆက်မှု အရည်အသွေးကို ပိုကောင်းအောင် ပြုလုပ်ထားသည် (၃၃၀kbps/၃၀၃kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"အသံအရည်အသွေးကို ပိုကောင်းအောင် ပြုလုပ်ထားသည်"</item>
+ <item msgid="4327143584633311908">"အသံနှင့် ချိတ်ဆက်မှု အရည်သွေးကို မျှတအောင် ချိန်ဆပေးသည်"</item>
+ <item msgid="4681409244565426925">"ချိတ်ဆက်မှု အရည်အသွေးကို ပိုကောင်းအောင် ပြုလုပ်ထားသည်"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ပိတ်ပါ"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2c976d074283..93507d2bda6a 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ဆဲလ်လူလာဒေတာ အမြဲတမ်းဖွင့်ထားသည်"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ဘလူးတုသ်အသံကိုးဒက်ခ်ကို ရွေးပါ"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ဘလူးတုသ်အသံနမူနာနှုန်း"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်ကို ရွေးပါ−\nနမူနာနှုန်း"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ်အသံပမာဏ Bits"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်ကို ရွေးပါ−\nနမူနာတစ်ခုချင်းအတွက် Bits"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ဘလူးတုသ်အသံချန်နယ်မုဒ်"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ဘလူးတုသ်အသံကိုးဒက်ခ်ကို ရွေးပါ−\nချန်နယ်မုဒ်"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ဘလူးတုသ်အသံ LDAC ကိုးဒက်ခ်− နားထောင်ရန် အရည်အသွေး"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ဘလူးတုသ်အသံ LDAC ကိုးဒက်ခ်ကို ရွေးပါ−\nနားထောင်ရန် အရည်အသွေး"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"တိုက်ရိုက်လွှင့်နေသည်− <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ဖွင့်ထားလျှင်၊ Wi‑Fi မှ ဆယ်လူလာသို့ အချက်လက် ချိတ်ဆက်မှုအား လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်၊ WIFI အားနည်းနေချိန်တွင်"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"ဂရင်းနစ်စံတော်ချိန်"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ဒီမိုမုဒ်၌မူလဆက်တင်ထားရန် စကားဝှက်ထည့်ပါ"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ရှေ့သို့"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"စကားဝှက် လိုအပ်သည်"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 1d5d0985b4f0..36bc9e0ea3a0 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Bruk HDCP-kontroll kun for DRM-innhold"</item>
<item msgid="45075631231212732">"Bruk alltid HDCP-kontroll"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Bruk systemvalg (standard)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Bruk systemvalg (standard)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Bruk systemvalg (standard)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Bruk systemvalg (standard)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Bruk systemvalg (standard)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Bruk systemvalg (standard)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Bruk systemvalg (standard)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Bruk systemvalg (standard)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimalisert for lydkvalitet (990 kbps / 909 kbps)"</item>
+ <item msgid="2921767058740704969">"Balansert lyd- og tilkoblingskvalitet (660 kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Optimalisert for tilkoblingskvalitet (330 kbps / 303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimalisert for lydkvalitet"</item>
+ <item msgid="4327143584633311908">"Balansert lyd- og tilkoblingskvalitet"</item>
+ <item msgid="4681409244565426925">"Optimalisert for tilkoblingskvalitet"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Av"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 02b742a6ac06..172d59cd2466 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata er alltid aktiv"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slå av funksjonen for absolutt volum"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Velg kodek for Bluetooth-lyd"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Samplefrekvens for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Velg kodek for Bluetooth-lyd:\nSamplefrekvens"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per sample for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Velg lydkodek for Bluetooth:\nBits Per Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanalmodus for Bluetooth-lyd"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Velg lydkodek for Bluetooth:\nKanalmodus"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-kodek for Bluetooth-lyd: Avspillingskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Velg LDAC-kodek for Bluetooth-lyd:\nAvspillingskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strømming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Hvis dette slås på, overfører Wi-Fi-nettverket datatilkoblingen til mobil mer aggressivt når Wi-Fi-signalet er lavt"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Skriv inn passordet for å tilbakestille til fabrikkstandard i demomodus"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Neste"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Passord er obligatorisk"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index 19597ec66ac6..cee130b273f4 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM सामग्रीको लागि मात्र HDCP जाँचको प्रयोग गर्नुहोस्"</item>
<item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="8895532488906185219">"४४.१ kHz"</item>
+ <item msgid="2909915718994807056">"४८.० kHz"</item>
+ <item msgid="3347287377354164611">"८८.२ kHz"</item>
+ <item msgid="1234212100239985373">"९६.० kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="4482862757811638365">"४४.१ kHz"</item>
+ <item msgid="354495328188724404">"४८.० kHz"</item>
+ <item msgid="7329816882213695083">"८८.२ kHz"</item>
+ <item msgid="6967397666254430476">"९६.० kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="5618929009984956469">"१६ बिट/नमूना"</item>
+ <item msgid="3412640499234627248">"२४ बिट/नमूना"</item>
+ <item msgid="121583001492929387">"३२ बिट/नमूना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="4726688794884191540">"१६ बिट/नमूना"</item>
+ <item msgid="305344756485516870">"२४ बिट/नमूना"</item>
+ <item msgid="244568657919675099">"३२ बिट/नमूना"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="4106832974775067314">"मोनो"</item>
+ <item msgid="5571632958424639155">"स्टेरियो"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="8900559293912978337">"मोनो"</item>
+ <item msgid="8883739882299884241">"स्टेरियो"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"अडियोको गुणस्तर सुधार्न अनुकूलन गरिएको (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"सन्तुलित अडियो र जडान गुणस्तर (६६०kbps/६०६kbps)"</item>
+ <item msgid="8860982705384396512">"जडानको गुणस्तर सुधार्न अनुकूलन गरिएको (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"अडियोको गुणस्तर सुधार्न अनुकूलन गरिएको"</item>
+ <item msgid="4327143584633311908">"सन्तुलित अडियो र जडान गुणस्तर"</item>
+ <item msgid="4681409244565426925">"जडानको गुणस्तर सुधार्न अनुकूलन गरिएको"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
<item msgid="1593289376502312923">"६४के"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 12b3b1553588..c6c7fd345b7f 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेलुलर डेटा सधैं सक्रिय"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लुटुथ अडियोको कोडेक"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ब्लुटुथ अडियोको कोडेक चयन गर्नुहोस्‌"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लुटुथ अडियोको नमूना दर"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ब्लुटुथ अडियोको कोडेक चयन गर्नुहोस्‌:\nनमूना दर"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"प्रति नमूना ब्लुटुथ अडियोका बिटहरू"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ब्लुटुथ अडियोको कोडेक चयन गर्नुहोस्‌:\n प्रति नमूना बिट"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लुटुथ अडियो च्यानलको मोड"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ब्लुटुथ अडियोको कोडेक चयन गर्नुहोस्‌:\nच्यानलको मोड"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ब्लुटुथ अडियो LDAC कोडेक: प्लेब्याक गुणस्तर"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ब्लुटुथ अडियो LDAC कोडेक चयन गर्नुहोस्‌:\nप्लेब्याक गुणस्तर"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"स्ट्रिमिङ: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wi-Fi संकेत कम हुँदा, सक्षम जब गरिन्छ, Wi-Fi सेलुलर लागि डेटा जडान सुम्पनामा बढी आक्रामक हुनेछ"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्ट गर्नुहोस्"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"अर्को"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक छ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index eaa840224c10..93db1c6178e9 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP-controle alleen voor DRM-content gebruiken"</item>
<item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="5618929009984956469">"16 bits per sample"</item>
+ <item msgid="3412640499234627248">"24 bits per sample"</item>
+ <item msgid="121583001492929387">"32 bits per sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="4726688794884191540">"16 bits per sample"</item>
+ <item msgid="305344756485516870">"24 bits per sample"</item>
+ <item msgid="244568657919675099">"32 bits per sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Systeemselectie gebruiken (standaard)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Geoptimaliseerd voor audiokwaliteit (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Gebalanceerde audio- en verbindingskwaliteit (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Geoptimaliseerd voor verbindingskwaliteit (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Geoptimaliseerd voor audiokwaliteit"</item>
+ <item msgid="4327143584633311908">"Gebalanceerde audio- en verbindingskwaliteit"</item>
+ <item msgid="4681409244565426925">"Geoptimaliseerd voor verbindingskwaliteit"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Uit"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 9d53379bba16..304397104810 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele data altijd actief"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-audiocodec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth-audiocodec selecteren"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bemonsteringsfrequentie (sample rate) van Bluetooth-audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth-audiocodec selecteren:\nbemonsteringsfrequentie"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per sample voor Bluetooth-audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth-audiocodec selecteren:\nbit per sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanaalmodus voor Bluetooth-audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth-audiocodec selecteren:\nkanaalmodus"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-codec voor Bluetooth-audio: afspeelkwaliteit"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"LDAC-codec voor Bluetooth-audio selecteren:\nafspeelkwaliteit"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Indien ingeschakeld, is wifi agressiever bij het overgeven van de gegevensverbinding aan mobiel wanneer het wifi-signaal zwak is"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Geef wachtwoord op om terug te zetten op fabrieksinstellingen in demomodus"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Volgende"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Wachtwoord vereist"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index 7a100a9a5c9d..f7ca9e1646e6 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ਕੇਵਲ DRM ਸਮੱਗਰੀ ਲਈ HDCP ਜਾਂਚ"</item>
<item msgid="45075631231212732">"ਹਮੇਸਾਂ HDCP ਜਾਂਚ ਵਰਤੋ"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="5618929009984956469">"16 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ <item msgid="3412640499234627248">"24 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ <item msgid="121583001492929387">"32 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="4726688794884191540">"16 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ <item msgid="305344756485516870">"24 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ <item msgid="244568657919675099">"32 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="4106832974775067314">"ਮੋਨੋ"</item>
+ <item msgid="5571632958424639155">"ਸਟੀਰੀਓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="8900559293912978337">"ਮੋਨੋ"</item>
+ <item msgid="8883739882299884241">"ਸਟੀਰੀਓ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ਔਡੀਓ ਗੁਣਵੱਤਾ ਲਈ ਸੁਯੋਗ ਬਣਾਇਆ ਗਿਆ (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"ਸੰਤੁਲਿਤ ਔਡੀਓ ਅਤੇ ਕਨੈਕਸ਼ਨ ਗੁਣਵੱਤਾ (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"ਕਨੈਕਸ਼ਨ ਗੁਣਵੱਤਾ ਲਈ ਸੁਯੋਗ ਬਣਾਇਆ ਗਿਆ (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ਔਡੀਓ ਗੁਣਵੱਤਾ ਲਈ ਸੁਯੋਗ ਬਣਾਇਆ ਗਿਆ"</item>
+ <item msgid="4327143584633311908">"ਸੰਤੁਲਿਤ ਔਡੀਓ ਅਤੇ ਕਨੈਕਸ਼ਨ ਗੁਣਵੱਤਾ"</item>
+ <item msgid="4681409244565426925">"ਕਨੈਕਸ਼ਨ ਗੁਣਵੱਤਾ ਲਈ ਸੁਯੋਗ ਬਣਾਇਆ ਗਿਆ"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ਬੰਦ"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 647e573ac147..13c817e99f40 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ਸੈਲਿਊਲਰ ਡੇਟਾ ਹਮੇਸ਼ਾ ਕਿਰਿਆਸ਼ੀਲ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਵੌਲਿਊਮ ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ ਚੁਣੋ"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਨਮੂਨਾ ਦਰ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ ਚੁਣੋ:\nਸੈਂਪਲ ਰੇਟ"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਬਲੂਟੁੱਥ ਔਡੀਓ ਬਿਟਾਂ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ ਚੁਣੋ:\nਬਿਟਾਂ ਪ੍ਰਤੀ ਨਮੂਨਾ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਚੈਨਲ ਮੋਡ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ ਚੁਣੋ:\nਚੈਨਲ ਮੋਡ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ਬਲੂਟੁੱਥ ਔਡੀਓ LDAC ਕੋਡੇਕ: ਪਲੇਬੈਕ ਗੁਣਵੱਤਾ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ਬਲੂਟੁੱਥ ਔਡੀਓ LDAC ਕੋਡੇਕ ਚੁਣੋ:\nਪਲੇਬੈਕ ਗੁਣਵੱਤਾ"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ਸਟ੍ਰੀਮਿੰਗ: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ਵਾਇਰਲੈਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਦਿਖਾਓ"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, Wi‑Fi Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ਜਦੋਂ ਸਮਰਥਿਤ ਹੋਵੇ, ਤਾਂ Wi‑Fi ਸੈਲਿਊਲਰ ਨੂੰ ਡੈਟਾ ਕਨੈਕਸ਼ਨ ਹੈਂਡ ਓਵਰ ਕਰਨ ਵਿੱਚ ਵੱਧ ਅਗ੍ਰੈਸਿਵ ਹੋ ਜਾਏਗਾ, ਜਦੋਂ Wi‑Fi ਸਿਗਨਲ ਘੱਟ ਹੋਵੇ"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ਡੈਮੋ ਮੋਡ \'ਚ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਲਈ ਪਾਸਵਰਡ ਦਿਓ"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ਅੱਗੇ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index c813cad681b4..cd7eb7d1823c 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Użyj sprawdzania HDCP tylko w przypadku treści chronionych DRM"</item>
<item msgid="45075631231212732">"Zawsze używaj sprawdzania HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="5618929009984956469">"16 bitów/próbkę"</item>
+ <item msgid="3412640499234627248">"24 bity/próbkę"</item>
+ <item msgid="121583001492929387">"32 bity/próbkę"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="4726688794884191540">"16 bitów/próbkę"</item>
+ <item msgid="305344756485516870">"24 bity/próbkę"</item>
+ <item msgid="244568657919675099">"32 bity/próbkę"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Użyj wyboru systemu (domyślnie)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optymalizacja pod kątem jakości dźwięku (990 kb/s lub 909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Zrównoważona jakość dźwięku i połączenia (660 kb/s lub 606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optymalizacja pod kątem jakości połączenia (330 kb/s lub 303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optymalizacja pod kątem jakości dźwięku"</item>
+ <item msgid="4327143584633311908">"Zrównoważona jakość dźwięku i połączenia"</item>
+ <item msgid="4681409244565426925">"Optymalizacja pod kątem jakości połączenia"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Wył."</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 20cb365ab707..fcf974c38d16 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dane komórkowe zawsze aktywne"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Wyłącz głośność bezwzględną"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek dźwięku Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Wybierz kodek dźwięku Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Dźwięk Bluetooth – współczynnik próbkowania"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Wybierz kodek dźwięku Bluetooth:\nwspółczynnik próbkowania"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Dźwięk Bluetooth – liczba bitów na próbkę"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Wybierz kodek dźwięku Bluetooth:\nliczba bitów na próbkę"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Dźwięk Bluetooth – tryb kanału"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Wybierz kodek dźwięku Bluetooth:\ntryb kanału"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek dźwięku Bluetooth LDAC: jakość odtwarzania"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Wybierz kodek dźwięku Bluetooth LDAC:\njakość odtwarzania"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Strumieniowe przesyłanie danych: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Po włączeniu połączenie danych będzie bardziej agresywnie przełączać się z Wi-Fi na sieć komórkową przy słabym sygnale Wi-Fi"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Wpisz hasło, by przywrócić ustawienia fabryczne w trybie demonstracyjnym"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalej"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Wymagane hasło"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 29e3f415c136..8a2fdc655062 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Usar a verificação HDCP somente para conteúdo DRM"</item>
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="5618929009984956469">"16 bits/amostra"</item>
+ <item msgid="3412640499234627248">"24 bits/amostra"</item>
+ <item msgid="121583001492929387">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4726688794884191540">"16 bits/amostra"</item>
+ <item msgid="305344756485516870">"24 bits/amostra"</item>
+ <item msgid="244568657919675099">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Otimizado para qualidade de áudio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Qualidade de áudio e de conexão balanceada (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Otimizado para qualidade de conexão (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Otimizado para qualidade de áudio"</item>
+ <item msgid="4327143584633311908">"Qualidade de áudio e de conexão balanceada"</item>
+ <item msgid="4681409244565426925">"Otimizado para qualidade de conexão"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desativado"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 5ad3cd9ec20c..dcbac244b285 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selecionar codec de áudio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostra do áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selecionar codec de áudio Bluetooth:\ntaxa de amostragem"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra do áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selecionar codec de áudio Bluetooth:\nbits por amostra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selecionar codec de áudio Bluetooth:\nmodo de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec de áudio Bluetooth LDAC: qualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec de áudio Bluetooth LDAC:\nqualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Digite a senha para redef. p/ configuração original em modo demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Senha necessária"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index cf4d1c847786..1b10a3f8f479 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utilizar a verificação HDCP para conteúdo DRM apenas"</item>
<item msgid="45075631231212732">"Utilizar sempre a verificação HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="5618929009984956469">"16 bits/amostra"</item>
+ <item msgid="3412640499234627248">"24 bits/amostra"</item>
+ <item msgid="121583001492929387">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="4726688794884191540">"16 bits/amostra"</item>
+ <item msgid="305344756485516870">"24 bits/amostra"</item>
+ <item msgid="244568657919675099">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Utilizar seleção do sistema (predef.)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Otimizado para a qualidade do áudio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Qualidade de áudio e de ligação equilibrada (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Otimizado para a qualidade da ligação (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Otimizado para a qualidade do áudio"</item>
+ <item msgid="4327143584633311908">"Qualidade de áudio e de ligação equilibradas"</item>
+ <item msgid="4681409244565426925">"Otimizado para a qualidade da ligação"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desativado"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index f8ceac2b6255..fb2bd6e2f178 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados móveis sempre ativados"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selecionar codec de áudio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostragem de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selecionar codec de áudio Bluetooth:\nTaxa de amostragem"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selecionar codec de áudio Bluetooth:\nBits por amostra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selecionar codec de áudio de Bluetooth:\nModo de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC de áudio Bluetooth: qualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec LDAC de áudio Bluetooth:\nQualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmissão em fluxo contínuo: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Se estiver ativado, o Wi-Fi será mais agressivo ao transmitir a lig. de dados p/ a rede móvel quando o sinal Wi-Fi estiver fraco"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Introduzir palavra-passe para efetuar a reposição de fábrica no modo demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Próximo"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Palavra-passe obrigatória"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 29e3f415c136..8a2fdc655062 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Usar a verificação HDCP somente para conteúdo DRM"</item>
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="5618929009984956469">"16 bits/amostra"</item>
+ <item msgid="3412640499234627248">"24 bits/amostra"</item>
+ <item msgid="121583001492929387">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4726688794884191540">"16 bits/amostra"</item>
+ <item msgid="305344756485516870">"24 bits/amostra"</item>
+ <item msgid="244568657919675099">"32 bits/amostra"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Usar seleção do sistema (padrão)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Estéreo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Otimizado para qualidade de áudio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Qualidade de áudio e de conexão balanceada (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Otimizado para qualidade de conexão (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Otimizado para qualidade de áudio"</item>
+ <item msgid="4327143584633311908">"Qualidade de áudio e de conexão balanceada"</item>
+ <item msgid="4681409244565426925">"Otimizado para qualidade de conexão"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Desativado"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 5ad3cd9ec20c..dcbac244b285 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selecionar codec de áudio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostra do áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selecionar codec de áudio Bluetooth:\ntaxa de amostragem"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra do áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selecionar codec de áudio Bluetooth:\nbits por amostra"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de áudio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selecionar codec de áudio Bluetooth:\nmodo de canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec de áudio Bluetooth LDAC: qualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecionar codec de áudio Bluetooth LDAC:\nqualidade de reprodução"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Digite a senha para redef. p/ configuração original em modo demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Senha necessária"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index dc030656bcd6..2f4d0c74ea75 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Utilizează verificarea HDCP numai pentru conținut DRM"</item>
<item msgid="45075631231212732">"Utilizează întotdeauna verificarea HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="5618929009984956469">"16 biți/eșantion"</item>
+ <item msgid="3412640499234627248">"24 biți/eșantion"</item>
+ <item msgid="121583001492929387">"32 biți/eșantion"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="4726688794884191540">"16 biți/eșantion"</item>
+ <item msgid="305344756485516870">"24 biți/eșantion"</item>
+ <item msgid="244568657919675099">"32 biți/eșantion"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizat pentru calitatea audio (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Calitatea audio și a conexiunii echilibrată (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizat pentru calitatea conexiunii (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizat pentru calitatea audio"</item>
+ <item msgid="4327143584633311908">"Calitatea audio și a conexiunii echilibrată"</item>
+ <item msgid="4681409244565426925">"Optimizat pentru calitatea conexiunii"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Dezactivată"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 87149264a83d..372833d58f6a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Conexiunea de date mobile este întotdeauna activată"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Dezactivați volumul absolut"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Selectați codecul audio Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Rată de eșantionare audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Selectați codecul audio Bluetooth:\nrată de eșantionare"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Biți audio Bluetooth per eșantion"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Selectați codecul audio Bluetooth:\nbiți per eșantion"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modul canal audio Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Selectați codecul audio Bluetooth:\nmodul canal"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codecul LDAC audio pentru Bluetooth: calitatea redării"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selectați codecul LDAC audio pentru Bluetooth:\ncalitatea redării"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmitere în flux: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Când este activată, funcția Wi-Fi va fi mai agresivă la predarea conexiunii de date către mobil când semnalul Wi-Fi este slab"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Introduceți parola pentru a reveni la setările din fabrică în modul demo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Înainte"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Trebuie să introduceți o parolă"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index bf192a5b87a9..6498ea0ed8a1 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Использовать проверку HDCP только для DRM-контента"</item>
<item msgid="45075631231212732">"Всегда использовать проверку HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Выбор системы (по умолчанию)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Выбор системы (по умолчанию)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Выбор системы (по умолчанию)"</item>
+ <item msgid="8895532488906185219">"44,1 кГц"</item>
+ <item msgid="2909915718994807056">"48 кГц"</item>
+ <item msgid="3347287377354164611">"88,2 кГц"</item>
+ <item msgid="1234212100239985373">"96 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Выбор системы (по умолчанию)"</item>
+ <item msgid="4482862757811638365">"44,1 кГц"</item>
+ <item msgid="354495328188724404">"48 кГц"</item>
+ <item msgid="7329816882213695083">"88,2 кГц"</item>
+ <item msgid="6967397666254430476">"96 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Выбор системы (по умолчанию)"</item>
+ <item msgid="5618929009984956469">"16 бит/отсчет"</item>
+ <item msgid="3412640499234627248">"24 бит/отсчет"</item>
+ <item msgid="121583001492929387">"32 бит/отсчет"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Выбор системы (по умолчанию)"</item>
+ <item msgid="4726688794884191540">"16 бит/отсчет"</item>
+ <item msgid="305344756485516870">"24 бит/отсчет"</item>
+ <item msgid="244568657919675099">"32 бит/отсчет"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Выбор системы (по умолчанию)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Выбор системы (по умолчанию)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Оптимизировать качество звука (990/909 Кбит/с)"</item>
+ <item msgid="2921767058740704969">"Баланс качества звука и скорости подключения (660/606 кбит/с)"</item>
+ <item msgid="8860982705384396512">"Оптимизировать скорость подключения (330/303 Кбит/с)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Оптимизировать качество звука"</item>
+ <item msgid="4327143584633311908">"Баланс качества звука и скорости подключения"</item>
+ <item msgid="4681409244565426925">"Оптимизировать скорость подключения"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Выкл."</item>
<item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9da906bd3149..97aea3041318 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не отключать передачу данных"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Отключить абсолютный уровень громкости"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек для передачи через Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Аудиокодек для Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частота дискретизации при передаче через Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Аудиокодек для Bluetooth:\nчастота дискретизации"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Глубина кодирования звука при передаче через Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Аудиокодек для Bluetooth:\nразрядность"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим аудиоканала Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Аудиокодек для Bluetooth:\nрежим канала"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Аудиокодек LDAC для Bluetooth: качество воспроизведения"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Аудиокодек LDAC для Bluetooth:\nкачество воспроизведения"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Потоковая передача: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"При выборе Wi‑Fi указывать в журнале RSSI для каждого SSID"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Принудительно переключаться на мобильную сеть, если сигнал Wi-Fi слабый"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Чтобы сбросить настройки в деморежиме, введите пароль."</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Далее"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Требуется пароль"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index c9a5d1203b26..4af877dee790 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM අන්තර්ගත සඳහා පමණක් HDCP පරික්ෂාව භාවිතා කරන්න"</item>
<item msgid="45075631231212732">"සැමවිටම HDCP පිරික්සුම භාවිතා කරන්න"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="5618929009984956469">"බිටු 16/නියැදිය"</item>
+ <item msgid="3412640499234627248">"බිටු 24/නියැදිය"</item>
+ <item msgid="121583001492929387">"බිටු 32/නියැදිය"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="4726688794884191540">"බිටු 16/නියැදිය"</item>
+ <item msgid="305344756485516870">"බිටු 24/නියැදිය"</item>
+ <item msgid="244568657919675099">"බිටු 32/නියැදිය"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="4106832974775067314">"ඒකල"</item>
+ <item msgid="5571632958424639155">"ස්ටීරියෝ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="8900559293912978337">"ඒකල"</item>
+ <item msgid="8883739882299884241">"ස්ටීරියෝ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ශ්‍රව්‍ය ගුණත්වය සඳහා ප්‍රශස්ත කරන ලදී (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"සමබර ශ්‍රව්‍ය සහ සබැඳුම් ගුණත්වය (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"සබැඳුම් ගුණත්වය සඳහා ප්‍රශස්ත කරන ලදී (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ශ්‍රව්‍ය ගුණත්වය සඳහා ප්‍රශස්ත කරන ලදී"</item>
+ <item msgid="4327143584633311908">"සමබර ශ්‍රව්‍ය සහ සබැඳුම් ගුණත්වය"</item>
+ <item msgid="4681409244565426925">"සබැඳුම් ගුණත්වය සඳහා ප්‍රශස්ත කරන ලදී"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ක්‍රියාවිරහිතය"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1ff81e6d3fa0..b53a46f31f89 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"සෙලියුලර් දත්ත සැමවිට ක්‍රියාකාරීය"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"බ්ලූටූත් ශ්‍රව්‍ය Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"බ්ලූටූත් ශ්‍රව්‍ය කොඩෙක් තෝරන්න"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"බ්ලූටූත් ශ්‍රව්‍ය නියැදි අනුපාතය"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"බ්ලූටූත් ශ්‍රව්‍ය කොඩෙක් තෝරන්න:\nනියැදි අනුපාතය"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"නියැදියකට බ්ලූටූත් ශ්‍රව්‍ය බිටු"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"බ්ලූටූත් ශ්‍රව්‍ය කොඩෙක් තෝරන්න:\nනියැදියකට බිටු"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"බ්ලූටූත් ශ්‍රව්‍ය නාලිකා ප්‍රකාරය"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"බ්ලූටූත් ශ්‍රව්‍ය කොඩෙක් තෝරන්න:\nනාලිකා ප්‍රකාරය"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"බ්ලූටූත් ශ්‍රව්‍ය LDAC පසුධාවන ගුණත්වය"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"බ්ලූටූත් ශ්‍රව්‍ය LDAC කොඩෙක් තෝරන්න:\nපසුධාවන ගුණත්වය"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ප්‍රවාහ කරමින්: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"සබල විට Wi‑Fi සිග්නලය අඩු විට Wi‑Fi දත්ත සම්බන්ධතාවය සෙලියුලර් වෙත භාර දීමට වඩා ආක්‍රමණික වේ"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්‍රතිපෝෂණ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ආදර්ශන ප්‍රකාර කර්මාන්තශාලා යළි සැකසීමට මුරපදය ඇ. ක."</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ඊළඟ"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"මුරපදය අවශ්‍යයි"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 3dd56cbf0982..c0cc99e82484 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Použiť kontrolu HDCP len pre obsah DRM"</item>
<item msgid="45075631231212732">"Vždy používať kontrolu HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="5618929009984956469">"16 bitov na vzorku"</item>
+ <item msgid="3412640499234627248">"24 bitov na vzorku"</item>
+ <item msgid="121583001492929387">"32 bitov na vzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="4726688794884191540">"16 bitov na vzorku"</item>
+ <item msgid="305344756485516870">"24 bitov na vzorku"</item>
+ <item msgid="244568657919675099">"32 bitov na vzorku"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Použiť voľbu systému (predvolené)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimalizovaná kvalita zvuku (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Vyrovnaná kvalita zvuku a pripojenia (660/606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimalizovaná kvalita pripojenia (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimalizovaná kvalita zvuku"</item>
+ <item msgid="4327143584633311908">"Vyrovnaná kvalita zvuku a pripojenia"</item>
+ <item msgid="4681409244565426925">"Optimalizovaná kvalita pripojenia"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Vypnuté"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index dfdc8f160822..ce1315a59b25 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilné dáta vždy aktívne"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázať absolútnu hlasitosť"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Vybrať kodek Bluetooth Audio"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio – vzorkovacia frekvencia"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Vybrať kodek Bluetooth Audio:\nVzorkovacia frekvencia"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio – počet bitov na vzorku"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Vybrať kodek Bluetooth Audio:\nPočet bitov na vzorku"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio – režim kanála"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Vybrať kodek Bluetooth Audio:\nRežim kanála"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodek LDAC Bluetooth Audio: Kvalita prehrávania"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Vybrať kodek LDAC Bluetooth Audio:\nKvalita prehrávania"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streamovanie: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Zadajte heslo na obnovenie továrenských nastavení v režime ukážky"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Ďalej"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Vyžaduje sa heslo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index d7173085954e..5560936b34ec 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Preverjanje HDCP uporabi samo za vsebino DRM"</item>
<item msgid="45075631231212732">"Vedno uporabi preverjanje HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="5618929009984956469">"16 bitov/vzorec"</item>
+ <item msgid="3412640499234627248">"24 bitov/vzorec"</item>
+ <item msgid="121583001492929387">"32 bitov/vzorec"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="4726688794884191540">"16 bitov/vzorec"</item>
+ <item msgid="305344756485516870">"24 bitov/vzorec"</item>
+ <item msgid="244568657919675099">"32 bitov/vzorec"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizirano za kakovost zvoka (990/909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Uravnotežena kakovost zvoka in povezave (660/606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Optimizirano za kakovost povezave (330/303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizirano za kakovost zvoka"</item>
+ <item msgid="4327143584633311908">"Uravnotežena kakovost zvoka in povezave"</item>
+ <item msgid="4681409244565426925">"Optimizirano za kakovost povezave"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Izklopljeno"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index af564f8ebe09..ca9eb95f58a6 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Prenos podatkov v mobilnih omrežjih je vedno aktiven"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutnega praga glasnosti"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Zvočni kodek za Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Izberi zvočni kodek za Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Hitrost vzorčenja zvoka prek Bluetootha"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Izberi zvočni kodek za Bluetooth:\nHitrost vzorčenja"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Število bitov na vzorec za zvok prek Bluetootha"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Izberi zvočni kodek za Bluetooth:\nBitov na vzorec"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način zvočnega kanala prek Bluetootha"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Izberi zvočni kodek za Bluetooth:\nNačin kanala"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Zvočni kodek LDAC za Bluetooth: kakovost predvajanja"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Izberi zvočni kodek LDAC za Bluetooth:\nKakovost predvajanja"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Pretočno predvajanje: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Če je ta možnost omogočena, Wi-Fi odločneje preda podatkovno povezavo mobilnemu omrežju, ko je signal Wi-Fi šibek"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Geslo za tovar. nast. v predstav. načinu"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Naprej"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Vnesite geslo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index b91f69437653..0f8269af4e28 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Përdor kontrollin e HDCP-së vetëm për përmbajtjet DRM"</item>
<item msgid="45075631231212732">"Përdor gjithmonë kontrollin e HDCP-së"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="5618929009984956469">"16 bite/shembull"</item>
+ <item msgid="3412640499234627248">"24 bite/shembull"</item>
+ <item msgid="121583001492929387">"32 bite/shembull"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="4726688794884191540">"16 bite/shembull"</item>
+ <item msgid="305344756485516870">"24 bite/shembull"</item>
+ <item msgid="244568657919675099">"32 bite/shembull"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimizuar për cilësi audioje (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"Cilësi e balancuar e audios dhe e lidhjes (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"Optimizuar për cilësi lidhjeje (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimizuar për cilësi audioje"</item>
+ <item msgid="4327143584633311908">"Cilësi e balancuar e audios dhe e lidhjes"</item>
+ <item msgid="4681409244565426925">"Optimizuar për cilësi lidhjeje"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Joaktiv"</item>
<item msgid="1593289376502312923">"64 mijë"</item>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 1017cfc5cf2c..716385245503 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Të dhënat celulare gjithmonë aktive"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Çaktivizo volumin absolut"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeku Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Zgjidh kodekun e audios së Bluetooth-it"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Shpejtësia e shembullit të Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Zgjidh kodekun e audios së Bluetooth-it:\nShpejtësia e shembullit"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bite për shembull Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Zgjidh kodekun e audios së Bluetooth-it:\nBite për shembull"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Regjimi i kanalit Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Zgjidh kodekun e audios së Bluetooth-it:\nModaliteti i kanalit"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodeku LDAC i audios së Bluetooth-it: Cilësia e luajtjes"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Zgjidh kodekun LDAC të audios së Bluetooth-it:\nCilësia e luajtjes"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmetimi: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kur ky funksion aktivizohet, Wi‑Fi bëhet më agresiv në kalimin e lidhjes së të dhënave te rrjeti celular, në rastet kur sinjali Wi‑Fi është i dobët"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Fut fjalëkalimin për të kryer rivendosje në gjendje fabrike në modalitetin e demonstrimit"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Përpara"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Kërkohet fjalëkalimi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index e76714549c06..912d20b9406c 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Користи HDCP проверу само за DRM садржај"</item>
<item msgid="45075631231212732">"Увек користи HDCP проверу"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Користи избор система (подразумевано)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Користи избор система (подразумевано)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Користи избор система (подразумевано)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Користи избор система (подразумевано)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Користи избор система (подразумевано)"</item>
+ <item msgid="5618929009984956469">"16 битова по узорку"</item>
+ <item msgid="3412640499234627248">"24 бита по узорку"</item>
+ <item msgid="121583001492929387">"32 бита по узорку"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Користи избор система (подразумевано)"</item>
+ <item msgid="4726688794884191540">"16 битова по узорку"</item>
+ <item msgid="305344756485516870">"24 бита по узорку"</item>
+ <item msgid="244568657919675099">"32 бита по узорку"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Користи избор система (подразумевано)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Користи избор система (подразумевано)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Оптимизовано за квалитет звука (990 kb/s/909 kb/s)"</item>
+ <item msgid="2921767058740704969">"Уједначен квалитет звука и везе (660 kb/s/606 kb/s)"</item>
+ <item msgid="8860982705384396512">"Оптимизовано за квалитет везе (330 kb/s/303 kb/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Оптимизовано за квалитет звука"</item>
+ <item msgid="4327143584633311908">"Уједначен квалитет звука и везе"</item>
+ <item msgid="4681409244565426925">"Оптимизовано за квалитет везе"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Искључено"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index f6de46bc22d5..7ea3bf3ec255 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Подаци за мобилне уређаје су увек активни"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Онемогући главно подешавање јачине звука"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Изаберите Bluetooth аудио кодек"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Брзина узорковања за Bluetooth аудио"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Изаберите Bluetooth аудио кодек:\nбрзина узорковања"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Битова по узорку за Bluetooth аудио"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Изаберите Bluetooth аудио кодек:\nбитова по узорку"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим канала за Bluetooth аудио"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Изаберите Bluetooth аудио кодек:\nрежим канала"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth аудио кодек LDAC: квалитет репродукције"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Изаберите Bluetooth аудио кодек LDAC:\nквалитет репродукције"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Стримовање: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Када се омогући, Wi‑Fi ће бити агресивнији при пребацивању мреже за пренос података на Мобилну, када је Wi‑Fi сигнал слаб"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Унесите лозинку да бисте обавили ресетовање на фабричка подешавања у режиму демонстрације"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Даље"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Потребна је лозинка"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index fe395acbc6cf..26496aae9b4c 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Använd bara HDCP-kontroll för DRM-innehåll"</item>
<item msgid="45075631231212732">"Använd alltid HDCP-kontroll"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Använd systemval (standardinställning)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Använd systemval (standardinställning)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Använd systemval (standardinställning)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Använd systemval (standardinställning)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Använd systemval (standardinställning)"</item>
+ <item msgid="5618929009984956469">"16 bitar/sampling"</item>
+ <item msgid="3412640499234627248">"24 bitar/sampling"</item>
+ <item msgid="121583001492929387">"32 bitar/sampling"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Använd systemval (standardinställning)"</item>
+ <item msgid="4726688794884191540">"16 bitar/sampling"</item>
+ <item msgid="305344756485516870">"24 bitar/sampling"</item>
+ <item msgid="244568657919675099">"32 bitar/sampling"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Använd systemval (standardinställning)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Använd systemval (standardinställning)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Optimerad för ljudkvalitet (990 kbit/s eller 909 kbit/s)"</item>
+ <item msgid="2921767058740704969">"Balanserad ljud- och anslutningskvalitet (660 kbit/s/606 kbit/s)"</item>
+ <item msgid="8860982705384396512">"Optimerad för anslutningskvalitet (330 kbit/s eller 303 kbit/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Optimerad för ljudkvalitet"</item>
+ <item msgid="4327143584633311908">"Balanserad ljud- och anslutningskvalitet"</item>
+ <item msgid="4681409244565426925">"Optimerad för anslutningskvalitet"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Av"</item>
<item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index d68580ba78c4..c8d3127846ab 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata alltid aktiverad"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inaktivera Absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Ljudkodek för Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Välj Ljudkodek för Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Samplingsfrekvens för Bluetooth-ljud"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Välj Ljudkodek för Bluetooth:\nsamplingsfrekvens"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Antar bitar per sampling för Bluetooth-ljud"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Välj Ljudkodek för Bluetooth:\nbitar per sampling"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanalläge för Bluetooth-ljud"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Välj Ljudkodek för Bluetooth:\nkanalläge"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-ljud via LDAC-kodek: uppspelningskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Välj Bluetooth-ljud via LDAC-kodek:\nuppspelningskvalitet"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"När funktionen har aktiverats kommer dataanslutningen lämnas över från Wi-Fi till mobilen på ett aggressivare sätt när Wi-Fi-signalen är svag"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Ange lösenord och utför fabriksåterställning i demoläge"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Nästa"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Lösenord krävs"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index a7c4b63e88dd..92dbaeb1731f 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Tumia ukaguaji wa HDCP kwa maudhui ya DRM pekee"</item>
<item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="8895532488906185219">"kHz 44.1"</item>
+ <item msgid="2909915718994807056">"kHz 48.0"</item>
+ <item msgid="3347287377354164611">"kHz 88.2"</item>
+ <item msgid="1234212100239985373">"kHz 96.0"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="4482862757811638365">"kHz 44.1"</item>
+ <item msgid="354495328188724404">"kHz 48.0"</item>
+ <item msgid="7329816882213695083">"kHz 88.2"</item>
+ <item msgid="6967397666254430476">"kHz 96.0"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="5618929009984956469">"Biti 16 kwa kila sampuli"</item>
+ <item msgid="3412640499234627248">"Biti 24 kwa kila sampuli"</item>
+ <item msgid="121583001492929387">"Biti 32 kwa kila sampuli"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="4726688794884191540">"Biti 16 kwa kila sampuli"</item>
+ <item msgid="305344756485516870">"Biti 24 kwa kila sampuli"</item>
+ <item msgid="244568657919675099">"Biti 32 kwa kila sampuli"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Imeimarishwa kwa ajili ya Ubora wa Sauti (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Ubora wa Muunganisho na Sauti Umesawazishwa (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Imeimarishwa kwa ajili ya Ubora wa Muunganisho (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Imeimarishwa kwa ajili ya Ubora wa Sauti"</item>
+ <item msgid="4327143584633311908">"Ubora wa Muunganisho na Sauti Umesawazishwa"</item>
+ <item msgid="4681409244565426925">"Imeimarishwa kwa ajili ya Ubora wa Muunganisho"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Imezimwa"</item>
<item msgid="1593289376502312923">"K64"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1b2f876b23a0..9296e81a4216 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Data ya kifaa cha mkononi inatumika kila wakati"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zima sauti kamili"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeki ya Sauti ya Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Chagua Kodeki ya Sauti ya Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Kiwango cha Sampuli ya Sauti ya Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Chagua Kodeki ya Sauti ya Bluetooth:\nKiwango cha Sampuli"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Biti za Sauti ya Bluetooth kwa Kila Sampuli"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Chagua Kodeki ya Sauti ya Bluetooth:\nBiti kwa Kila Sampuli"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hali ya Mkondo wa Sauti ya Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Chagua Kodeki ya Sauti ya Bluetooth:\nHali ya Kituo"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodeki ya LDAC ya Sauti ya Bluetooth: Ubora wa Kucheza"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Chagua Kodeki ya LDAC ya Sauti ya Bluetooth:\nUbora wa Kucheza"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Kutiririsha: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ikiwashwa, Wifi itakabidhi kwa hima muunganisho wa data kwa mtandao wa Simu za Mkononi, mawimbi ya Wifi yanapokuwa hafifu"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Weka nenosiri ili urejeshe mipangilio ya kiwandani ikiwa katika hali ya onyesho."</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Inayofuata"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Nenosiri linahitajika"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index efbe16d25b72..cefb5de5b58d 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM உள்ளடக்கத்திற்கு மட்டும் HDCP சோதனையைப் பயன்படுத்து"</item>
<item msgid="45075631231212732">"HDCP சரிபார்ப்பை எப்போதும் பயன்படுத்து"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="5618929009984956469">"16 பிட்கள்/சாம்பிள்"</item>
+ <item msgid="3412640499234627248">"24 பிட்கள்/சாம்பிள்"</item>
+ <item msgid="121583001492929387">"32 பிட்கள்/சாம்பிள்"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="4726688794884191540">"16 பிட்கள்/சாம்பிள்"</item>
+ <item msgid="305344756485516870">"24 பிட்கள்/சாம்பிள்"</item>
+ <item msgid="244568657919675099">"32 பிட்கள்/சாம்பிள்"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="4106832974775067314">"மோனோ"</item>
+ <item msgid="5571632958424639155">"ஸ்டீரியோ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+ <item msgid="8900559293912978337">"மோனோ"</item>
+ <item msgid="8883739882299884241">"ஸ்டீரியோ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ஆடியோ தரத்திற்காக மேம்படுத்தியது (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"சமன்படுத்தப்பட்ட ஆடியோ மற்றும் இணைப்புத் தரம் (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"இணைப்புத் தரத்திற்காக மேம்படுத்தியது (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ஆடியோ தரத்திற்காக மேம்படுத்தியது"</item>
+ <item msgid="4327143584633311908">"சமன்படுத்தப்பட்ட ஆடியோ மற்றும் இணைப்புத் தரம்"</item>
+ <item msgid="4681409244565426925">"இணைப்புத் தரத்திற்காக மேம்படுத்தியது"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"முடக்கு"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index a94dd3a794b1..7768dfd8eb30 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"செல்லுலார் தரவு எப்போதும் இயக்கத்தில்"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"புளூடூத் ஆடியோ கோடெக்"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"புளூடூத் ஆடியோ கோடெக்கைத் தேர்ந்தெடுக்கவும்"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"புளூடூத் ஆடியோ சாம்பிள் ரேட்"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"புளூடூத் ஆடியோ கோடெக்கைத் தேர்ந்தெடுக்கவும்:\nசாம்பிள் ரேட்"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"புளூடூத் ஆடியோ பிட்கள்/சாம்பிள்"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"புளூடூத் ஆடியோ கோடெக்கைத் தேர்ந்தெடுக்கவும்:\nபிட்கள்/சாம்பிள்"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"புளூடூத் ஆடியோ சேனல் பயன்முறை"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"புளூடூத் ஆடியோ கோடெக்கைத் தேர்ந்தெடுக்கவும்:\nசேனல் பயன்முறை"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"புளூடூத் ஆடியோ LDAC கோடெக்: வீடியோவின் தரம்"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"புளூடூத் ஆடியோ LDAC கோடெக்கைத் தேர்ந்தெடுக்கவும்:\nவீடியோவின் தரம்"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ஸ்ட்ரீமிங்: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wifi நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"இயக்கப்பட்டதும், வைஃபை சிக்னல் குறையும் போது, வைஃபை முழுமையாக ஒத்துழைக்காமல் இருப்பதால் செல்லுலாரின் தரவு இணைப்புக்கு மாறும்"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"டெமோ பயன்முறையில் ஆரம்பநிலை மீட்டமைவைச் செயல்படுத்த, கடவுச்சொல்லை உள்ளிடவும்"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"அடுத்து"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"கடவுச்சொல் தேவை"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index bee64026a88a..dd9810b1d291 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"DRM కంటెంట్‌కు మాత్రమే HDCP తనిఖీని ఉపయోగించండి"</item>
<item msgid="45075631231212732">"ఎప్పటికీ HDCP తనిఖీని ఉపయోగించు"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="5618929009984956469">"16 బిట్‌లు/నమూనా"</item>
+ <item msgid="3412640499234627248">"24 బిట్‌లు/నమూనా"</item>
+ <item msgid="121583001492929387">"32 బిట్‌లు/నమూనా"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="4726688794884191540">"16 బిట్‌లు/నమూనా"</item>
+ <item msgid="305344756485516870">"24 బిట్‌లు/నమూనా"</item>
+ <item msgid="244568657919675099">"32 బిట్‌లు/నమూనా"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="4106832974775067314">"మోనో"</item>
+ <item msgid="5571632958424639155">"స్టీరియో"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="8900559293912978337">"మోనో"</item>
+ <item msgid="8883739882299884241">"స్టీరియో"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"ఆడియో నాణ్యత (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="2921767058740704969">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"కనెక్షన్ నాణ్యత (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"ఆడియో నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="4327143584633311908">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత"</item>
+ <item msgid="4681409244565426925">"కనెక్షన్ నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ఆఫ్"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index d96e412ec1c9..8379dd8d8753 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"ఎల్లప్పుడూ సెల్యులార్ డేటాను సక్రియంగా ఉంచు"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"బ్లూటూత్ ఆడియో కోడెక్"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"బ్లూటూత్ ఆడియో కోడెక్‌ని ఎంచుకోండి"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"బ్లూటూత్ ఆడియో నమూనా రేట్"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"బ్లూటూత్ ఆడియో కోడెక్‌ని ఎంచుకోండి:\nనమూనా రేటు"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ఒక్కో నమూనాకు బ్లూటూత్ ఆడియో బిట్‌లు"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"బ్లూటూత్ ఆడియో కోడెక్‌ని ఎంచుకోండి:\nఒక్కో నమూనాలో బిట్‌లు"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"బ్లూటూత్ ఆడియో కోడెక్‌ని ఎంచుకోండి:\nఛానెల్ మోడ్"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ నాణ్యత"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"బ్లూటూత్ ఆడియో LDAC కోడెక్‌ని ఎంచుకోండి:\nప్లేబ్యాక్ నాణ్యత"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ప్రసారం చేస్తోంది: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"వైర్‌లెస్ ప్రదర్శన ప్రమాణపత్రం కోసం ఎంపికలను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ప్రారంభించబడినప్పుడు, Wi‑Fi సిగ్నల్ బలహీనంగా ఉంటే డేటా కనెక్షన్‌ను సెల్యులార్‌కి మార్చేలా Wi‑Fiపై మరింత తీవ్ర ఒత్తిడి కలుగుతుంది"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"డెమో మోడ్‌లో ఫ్యాక్టరీ రీసెట్‌ను నిర్వహించడానికి పాస్‌వర్డ్‌ను నమోదు చేయండి"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"తదుపరి"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"పాస్‌వర్డ్ అవసరం"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 690ce0cb12ae..c1178d2c6a93 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"ใช้การตรวจสอบ HDCP สำหรับเนื้อหา DRM เท่านั้น"</item>
<item msgid="45075631231212732">"ใช้การตรวจสอบ HDCP เสมอ"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="5618929009984956469">"16 บิต/ตัวอย่าง"</item>
+ <item msgid="3412640499234627248">"24 บิต/ตัวอย่าง"</item>
+ <item msgid="121583001492929387">"32 บิต/ตัวอย่าง"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="4726688794884191540">"16 บิต/ตัวอย่าง"</item>
+ <item msgid="305344756485516870">"24 บิต/ตัวอย่าง"</item>
+ <item msgid="244568657919675099">"32 บิต/ตัวอย่าง"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="4106832974775067314">"โมโน"</item>
+ <item msgid="5571632958424639155">"สเตอริโอ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"ใช้การเลือกระบบ (ค่าเริ่มต้น)"</item>
+ <item msgid="8900559293912978337">"โมโน"</item>
+ <item msgid="8883739882299884241">"สเตอริโอ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"เพิ่มประสิทธิภาพสำหรับคุณภาพเสียง (990 kbps/909 kbps)"</item>
+ <item msgid="2921767058740704969">"คุณภาพเสียงและการเชื่อมต่อที่สมดุล (660 kbps/606 kbps)"</item>
+ <item msgid="8860982705384396512">"เพิ่มประสิทธิภาพสำหรับคุณภาพการเชื่อมต่อ (330 kbps/303 kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"เพิ่มประสิทธิภาพสำหรับคุณภาพเสียง"</item>
+ <item msgid="4327143584633311908">"คุณภาพเสียงและการเชื่อมต่อที่สมดุล"</item>
+ <item msgid="4681409244565426925">"เพิ่มประสิทธิภาพสำหรับคุณภาพการเชื่อมต่อ"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"ปิด"</item>
<item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 3d8af856568b..8f9bd86238f6 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"เปิดใช้ข้อมูลมือถือเสมอ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ตัวแปลงรหัสเสียงบลูทูธ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"เลือกตัวแปลงรหัสเสียงบลูทูธ"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"อัตราตัวอย่างเสียงบลูทูธ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"เลือกตัวแปลงรหัสเสียงบลูทูธ:\nอัตราการสุ่มตัวอย่าง"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"บิตต่อตัวอย่างของเสียงบลูทูธ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"เลือกตัวแปลงรหัสเสียงบลูทูธ:\nบิตต่อตัวอย่าง"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"โหมดช่องสัญญาณเสียงบลูทูธ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"เลือกตัวแปลงรหัสเสียงบลูทูธ:\nโหมดช่องสัญญาณ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ตัวแปลงรหัสเสียงบลูทูธที่ใช้ LDAC: คุณภาพการเล่น"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"เลือกตัวแปลงรหัสเสียงบลูทูธที่ใช้ LDAC:\nคุณภาพการเล่น"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"สตรีมมิง: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"เมื่อเปิดใช้แล้ว Wi-Fi จะส่งผ่านการเชื่อมต่อข้อมูลไปยังเครือข่ายมือถือในทันทีที่พบสัญญาณ Wi-Fi อ่อน"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ป้อนรหัสผ่านเพื่อรีเซ็ตค่าในโหมดสาธิต"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"ถัดไป"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"ต้องป้อนรหัสผ่าน"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index c67be8afc4cb..a5a8219ec088 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Gamitin lang ang pagsusuring HDCP para sa nilalamang DRM"</item>
<item msgid="45075631231212732">"Palaging gumamit ng pagsusuring HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="5618929009984956469">"16 bits/sample"</item>
+ <item msgid="3412640499234627248">"24 bits/sample"</item>
+ <item msgid="121583001492929387">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="4726688794884191540">"16 bits/sample"</item>
+ <item msgid="305344756485516870">"24 bits/sample"</item>
+ <item msgid="244568657919675099">"32 bits/sample"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Gamitin ang Pagpili ng System (Default)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Naka-optimize para sa Kalidad ng Audio (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Balanse ang Kalidad ng Audio at Koneksyon (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Naka-optimize para sa Kalidad ng Koneksyon (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Naka-optimize para sa Kalidad ng Audio"</item>
+ <item msgid="4327143584633311908">"Balanse ang Kalidad ng Audio at Koneksyon"</item>
+ <item msgid="4681409244565426925">"Naka-optimize para sa Kalidad ng Koneksyon"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"I-off"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a7ccc2a341ec..47fdae2574ab 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Palaging aktibo ang cellular data"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"I-disable ang absolute volume"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Piliin ang Audio Codec ng Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Sample na Rate ng Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Piliin ang Audio Codec ng Bluetooth:\nRate ng Sample"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits Per Sample ng Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Piliin ang Audio Codec ng Bluetooth:\nBit Kada Sample"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Channel Mode ng Bluetooth Audio"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Piliin ang Audio Codec ng Bluetooth:\nChannel Mode"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Audio LDAC Codec ng Bluetooth: Kalidad ng Pag-playback"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Piliin ang Audio LDAC Codec ng Bluetooth:\nKalidad ng Pag-playback"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kapag naka-enable, mas magiging agresibo ang Wi‑Fi sa paglipat ng koneksyon ng data sa Cellular, kapag mahina ang signal ng Wi‑Fi"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Ilagay ang password upang mag-factory reset sa demo mode"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Susunod"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Kinakailangan ang password"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 00cf236d1bc4..234ab2880644 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP denetimini yalnızca DRM içeriği için kullan"</item>
<item msgid="45075631231212732">"HDCP denetimini her zaman kullan"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="5618929009984956469">"16 bit/örnek"</item>
+ <item msgid="3412640499234627248">"24 bit/örnek"</item>
+ <item msgid="121583001492929387">"32 bit/örnek"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="4726688794884191540">"16 bit/örnek"</item>
+ <item msgid="305344756485516870">"24 bit/örnek"</item>
+ <item msgid="244568657919675099">"32 bit/örnek"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Sistem Seçimini Kullan (Varsayılan)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Ses Kalitesi (990 kb/sn. / 909 kb/sn.) için optimize edildi"</item>
+ <item msgid="2921767058740704969">"Dengeli Ses ve Bağlantı Kalitesi (660 kb/sn. / 606 kb/sn.)"</item>
+ <item msgid="8860982705384396512">"Bağlantı Kalitesi (330 kb/sn. / 303 kb/sn.) için optimize edildi"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Ses Kalitesi için optimize edildi"</item>
+ <item msgid="4327143584633311908">"Dengeli Ses ve Bağlantı Kalitesi"</item>
+ <item msgid="4681409244565426925">"Bağlantı Kalitesi için optimize edildi"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Kapalı"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index a45248173432..57acf2126b64 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Hücresel veri her zaman etkin"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mutlak sesi iptal et"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Ses Codec\'i"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth Ses Codec\'ini Seçin"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Ses Örnek Hızı"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth Ses Codec\'ini Seçin:\nÖrnek Hızı"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Ses Örnek Başına Bit Sayısı"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth Ses Codec\'ini Seçin:\nÖrnek Başına Bit Sayısı"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Ses Kanalı Modu"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth Ses Codec\'ini Seçin:\nKanal Modu"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Ses LDAC Codec\'i: Oynatma Kalitesi"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Bluetooth Ses LDAC Codec\'ini Seçin:\nOynatma Kalitesi"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Akış: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Etkinleştirildiğinde, Kablosuz ağ sinyali zayıfken veri bağlantısının Hücresel ağa geçirilmesinde daha agresif olunur"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Demo modunda sıfırlamak için şifreyi girin"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Sonraki"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Şifre gerekli"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index dd661c49aa79..ea7af717a833 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Використовувати перевірку HDCP лише для вмісту, захищеного DRM"</item>
<item msgid="45075631231212732">"Завжди використовувати перевірку HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="8895532488906185219">"44,1 кГц"</item>
+ <item msgid="2909915718994807056">"48 кГц"</item>
+ <item msgid="3347287377354164611">"88,2 кГц"</item>
+ <item msgid="1234212100239985373">"96 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="4482862757811638365">"44,1 кГц"</item>
+ <item msgid="354495328188724404">"48 кГц"</item>
+ <item msgid="7329816882213695083">"88,2 кГц"</item>
+ <item msgid="6967397666254430476">"96 кГц"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="5618929009984956469">"16 бітів на зразок"</item>
+ <item msgid="3412640499234627248">"24 біти на зразок"</item>
+ <item msgid="121583001492929387">"32 біти на зразок"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="4726688794884191540">"16 бітів на зразок"</item>
+ <item msgid="305344756485516870">"24 біти на зразок"</item>
+ <item msgid="244568657919675099">"32 біти на зразок"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="4106832974775067314">"Моно"</item>
+ <item msgid="5571632958424639155">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="8900559293912978337">"Моно"</item>
+ <item msgid="8883739882299884241">"Стерео"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Оптимізовано для кращої якості аудіо (990/909 кбіт/с)"</item>
+ <item msgid="2921767058740704969">"Збалансована якість аудіо та з’єднання (660/606 кбіт/с)"</item>
+ <item msgid="8860982705384396512">"Оптимізовано для кращої якості з’єднання (330/303 кбіт/с)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Оптимізовано для кращої якості аудіо"</item>
+ <item msgid="4327143584633311908">"Збалансована якість аудіо та з’єднання"</item>
+ <item msgid="4681409244565426925">"Оптимізовано для кращої якості з’єднання"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Вимкнено"</item>
<item msgid="1593289376502312923">"64 Кб"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index b67c7c9e328e..9a742cb0c4db 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не вимикати передавання даних"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Вимкнути абсолютну гучність"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек для аудіо Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Вибрати кодек для аудіо Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частота вибірки для аудіо Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Вибрати кодек для аудіо Bluetooth:\nчастота вибірки"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Кількість бітів на зразок для аудіо Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Вибрати кодек для аудіо Bluetooth:\nбіти у вибірці"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим каналу для аудіо Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Вибрати кодек для аудіо Bluetooth:\nрежим каналу"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Кодек для аудіо Bluetooth LDAC: якість відтворення"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Вибрати кодек для аудіо Bluetooth LDAC:\nякість відтворення"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляція: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Примусово перемикатися на мобільну мережу, коли сигнал Wi-Fi слабкий"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Введіть пароль, щоб скинути налаштування в демо-режимі"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Далі"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Потрібен пароль"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index d970f19efbfc..7ad1d17bd21a 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"‏HDCP چیکنگ صرف DRM مواد کیلئے استعمال کریں"</item>
<item msgid="45075631231212732">"‏ہمیشہ HDCP چیکنگ استعمال کریں"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="5618929009984956469">"16 بٹس/نمونہ"</item>
+ <item msgid="3412640499234627248">"24 بٹس/نمونہ"</item>
+ <item msgid="121583001492929387">"32 بٹس/نمونہ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="4726688794884191540">"16 بٹس/نمونہ"</item>
+ <item msgid="305344756485516870">"24 بٹس/نمونہ"</item>
+ <item msgid="244568657919675099">"32 بٹس/نمونہ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="4106832974775067314">"مونو"</item>
+ <item msgid="5571632958424639155">"اسٹیریو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+ <item msgid="8900559293912978337">"مونو"</item>
+ <item msgid="8883739882299884241">"اسٹیریو"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"‏آڈیو کے معیار کیلئے بہتر بنایا گيا (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"‏متوازن آڈیو اور کنکشن کا معیار (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"‏کنکشن کے معیار کیلئے بہتر بنایا گيا (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"آڈیو کے معیار کیلئے بہتر بنایا گيا"</item>
+ <item msgid="4327143584633311908">"متوازن آڈیو اور کنکشن کا معیار"</item>
+ <item msgid="4681409244565426925">"کنکشن کے معیار کیلئے بہتر بنایا گيا"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"آف"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index d4ad6b9d83c4..b5a52ba7b447 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"سیلولر ڈیٹا کو ہمیشہ فعال رکھیں"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"بلوٹوتھ آڈیو کوڈیک"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"بلوٹوتھ آڈیو کوڈیک منتخب کریں"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"بلوٹوتھ آڈیو کے نمونے کی شرح"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"بلوٹوتھ آڈیو کوڈیک منتخب کریں:\nنمونے کی شرح"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"بلوٹوتھ آڈیو بٹس فی نمونہ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"بلوٹوتھ آڈیو کوڈیک منتخب کریں:\nبٹس فی نمونہ"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"بلوٹوتھ آڈیو چینل موڈ"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"بلوٹوتھ آڈیو کوڈیک منتخب کریں:\nچینل موڈ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"‏بلوٹوتھ آڈیو LDAC کوڈیک: پلے بیک کا معیار"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"‏بلوٹوتھ آڈیو LDAC کوڈیک منتخب کریں:\nپلے بیک کا معیار"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"سلسلہ بندی: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏فعال ہونے پر، جب Wi‑Fi سگنل کمزور ہوگا تو Wi‑Fi سیلولر پر ڈیٹا کنکشن بھیجنے کیلئے مزید جارحانہ کاروائی کرے گا۔"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"ڈیمو موڈ میں فیکٹری ری سیٹ کیلئے پاس ورڈ درج کریں"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"اگلا"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"پاس ورڈ درکار ہے"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index f784021fb715..9790d6521451 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"HDCP tekshiruvi faqat DRM kontent uchun ishlatilsin"</item>
<item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="8895532488906185219">"44.1 kGs"</item>
+ <item msgid="2909915718994807056">"48.0 kGs"</item>
+ <item msgid="3347287377354164611">"88.2 kGs"</item>
+ <item msgid="1234212100239985373">"96.0 kGs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="4482862757811638365">"44.1 kGs"</item>
+ <item msgid="354495328188724404">"48.0 kGs"</item>
+ <item msgid="7329816882213695083">"88.2 kGs"</item>
+ <item msgid="6967397666254430476">"96.0 kGs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="5618929009984956469">"16 bit/namuna"</item>
+ <item msgid="3412640499234627248">"24 bit/namuna"</item>
+ <item msgid="121583001492929387">"32 bit/namuna"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="4726688794884191540">"16 bit/namuna"</item>
+ <item msgid="305344756485516870">"24 bit/namuna"</item>
+ <item msgid="244568657919675099">"32 bit/namuna"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="4106832974775067314">"Mono"</item>
+ <item msgid="5571632958424639155">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="8900559293912978337">"Mono"</item>
+ <item msgid="8883739882299884241">"Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Ovoz sifatini optimallashtirish (990/909 kbit/s)"</item>
+ <item msgid="2921767058740704969">"Audio sifati balansi va ulanish tezligi (660/606 kbit/s)"</item>
+ <item msgid="8860982705384396512">"Ulanish tezligini optimallashtirish (330/303 kbit/s)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Ovoz sifatini optimallashtirish"</item>
+ <item msgid="4327143584633311908">"Audio sifati balansi va ulanish tezligi"</item>
+ <item msgid="4681409244565426925">"Ulanish tezligini optimallashtirish"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"O‘chiq"</item>
<item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f50f36b4526e..b5460c2d3d7b 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil internet o‘chirilmasin"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Ovoz balangligining mutlaq darajasini o‘chirib qo‘yish"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeki"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Bluetooth orqali uzatish uchun audiokodek"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth audio namunasi chastotasi"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Bluetooth orqali uzatish uchun audiokodek:\nnamuna chastotasi"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio namunasidagi bitlar soni"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Bluetooth orqali uzatish uchun audiokodek:\nnamunadagi bitlar soni"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth audio kanali rejimi"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Bluetooth orqali uzatish uchun audiokodek:\nkanal rejimi"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC audiokodeki bilan ijro etish sifati (Bluetooth orqali)"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"LDAC audiokodeki:\nijro sifati"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Translatsiya: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Agar ushbu funksiya yoqilsa, Wi-Fi signali past bo‘lganda internetga ulanish majburiy ravishda mobil internetga o‘tkaziladi."</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Demo rejimda zavod holatiga qaytarish uchun parolni kiriting"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Keyingisi"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Parolni kiritish zarur"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 21bbf0aa2451..c239039086bb 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Chỉ sử dụng kiểm tra HDCP cho nội dung DRM"</item>
<item msgid="45075631231212732">"Luôn sử dụng kiểm tra HDCP"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="8895532488906185219">"44,1 kHz"</item>
+ <item msgid="2909915718994807056">"48,0 kHz"</item>
+ <item msgid="3347287377354164611">"88,2 kHz"</item>
+ <item msgid="1234212100239985373">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="4482862757811638365">"44,1 kHz"</item>
+ <item msgid="354495328188724404">"48,0 kHz"</item>
+ <item msgid="7329816882213695083">"88,2 kHz"</item>
+ <item msgid="6967397666254430476">"96,0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="5618929009984956469">"16 bit/mẫu"</item>
+ <item msgid="3412640499234627248">"24 bit/mẫu"</item>
+ <item msgid="121583001492929387">"32 bit/mẫu"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="4726688794884191540">"16 bit/mẫu"</item>
+ <item msgid="305344756485516870">"24 bit/mẫu"</item>
+ <item msgid="244568657919675099">"32 bit/mẫu"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="4106832974775067314">"Đơn âm"</item>
+ <item msgid="5571632958424639155">"Âm thanh nổi"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Sử dụng lựa chọn hệ thống (Mặc định)"</item>
+ <item msgid="8900559293912978337">"Đơn âm"</item>
+ <item msgid="8883739882299884241">"Âm thanh nổi"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Được tối ưu hóa cho chất lượng âm thanh (990kb/giây/909kb/giây)"</item>
+ <item msgid="2921767058740704969">"Chất lượng kết nối và âm thanh cân bằng (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Được tối ưu hóa cho chất lượng kết nối (330kb/giây/303kb/giây)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Được tối ưu hóa cho chất lượng âm thanh"</item>
+ <item msgid="4327143584633311908">"Chất lượng kết nối và âm thanh cân bằng"</item>
+ <item msgid="4681409244565426925">"Được tối ưu hóa cho chất lượng kết nối"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Tắt"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 85be70e9914a..ff9a557f2f63 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Dữ liệu di động luôn hoạt động"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Vô hiệu hóa âm lượng tuyệt đối"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec âm thanh Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Chọn Codec âm thanh Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Tốc độ lấy mẫu âm thanh Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Chọn Codec âm thanh Bluetooth:\nTốc độ lấy mẫu"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Số bit âm thanh Bluetooth mỗi mẫu"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Chọn Codec âm thanh Bluetooth:\nSố bit trên mẫu"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Chế độ kênh âm thanh Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Chọn Codec âm thanh Bluetooth:\nChế độ kênh"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codec LDAC âm thanh Bluetooth: Chất lượng phát lại"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Chọn Codec LDAC âm thanh Bluetooth:\nChất lượng phát lại"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Truyền trực tuyến: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Khi được bật, Wi‑Fi sẽ tích cực hơn trong việc chuyển vùng kết nối dữ liệu sang mạng di động khi tín hiệu Wi‑Fi yếu"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Nhập mật khẩu để tiến hành khôi phục cài đặt gốc ở chế độ trình diễn"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Tiếp theo"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Yêu cầu mật khẩu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 5ec63b34412e..7c6e2ee7c0b9 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"仅使用 HDCP 检查 DRM 内容"</item>
<item msgid="45075631231212732">"始终使用 HDCP 检查"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"使用系统选择(默认)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"使用系统选择(默认)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"使用系统选择(默认)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"使用系统选择(默认)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"使用系统选择(默认)"</item>
+ <item msgid="5618929009984956469">"16 位/样本"</item>
+ <item msgid="3412640499234627248">"24 位/样本"</item>
+ <item msgid="121583001492929387">"32 位/样本"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"使用系统选择(默认)"</item>
+ <item msgid="4726688794884191540">"16 位/样本"</item>
+ <item msgid="305344756485516870">"24 位/样本"</item>
+ <item msgid="244568657919675099">"32 位/样本"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"使用系统选择(默认)"</item>
+ <item msgid="4106832974775067314">"单声道"</item>
+ <item msgid="5571632958424639155">"立体声"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"使用系统选择(默认)"</item>
+ <item msgid="8900559293912978337">"单声道"</item>
+ <item msgid="8883739882299884241">"立体声"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"偏重音频质量 (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"兼顾音频和连接质量 (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"偏重连接质量 (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"偏重音频质量"</item>
+ <item msgid="4327143584633311908">"兼顾音频和连接质量"</item>
+ <item msgid="4681409244565426925">"偏重连接质量"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"关闭"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 3ab17fb33daf..97a567852d28 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"始终开启移动数据网络"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用绝对音量功能"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"蓝牙音频编解码器"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"选择蓝牙音频编解码器"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"蓝牙音频采样率"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"选择蓝牙音频编解码器:\n采样率"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"蓝牙音频每样本位数"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"选择蓝牙音频编解码器:\n每样本位数"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"蓝牙音频声道模式"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"选择蓝牙音频编解码器:\n声道模式"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"蓝牙音频 LDAC 编解码器:播放质量"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"选择蓝牙音频 LDAC 编解码器:\n播放质量"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"正在流式传输:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"显示无线显示认证选项"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"提升WLAN日志记录级别(在WLAN选择器中显示每个SSID的RSSI)"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"开启此设置后,系统会在WLAN信号较弱时,主动将网络模式从WLAN网络切换到移动数据网络"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"输入密码即可在演示模式下恢复出厂设置"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"需要输入密码"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 953c8cc505d3..642d6162df5f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"僅使用 HDCP 檢查 DRM 內容"</item>
<item msgid="45075631231212732">"永遠使用 HDCP 檢查"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"使用系統選擇 (預設)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"使用系統選擇 (預設)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"使用系統選擇 (預設)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"使用系統選擇 (預設)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"使用系統選擇 (預設)"</item>
+ <item msgid="5618929009984956469">"每個樣本 16 位元"</item>
+ <item msgid="3412640499234627248">"每個樣本 24 位元"</item>
+ <item msgid="121583001492929387">"每個樣本 32 位元"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"使用系統選擇 (預設)"</item>
+ <item msgid="4726688794884191540">"每個樣本 16 位元"</item>
+ <item msgid="305344756485516870">"每個樣本 24 位元"</item>
+ <item msgid="244568657919675099">"每個樣本 32 位元"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"使用系統選擇 (預設)"</item>
+ <item msgid="4106832974775067314">"單聲道"</item>
+ <item msgid="5571632958424639155">"立體聲"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"使用系統選擇 (預設)"</item>
+ <item msgid="8900559293912978337">"單聲道"</item>
+ <item msgid="8883739882299884241">"立體聲"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"已優化音訊品質 (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"平衡音訊和連線品質 (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"已優化連線品質 (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"已優化音訊品質"</item>
+ <item msgid="4327143584633311908">"平衡音訊和連線品質"</item>
+ <item msgid="4681409244565426925">"已優化連線品質"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"關閉"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 79fc760e577c..0838496601e9 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"經常啟用流動數據"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊編解碼器"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"選擇藍牙音訊編解碼器"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"藍牙音訊取樣率"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"選擇藍牙音訊編解碼器:\n取樣率"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"藍牙音訊每個樣本位元數"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"選擇藍牙音訊編解碼器:\n每個樣本位元數"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"藍牙音訊聲道模式"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"選擇藍牙音訊編解碼器:\n聲道模式"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"藍牙音訊 LDAC 編解碼器:播放品質"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"選擇藍牙音訊 LDAC 編解碼器:\n播放品質"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"正在串流:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線會在訊號不穩的情況下更積極轉換成流動數據連線"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"說明和意見反映"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"輸入密碼即可在示範模式下重設原廠設定"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"請輸入密碼"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index d426b301d348..449ccc151a2d 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"僅使用 HDCP 檢查 DRM 內容"</item>
<item msgid="45075631231212732">"一律使用 HDCP 檢查"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"使用系統選擇 (預設)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"使用系統選擇 (預設)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"使用系統選擇 (預設)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"使用系統選擇 (預設)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"使用系統選擇 (預設)"</item>
+ <item msgid="5618929009984956469">"16 位元/樣本"</item>
+ <item msgid="3412640499234627248">"24 位元/樣本"</item>
+ <item msgid="121583001492929387">"32 位元/樣本"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"使用系統選擇 (預設)"</item>
+ <item msgid="4726688794884191540">"16 位元/樣本"</item>
+ <item msgid="305344756485516870">"24 位元/樣本"</item>
+ <item msgid="244568657919675099">"32 位元/樣本"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"使用系統選擇 (預設)"</item>
+ <item msgid="4106832974775067314">"單聲道"</item>
+ <item msgid="5571632958424639155">"立體聲"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"使用系統選擇 (預設)"</item>
+ <item msgid="8900559293912978337">"單聲道"</item>
+ <item msgid="8883739882299884241">"立體聲"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"音訊品質最佳化 (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"兼顧音訊及連線品質 (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"連線品質最佳化 (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"音訊品質最佳化"</item>
+ <item msgid="4327143584633311908">"兼顧音訊及連線品質"</item>
+ <item msgid="4681409244565426925">"連線品質最佳化"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"關閉"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 2a322522e406..4d7f7368433b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"行動數據連線一律保持啟用狀態"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊轉碼器"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"選取藍牙音訊轉碼器"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"藍牙音訊取樣率"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"選取藍牙音訊轉碼器:\n取樣率"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"藍牙音訊每單位樣本位元數"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"選取藍牙音訊轉碼器:\n每單位樣本位元數"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"藍牙音訊聲道模式"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"選取藍牙音訊轉碼器:\n聲道模式"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"藍牙音訊 LDAC 轉碼器:播放品質"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"選取藍牙音訊 LDAC 轉碼器:\n播放品質"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"串流中:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線在訊號不穩的情況下會更積極轉換成行動數據連線"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"如要在示範模式中恢復原廠設定,請輸入密碼"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"請輸入密碼"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 04e7614f349f..ed78ed8e5eac 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -58,22 +58,68 @@
<item msgid="3878793616631049349">"Sebenzisa ukuhlola kwe-HDCP kokuqukethwe i-DRM kuphela"</item>
<item msgid="45075631231212732">"Sebenzisa njalo ukuhlola kwe-HDPC"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
- <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
- <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
- <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
- <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"I-AAC"</item>
+ <item msgid="8910200421843557332">"aptX"</item>
+ <item msgid="8434403964359457768">"aptX HD"</item>
+ <item msgid="6751080638867012696">"I-LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"I-AAC"</item>
+ <item msgid="2279916056363477395">"aptX"</item>
+ <item msgid="6641171061200063516">"aptX HD"</item>
+ <item msgid="7950781694447359344">"I-LDAC"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item msgid="3093023430402746802">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="8895532488906185219">"44.1 kHz"</item>
+ <item msgid="2909915718994807056">"48.0 kHz"</item>
+ <item msgid="3347287377354164611">"88.2 kHz"</item>
+ <item msgid="1234212100239985373">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
+ <item msgid="3214516120190965356">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="4482862757811638365">"44.1 kHz"</item>
+ <item msgid="354495328188724404">"48.0 kHz"</item>
+ <item msgid="7329816882213695083">"88.2 kHz"</item>
+ <item msgid="6967397666254430476">"96.0 kHz"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item msgid="2684127272582591429">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="5618929009984956469">"16 bits/isampula"</item>
+ <item msgid="3412640499234627248">"24 bits/isampula"</item>
+ <item msgid="121583001492929387">"32 bits/isampula"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
+ <item msgid="1081159789834584363">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="4726688794884191540">"16 bits/isampula"</item>
+ <item msgid="305344756485516870">"24 bits/isampula"</item>
+ <item msgid="244568657919675099">"32 bits/isampula"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item msgid="5226878858503393706">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="4106832974775067314">"Okukodwa"</item>
+ <item msgid="5571632958424639155">"I-Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
+ <item msgid="4118561796005528173">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+ <item msgid="8900559293912978337">"Okukodwa"</item>
+ <item msgid="8883739882299884241">"I-Stereo"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item msgid="7158319962230727476">"Kuthuthukiselwe ikhwalithi yomsindo (990kbps/909kbps)"</item>
+ <item msgid="2921767058740704969">"Umsindo obhalansile nekhwalithi yoxhumo (660kbps/606kbps)"</item>
+ <item msgid="8860982705384396512">"Kuthuthukiselwe ikhwalithi yoxhumo (330kbps/303kbps)"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+ <item msgid="6398189564246596868">"Kuthuthukiselwe ikhwalithi yomsebenzisi"</item>
+ <item msgid="4327143584633311908">"Umsindo obhalansile nekhwalithi yoxhumo"</item>
+ <item msgid="4681409244565426925">"Kuthuthukiselwe ikhwalithi yoxhumo"</item>
+ </string-array>
<string-array name="select_logd_size_titles">
<item msgid="8665206199209698501">"Valiwe"</item>
<item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 143d4d12128a..9f7e72ead7ca 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -171,23 +171,16 @@
<string name="mobile_data_always_on" msgid="7745605759775320362">"Idatha yeselula ihlala isebenza"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Khubaza ivolumu ngokuphelele"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"I-Bluetooth Audio Codec"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="4558347981670553665">"Khetha i-Bluetooth Audio Codec"</string>
<string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Isilinganiso sesampula yomsindo we-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5628790207448471613">"Khetha i-Bluetooth Audio Codec:\nIsilinganiso sesampula"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Ama-Bits omsindo we-Bluetooth ngesampula ngayinye"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4546131401358681321">"Khetha i-Bluetooth Audio Codec:\nBits ngesampuli"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Imodi yesiteshi somsindo we-Bluetooth"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
- <skip />
- <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="9133545781346216071">"Khetha i-Bluetooth Audio Codec:\nImodi yesiteshi"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"I-Bluetooth Audio LDAC Codec: Ikhwalithi yokudlala"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Khetha i-Bluetooth Audio LDAC Codec:\nIkhwalithi yokudlala"</string>
+ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Ukusakaza: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Uma inikwe amandla, i-Wi-Fi izoba namandla kakhulu ekunikezeleni ukuxhumeka kwedatha kuselula, uma isiginali ye-Wi-Fi iphansi"</string>
@@ -360,4 +353,7 @@
<string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"I-GMT"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Faka iphasiwedi ukuze wenze ukusetha kwefekthri kumodi yedemo"</string>
+ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Okulandelayo"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"Iphasiwedi iyadingeka"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index cfb990e440cb..eb64b3a9bbd9 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -103,10 +103,11 @@
<!-- Bluetooth settings -->
- <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_titles">
<item>Use System Selection (Default)</item>
<item>SBC</item>
+ <item>AAC</item>
<item>aptX</item>
<item>aptX HD</item>
<item>LDAC</item>
@@ -119,18 +120,20 @@
<item>1</item>
<item>2</item>
<item>3</item>
+ <item>4</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_summaries" >
<item>Use System Selection (Default)</item>
<item>SBC</item>
+ <item>AAC</item>
<item>aptX</item>
<item>aptX HD</item>
<item>LDAC</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item>Use System Selection (Default)</item>
<item>44.1 kHz</item>
@@ -148,7 +151,7 @@
<item>8</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
<item>Use System Selection (Default)</item>
<item>44.1 kHz</item>
@@ -157,7 +160,7 @@
<item>96.0 kHz</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
<item>Use System Selection (Default)</item>
<item>16 bits/sample</item>
@@ -173,7 +176,7 @@
<item>4</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
<item>Use System Selection (Default)</item>
<item>16 bits/sample</item>
@@ -181,7 +184,7 @@
<item>32 bits/sample</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_channel_mode_titles">
<item>Use System Selection (Default)</item>
<item>Mono</item>
@@ -195,7 +198,7 @@
<item>2</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
<item>Use System Selection (Default)</item>
<item>Mono</item>
@@ -204,9 +207,9 @@
<!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70] -->
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item>Optimize for Audio Quality (990kbps/909kbps)</item>
+ <item>Optimized for Audio Quality (990kbps/909kbps)</item>
<item>Balanced Audio And Connection Quality (660kbps/606kbps)</item>
- <item>Optimize for Connection Quality (330kbps/303kbps)</item>
+ <item>Optimized for Connection Quality (330kbps/303kbps)</item>
</string-array>
<!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
@@ -218,9 +221,9 @@
<!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70]-->
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
- <item>Optimize for Audio Quality</item>
+ <item>Optimized for Audio Quality</item>
<item>Balanced Audio And Connection Quality</item>
- <item>Optimize for Connection Quality</item>
+ <item>Optimized for Connection Quality</item>
</string-array>
<!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
@@ -517,4 +520,37 @@
<item>7</item>
</integer-array>
+ <!-- BatteryMeterView parameters -->
+ <array name="batterymeter_color_levels">
+ <item>15</item>
+ <item>100</item>
+ </array>
+ <array name="batterymeter_color_values">
+ <item>@*android:color/battery_saver_mode_color</item>
+ <item>@android:color/white</item>
+ </array>
+ <array name="batterymeter_bolt_points">
+ <item>73</item> <item>0</item>
+ <item>392</item><item>0</item>
+ <item>201</item><item>259</item>
+ <item>442</item><item>259</item>
+ <item>4</item> <item>703</item>
+ <item>157</item><item>334</item>
+ <item>0</item> <item>334</item>
+ </array>
+ <array name="batterymeter_plus_points">
+ <item>3</item><item>0</item>
+ <item>5</item><item>0</item>
+ <item>5</item><item>3</item>
+ <item>8</item><item>3</item>
+ <item>8</item><item>5</item>
+ <item>5</item><item>5</item>
+ <item>5</item><item>8</item>
+ <item>3</item><item>8</item>
+ <item>3</item><item>5</item>
+ <item>0</item><item>5</item>
+ <item>0</item><item>3</item>
+ <item>3</item><item>3</item>
+ </array>
+
</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 2e8b30fb5abf..b72bcc71f046 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -57,4 +57,15 @@
<dimen name="drawer_width">300dp</dimen>
<dimen name="drawer_item_top_bottom_margin">4dp</dimen>
<dimen name="drawer_spacer_height">32dp</dimen>
+
+ <dimen name="battery_height">48dp</dimen>
+ <dimen name="battery_width">38dp</dimen>
+
+ <!-- Margin on the right side of the system icon group on Keyguard. -->
+ <fraction name="battery_button_height_fraction">10.5%</fraction>
+
+ <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
+ fraction of a pixel.-->
+ <fraction name="battery_subpixel_smoothing_left">0%</fraction>
+ <fraction name="battery_subpixel_smoothing_right">0%</fraction>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a1b2bdf5662f..5475b325773f 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -893,4 +893,14 @@
<!-- Label for Greenwich mean time, used in a string like GMT+05:00. [CHAR LIMIT=NONE] -->
<string name="time_zone_gmt">GMT</string>
+
+ <!-- Label for carrier demo mode factory reset confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="retail_demo_reset_message">Enter password to perform factory reset in demo mode</string>
+ <!-- Label for positive button on carrier demo mode factory reset confirmation dialog [CHAR LIMIT=40] -->
+ <string name="retail_demo_reset_next">Next</string>
+ <!-- Title for carrier demo mode factory reset confirmation dialog. [CHAR LIMIT=40] -->
+ <string name="retail_demo_reset_title">Password required</string>
+
+ <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
+ <string name="battery_meter_very_low_overlay_symbol">!</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index b037a3da8ad5..fc697cea40ba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -198,7 +198,7 @@ public class HelpUtils {
intent.putExtra(feedbackIntentExtraKey, packageNameKey);
intent.putExtra(feedbackIntentNameKey, packageNameValue);
}
- intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */);
+ intent.putExtra(EXTRA_THEME, 0 /* Light theme */);
TypedArray array = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimary});
intent.putExtra(EXTRA_PRIMARY_COLOR, array.getColor(0, 0));
array.recycle();
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 21786c917763..4b0ab59a931c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -15,21 +15,28 @@
*/
package com.android.settingslib;
+import android.Manifest;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.util.Xml;
-import android.provider.Settings;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.view.InflateException;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
@@ -53,6 +60,20 @@ public class SuggestionParser {
// If defined and not true, do not should optional step.
private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
+ // If defined, only display this optional step if the current user is of that type.
+ private static final String META_DATA_REQUIRE_USER_TYPE =
+ "com.android.settings.require_user_type";
+
+ // If defined, only display this optional step if a connection is available.
+ private static final String META_DATA_IS_CONNECTION_REQUIRED =
+ "com.android.settings.require_connection";
+
+ // The valid values that setup wizard recognizes for differentiating user types.
+ private static final String META_DATA_PRIMARY_USER_TYPE_VALUE = "primary";
+ private static final String META_DATA_ADMIN_USER_TYPE_VALUE = "admin";
+ private static final String META_DATA_GUEST_USER_TYPE_VALUE = "guest";
+ private static final String META_DATA_RESTRICTED_USER_TYPE_VALUE = "restricted";
+
/**
* Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
* For instance:
@@ -73,35 +94,63 @@ public class SuggestionParser {
private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
+ // Default dismiss control for smart suggestions.
+ private static final String DEFAULT_SMART_DISMISS_CONTROL = "0,10";
+
private final Context mContext;
private final List<SuggestionCategory> mSuggestionList;
- private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+ private final ArrayMap<Pair<String, String>, Tile> mAddCache = new ArrayMap<>();
private final SharedPreferences mSharedPrefs;
+ private final String mSmartDismissControl;
- public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
+
+ public SuggestionParser(
+ Context context, SharedPreferences sharedPrefs, int orderXml, String smartDismissControl) {
mContext = context;
mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
.parse(orderXml);
mSharedPrefs = sharedPrefs;
+ mSmartDismissControl = smartDismissControl;
+ }
+
+ public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
+ this(context, sharedPrefs, orderXml, DEFAULT_SMART_DISMISS_CONTROL);
+ }
+
+ @VisibleForTesting
+ public SuggestionParser(Context context, SharedPreferences sharedPrefs) {
+ mContext = context;
+ mSuggestionList = new ArrayList<SuggestionCategory>();
+ mSharedPrefs = sharedPrefs;
+ mSmartDismissControl = DEFAULT_SMART_DISMISS_CONTROL;
+ Log.wtf(TAG, "Only use this constructor for testing");
}
public List<Tile> getSuggestions() {
+ return getSuggestions(false);
+ }
+
+ public List<Tile> getSuggestions(boolean isSmartSuggestionEnabled) {
List<Tile> suggestions = new ArrayList<>();
final int N = mSuggestionList.size();
for (int i = 0; i < N; i++) {
- readSuggestions(mSuggestionList.get(i), suggestions);
+ readSuggestions(mSuggestionList.get(i), suggestions, isSmartSuggestionEnabled);
}
return suggestions;
}
+ public boolean dismissSuggestion(Tile suggestion) {
+ return dismissSuggestion(suggestion, false);
+ }
+
/**
* Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
* be disabled.
*/
- public boolean dismissSuggestion(Tile suggestion) {
+ public boolean dismissSuggestion(Tile suggestion, boolean isSmartSuggestionEnabled) {
String keyBase = suggestion.intent.getComponent().flattenToShortString();
int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
- String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+ String dismissControl = getDismissControl(suggestion, isSmartSuggestionEnabled);
if (dismissControl == null || parseDismissString(dismissControl).length == index) {
return true;
}
@@ -111,23 +160,33 @@ public class SuggestionParser {
return false;
}
- private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
- int countBefore = suggestions.size();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(category.category);
- if (category.pkg != null) {
- intent.setPackage(category.pkg);
- }
- TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
- addCache, null, suggestions, true, false);
+ @VisibleForTesting
+ public void filterSuggestions(
+ List<Tile> suggestions, int countBefore, boolean isSmartSuggestionEnabled) {
for (int i = countBefore; i < suggestions.size(); i++) {
if (!isAvailable(suggestions.get(i)) ||
!isSupported(suggestions.get(i)) ||
+ !satisifesRequiredUserType(suggestions.get(i)) ||
!satisfiesRequiredAccount(suggestions.get(i)) ||
- isDismissed(suggestions.get(i))) {
+ !satisfiesConnectivity(suggestions.get(i)) ||
+ isDismissed(suggestions.get(i), isSmartSuggestionEnabled)) {
suggestions.remove(i--);
}
}
+ }
+
+ @VisibleForTesting
+ void readSuggestions(
+ SuggestionCategory category, List<Tile> suggestions, boolean isSmartSuggestionEnabled) {
+ int countBefore = suggestions.size();
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category.category);
+ if (category.pkg != null) {
+ intent.setPackage(category.pkg);
+ }
+ TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
+ mAddCache, null, suggestions, true, false);
+ filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
if (!category.multiple && suggestions.size() > (countBefore + 1)) {
// If there are too many, remove them all and only re-add the one with the highest
// priority.
@@ -146,32 +205,77 @@ public class SuggestionParser {
}
private boolean isAvailable(Tile suggestion) {
- String featureRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
- if (featureRequired != null) {
- return mContext.getPackageManager().hasSystemFeature(featureRequired);
+ final String featuresRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
+ if (featuresRequired != null) {
+ for (String feature : featuresRequired.split(",")) {
+ if (TextUtils.isEmpty(feature)) {
+ Log.w(TAG, "Found empty substring when parsing required features: "
+ + featuresRequired);
+ } else if (!mContext.getPackageManager().hasSystemFeature(feature)) {
+ Log.i(TAG, suggestion.title + " requires unavailable feature " + feature);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @RequiresPermission(Manifest.permission.MANAGE_USERS)
+ private boolean satisifesRequiredUserType(Tile suggestion) {
+ final String requiredUser = suggestion.metaData.getString(META_DATA_REQUIRE_USER_TYPE);
+ if (requiredUser != null) {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ UserInfo userInfo = userManager.getUserInfo(UserHandle.myUserId());
+ for (String userType : requiredUser.split("\\|")) {
+ final boolean primaryUserCondtionMet = userInfo.isPrimary()
+ && META_DATA_PRIMARY_USER_TYPE_VALUE.equals(userType);
+ final boolean adminUserConditionMet = userInfo.isAdmin()
+ && META_DATA_ADMIN_USER_TYPE_VALUE.equals(userType);
+ final boolean guestUserCondtionMet = userInfo.isGuest()
+ && META_DATA_GUEST_USER_TYPE_VALUE.equals(userType);
+ final boolean restrictedUserCondtionMet = userInfo.isRestricted()
+ && META_DATA_RESTRICTED_USER_TYPE_VALUE.equals(userType);
+ if (primaryUserCondtionMet || adminUserConditionMet || guestUserCondtionMet
+ || restrictedUserCondtionMet) {
+ return true;
+ }
+ }
+ Log.i(TAG, suggestion.title + " requires user type " + requiredUser);
+ return false;
}
return true;
}
public boolean satisfiesRequiredAccount(Tile suggestion) {
- String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
+ final String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
if (requiredAccountType == null) {
return true;
}
AccountManager accountManager = AccountManager.get(mContext);
Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
- return accounts.length > 0;
+ boolean satisfiesRequiredAccount = accounts.length > 0;
+ if (!satisfiesRequiredAccount) {
+ Log.i(TAG, suggestion.title + " requires unavailable account type "
+ + requiredAccountType);
+ }
+ return satisfiesRequiredAccount;
}
public boolean isSupported(Tile suggestion) {
- int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
+ final int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
try {
if (suggestion.intent == null) {
return false;
}
final Resources res = mContext.getPackageManager().getResourcesForActivity(
suggestion.intent.getComponent());
- return isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+ boolean isSupported =
+ isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+ if (!isSupported) {
+ Log.i(TAG, suggestion.title + " requires unsupported resource "
+ + isSupportedResource);
+ }
+ return isSupported;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
return false;
@@ -181,6 +285,22 @@ public class SuggestionParser {
}
}
+ private boolean satisfiesConnectivity(Tile suggestion) {
+ final boolean isConnectionRequired =
+ suggestion.metaData.getBoolean(META_DATA_IS_CONNECTION_REQUIRED);
+ if (!isConnectionRequired) {
+ return true;
+ }
+ ConnectivityManager cm =
+ (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo netInfo = cm.getActiveNetworkInfo();
+ boolean satisfiesConnectivity = netInfo != null && netInfo.isConnectedOrConnecting();
+ if (!satisfiesConnectivity) {
+ Log.i(TAG, suggestion.title + " is missing required connection.");
+ }
+ return satisfiesConnectivity;
+ }
+
public boolean isCategoryDone(String category) {
String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
@@ -191,12 +311,11 @@ public class SuggestionParser {
Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
}
- private boolean isDismissed(Tile suggestion) {
- Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
- if (dismissObj == null) {
+ private boolean isDismissed(Tile suggestion, boolean isSmartSuggestionEnabled) {
+ String dismissControl = getDismissControl(suggestion, isSmartSuggestionEnabled);
+ if (dismissControl == null) {
return false;
}
- String dismissControl = String.valueOf(dismissObj);
String keyBase = suggestion.intent.getComponent().flattenToShortString();
if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
mSharedPrefs.edit()
@@ -236,7 +355,16 @@ public class SuggestionParser {
return dismisses;
}
- private static class SuggestionCategory {
+ private String getDismissControl(Tile suggestion, boolean isSmartSuggestionEnabled) {
+ if (isSmartSuggestionEnabled) {
+ return mSmartDismissControl;
+ } else {
+ return suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+ }
+ }
+
+ @VisibleForTesting
+ static class SuggestionCategory {
public String category;
public String pkg;
public boolean multiple;
diff --git a/packages/SettingsLib/src/com/android/settingslib/TronUtils.java b/packages/SettingsLib/src/com/android/settingslib/TronUtils.java
new file mode 100644
index 000000000000..1d9d03a63711
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/TronUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib;
+
+import android.content.Context;
+import android.net.ScoredNetwork;
+
+import com.android.internal.logging.MetricsLogger;
+
+/** Utilites for Tron Logging. */
+public final class TronUtils {
+
+ private TronUtils() {};
+
+ public static void logWifiSettingsBadge(Context context, int badgeEnum) {
+ logNetworkBadgeMetric(context, "settings_wifibadging", badgeEnum);
+ }
+
+ /**
+ * Logs an occurrence of the given network badge to a Histogram.
+ *
+ * @param context Context
+ * @param histogram the Tron histogram name to write to
+ * @param badgeEnum the {@link ScoredNetwork.Badging} badge value
+ * @throws IllegalArgumentException if the given badge enum is not supported
+ */
+ private static void logNetworkBadgeMetric(
+ Context context, String histogram, int badgeEnum)
+ throws IllegalArgumentException {
+ int bucket;
+ switch (badgeEnum) {
+ case ScoredNetwork.BADGING_NONE:
+ bucket = 0;
+ break;
+ case ScoredNetwork.BADGING_SD:
+ bucket = 1;
+ break;
+ case ScoredNetwork.BADGING_HD:
+ bucket = 2;
+ break;
+ case ScoredNetwork.BADGING_4K:
+ bucket = 3;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported badge enum: " + badgeEnum);
+ }
+
+ MetricsLogger.histogram(context, histogram, bucket);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index fbc6aa382876..ae6ada2a258e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -21,6 +21,8 @@ import android.net.ScoredNetwork;
import android.os.BatteryManager;
import android.os.UserManager;
import android.print.PrintManager;
+import android.view.View;
+
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
@@ -32,7 +34,7 @@ public class Utils {
private static String sServicesSystemSharedLibPackageName;
private static String sSharedSystemSharedLibPackageName;
- static final int[] WIFI_PIE_FOR_BADGING = {
+ public static final int[] WIFI_PIE_FOR_BADGING = {
com.android.internal.R.drawable.ic_signal_wifi_badged_0_bars,
com.android.internal.R.drawable.ic_signal_wifi_badged_1_bar,
com.android.internal.R.drawable.ic_signal_wifi_badged_2_bars,
@@ -288,8 +290,15 @@ public class Utils {
});
}
- private static int getWifiBadgeResource(int badge) {
+ /**
+ * Returns the resource id for the given badge or {@link View.NO_ID} if no badge is to be shown.
+ *
+ * @throws IllegalArgumentException if the given badge value is not supported.
+ */
+ public static int getWifiBadgeResource(int badge) {
switch (badge) {
+ case ScoredNetwork.BADGING_NONE:
+ return View.NO_ID;
case ScoredNetwork.BADGING_SD:
return com.android.internal.R.drawable.ic_signal_wifi_badged_sd;
case ScoredNetwork.BADGING_HD:
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java
new file mode 100644
index 000000000000..74b0c6b9ece1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java
@@ -0,0 +1,235 @@
+/*
+ * 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.settingslib.accessibility;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.text.Layout;
+import android.text.Spanned;
+import android.text.style.ClickableSpan;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * COPIED FROM SETUP WIZARD An accessibility delegate that allows {@link
+ * android.text.style.ClickableSpan} to be focused and clicked by accessibility services.
+ *
+ * <p>Sample usage:
+ *
+ * <pre>
+ * LinkAccessibilityHelper mAccessibilityHelper;
+ *
+ * private void init() {
+ * mAccessibilityHelper = new LinkAccessibilityHelper(myTextView);
+ * ViewCompat.setAccessibilityDelegate(myTextView, mLinkHelper);
+ * }
+ *
+ * {@literal @}Override
+ * protected boolean dispatchHoverEvent({@literal @}NonNull MotionEvent event) {
+ * if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {
+ * return true;
+ * }
+ * return super.dispatchHoverEvent(event);
+ * }
+ * </pre>
+ *
+ * @see android.support.v4.widget.ExploreByTouchHelper
+ */
+public class LinkAccessibilityHelper extends ExploreByTouchHelper {
+
+ private static final String TAG = "LinkAccessibilityHelper";
+
+ private final TextView mView;
+ private final Rect mTempRect = new Rect();
+
+ public LinkAccessibilityHelper(TextView view) {
+ super(view);
+ mView = view;
+ }
+
+ @Override
+ protected int getVirtualViewAt(float x, float y) {
+ final CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ final int offset = getOffsetForPosition(mView, x, y);
+ ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class);
+ if (linkSpans.length == 1) {
+ ClickableSpan linkSpan = linkSpans[0];
+ return spannedText.getSpanStart(linkSpan);
+ }
+ }
+ return INVALID_ID;
+ }
+
+ @Override
+ protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ final CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ ClickableSpan[] linkSpans =
+ spannedText.getSpans(0, spannedText.length(), ClickableSpan.class);
+ for (ClickableSpan span : linkSpans) {
+ virtualViewIds.add(spannedText.getSpanStart(span));
+ }
+ }
+ }
+
+ @Override
+ protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ final ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ event.setContentDescription(getTextForSpan(span));
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ event.setContentDescription(mView.getText());
+ }
+ }
+
+ @Override
+ protected void onPopulateNodeForVirtualView(
+ int virtualViewId, AccessibilityNodeInfoCompat info) {
+ final ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ info.setContentDescription(getTextForSpan(span));
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ info.setContentDescription(mView.getText());
+ }
+ info.setFocusable(true);
+ info.setClickable(true);
+ getBoundsForSpan(span, mTempRect);
+ if (mTempRect.isEmpty()) {
+ Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
+ mTempRect.set(0, 0, 1, 1);
+ }
+ info.setBoundsInParent(mTempRect);
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+ }
+
+ @Override
+ protected boolean onPerformActionForVirtualView(
+ int virtualViewId, int action, Bundle arguments) {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+ ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ span.onClick(mView);
+ return true;
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ }
+ }
+ return false;
+ }
+
+ private ClickableSpan getSpanForOffset(int offset) {
+ CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ ClickableSpan[] spans = spannedText.getSpans(offset, offset, ClickableSpan.class);
+ if (spans.length == 1) {
+ return spans[0];
+ }
+ }
+ return null;
+ }
+
+ private CharSequence getTextForSpan(ClickableSpan span) {
+ CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ return spannedText.subSequence(
+ spannedText.getSpanStart(span), spannedText.getSpanEnd(span));
+ }
+ return text;
+ }
+
+ // Find the bounds of a span. If it spans multiple lines, it will only return the bounds for the
+ // section on the first line.
+ private Rect getBoundsForSpan(ClickableSpan span, Rect outRect) {
+ CharSequence text = mView.getText();
+ outRect.setEmpty();
+ if (text instanceof Spanned) {
+ final Layout layout = mView.getLayout();
+ if (layout != null) {
+ Spanned spannedText = (Spanned) text;
+ final int spanStart = spannedText.getSpanStart(span);
+ final int spanEnd = spannedText.getSpanEnd(span);
+ final float xStart = layout.getPrimaryHorizontal(spanStart);
+ final float xEnd = layout.getPrimaryHorizontal(spanEnd);
+ final int lineStart = layout.getLineForOffset(spanStart);
+ final int lineEnd = layout.getLineForOffset(spanEnd);
+ layout.getLineBounds(lineStart, outRect);
+ if (lineEnd == lineStart) {
+ // If the span is on a single line, adjust both the left and right bounds
+ // so outrect is exactly bounding the span.
+ outRect.left = (int) Math.min(xStart, xEnd);
+ outRect.right = (int) Math.max(xStart, xEnd);
+ } else {
+ // If the span wraps across multiple lines, only use the first line (as returned
+ // by layout.getLineBounds above), and adjust the "start" of outrect to where
+ // the span starts, leaving the "end" of outrect at the end of the line.
+ // ("start" being left for LTR, and right for RTL)
+ if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) {
+ outRect.right = (int) xStart;
+ } else {
+ outRect.left = (int) xStart;
+ }
+ }
+
+ // Offset for padding
+ outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop());
+ }
+ }
+ return outRect;
+ }
+
+ // Compat implementation of TextView#getOffsetForPosition().
+
+ private static int getOffsetForPosition(TextView view, float x, float y) {
+ if (view.getLayout() == null) return -1;
+ final int line = getLineAtCoordinate(view, y);
+ return getOffsetAtCoordinate(view, line, x);
+ }
+
+ private static float convertToLocalHorizontalCoordinate(TextView view, float x) {
+ x -= view.getTotalPaddingLeft();
+ // Clamp the position to inside of the view.
+ x = Math.max(0.0f, x);
+ x = Math.min(view.getWidth() - view.getTotalPaddingRight() - 1, x);
+ x += view.getScrollX();
+ return x;
+ }
+
+ private static int getLineAtCoordinate(TextView view, float y) {
+ y -= view.getTotalPaddingTop();
+ // Clamp the position to inside of the view.
+ y = Math.max(0.0f, y);
+ y = Math.min(view.getHeight() - view.getTotalPaddingBottom() - 1, y);
+ y += view.getScrollY();
+ return view.getLayout().getLineForVertical((int) y);
+ }
+
+ private static int getOffsetAtCoordinate(TextView view, int line, float x) {
+ x = convertToLocalHorizontalCoordinate(view, x);
+ return view.getLayout().getOffsetForHorizontal(line, x);
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 2b1582d14830..561d92447c1f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1429,6 +1429,23 @@ public class ApplicationsState {
}
};
+ public static final AppFilter FILTER_GAMES = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(ApplicationsState.AppEntry info) {
+ // TODO: Update for the new game category.
+ boolean isGame;
+ synchronized (info.info) {
+ isGame = ((info.info.flags & ApplicationInfo.FLAG_IS_GAME) != 0)
+ || info.info.category == ApplicationInfo.CATEGORY_GAME;
+ }
+ return isGame;
+ }
+ };
+
public static class VolumeFilter implements AppFilter {
private final String mVolumeUuid;
@@ -1472,4 +1489,19 @@ public class ApplicationsState {
return mFirstFilter.filterApp(info) && mSecondFilter.filterApp(info);
}
}
+
+ public static final AppFilter FILTER_AUDIO = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry entry) {
+ boolean isMusicApp;
+ synchronized(entry) {
+ isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO;
+ }
+ return isMusicApp;
+ }
+ };
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 115c62298d9f..2fb6843dba06 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -135,6 +135,10 @@ public class LocalBluetoothAdapter {
mAdapter.setDiscoverableTimeout(timeout);
}
+ public long getDiscoveryEndMillis() {
+ return mAdapter.getDiscoveryEndMillis();
+ }
+
public void setName(String name) {
mAdapter.setName(name);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 7e3f67b875e5..d6bde8132327 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -36,7 +36,6 @@ public final class CategoryKey {
public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
- public static final String CATEGORY_SYSTEM_INPUT = "com.android.settings.category.ia.input";
public static final String CATEGORY_SYSTEM_LANGUAGE =
"com.android.settings.category.ia.language";
public static final String CATEGORY_SYSTEM_DEVELOPMENT =
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
new file mode 100755
index 000000000000..d25bb2e1b1b7
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -0,0 +1,468 @@
+/*
+ * 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.settingslib.graph;
+
+import android.animation.ArgbEvaluator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.provider.Settings;
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+public class BatteryMeterDrawableBase extends Drawable {
+
+ private static final float ASPECT_RATIO = 9.5f / 14.5f;
+ public static final String TAG = BatteryMeterDrawableBase.class.getSimpleName();
+ public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
+
+ protected final Context mContext;
+
+ protected int mLevel = -1;
+ protected boolean mPluggedIn;
+ protected boolean mPowerSaveEnabled;
+ protected boolean mShowPercent;
+
+ private static final boolean SINGLE_DIGIT_PERCENT = false;
+
+ private static final int FULL = 96;
+
+ private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
+
+ private final int[] mColors;
+ private final int mIntrinsicWidth;
+ private final int mIntrinsicHeight;
+
+ private float mButtonHeightFraction;
+ private float mSubpixelSmoothingLeft;
+ private float mSubpixelSmoothingRight;
+ private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
+ mPlusPaint;
+ private float mTextHeight, mWarningTextHeight;
+ private int mIconTint = Color.WHITE;
+ private float mOldDarkIntensity = 0f;
+
+ private int mHeight;
+ private int mWidth;
+ private String mWarningString;
+ private final int mCriticalLevel;
+ private int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+ private final float[] mPlusPoints;
+ private final Path mPlusPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mBoltFrame = new RectF();
+ private final RectF mPlusFrame = new RectF();
+
+ private final Path mShapePath = new Path();
+ private final Path mClipPath = new Path();
+ private final Path mTextPath = new Path();
+
+ private int mDarkModeBackgroundColor;
+ private int mDarkModeFillColor;
+
+ private int mLightModeBackgroundColor;
+ private int mLightModeFillColor;
+
+ public BatteryMeterDrawableBase(Context context, int frameColor) {
+ mContext = context;
+ final Resources res = context.getResources();
+ TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+ TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+ final int N = levels.length();
+ mColors = new int[2 * N];
+ for (int i = 0; i < N; i++) {
+ mColors[2 * i] = levels.getInt(i, 0);
+ mColors[2 * i + 1] = colors.getColor(i, 0);
+ }
+ levels.recycle();
+ colors.recycle();
+ updateShowPercent();
+ mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+ mCriticalLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+ mButtonHeightFraction = context.getResources().getFraction(
+ R.fraction.battery_button_height_fraction, 1, 1);
+ mSubpixelSmoothingLeft = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_left, 1, 1);
+ mSubpixelSmoothingRight = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_right, 1, 1);
+
+ mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFramePaint.setColor(frameColor);
+ mFramePaint.setDither(true);
+ mFramePaint.setStrokeWidth(0);
+ mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBatteryPaint.setDither(true);
+ mBatteryPaint.setStrokeWidth(0);
+ mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ mTextPaint.setTypeface(font);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ font = Typeface.create("sans-serif", Typeface.BOLD);
+ mWarningTextPaint.setTypeface(font);
+ mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+ if (mColors.length > 1) {
+ mWarningTextPaint.setColor(mColors[1]);
+ }
+
+ mChargeColor = Utils.getDefaultColor(mContext, R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
+ mBoltPoints = loadBoltPoints(res);
+
+ mPlusPaint = new Paint(mBoltPaint);
+ mPlusPoints = loadPlusPoints(res);
+
+ mDarkModeBackgroundColor =
+ Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
+ mDarkModeFillColor =
+ Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
+ mLightModeBackgroundColor =
+ Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
+ mLightModeFillColor =
+ Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
+
+ mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
+ mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mIntrinsicHeight;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mIntrinsicWidth;
+ }
+
+ public void disableShowPercent() {
+ mShowPercent = false;
+ postInvalidate();
+ }
+
+ protected void postInvalidate() {
+ scheduleSelf(this::invalidateSelf, 0);
+ }
+
+ private static float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float) pts[i] / maxX;
+ ptsF[i + 1] = (float) pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
+
+ private static float[] loadPlusPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float) pts[i] / maxX;
+ ptsF[i + 1] = (float) pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ super.setBounds(left, top, right, bottom);
+ mHeight = bottom - top;
+ mWidth = right - left;
+ mWarningTextPaint.setTextSize(mHeight * 0.75f);
+ mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+ }
+
+ protected void updateShowPercent() {
+ mShowPercent = true;
+ }
+
+ private int getColorForLevel(int percent) {
+ // If we are in power save mode, always use the normal color.
+ if (mPowerSaveEnabled) {
+ return mColors[mColors.length - 1];
+ }
+ int thresh, color = 0;
+ for (int i = 0; i < mColors.length; i += 2) {
+ thresh = mColors[i];
+ color = mColors[i + 1];
+ if (percent <= thresh) {
+
+ // Respect tinting for "normal" level
+ if (i == mColors.length - 2) {
+ return mIconTint;
+ } else {
+ return color;
+ }
+ }
+ }
+ return color;
+ }
+
+ public void setDarkIntensity(float darkIntensity) {
+ if (darkIntensity == mOldDarkIntensity) {
+ return;
+ }
+ int backgroundColor = getBackgroundColor(darkIntensity);
+ int fillColor = getFillColor(darkIntensity);
+ setColors(fillColor, backgroundColor);
+ mOldDarkIntensity = darkIntensity;
+ }
+
+ public void setColors(int fillColor, int backgroundColor) {
+ mIconTint = fillColor;
+ mFramePaint.setColor(backgroundColor);
+ mBoltPaint.setColor(fillColor);
+ mChargeColor = fillColor;
+ invalidateSelf();
+ }
+
+ private int getBackgroundColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+ }
+
+ private int getFillColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+ }
+
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+ }
+
+ @Override
+ public void draw(Canvas c) {
+ final int level = mLevel;
+
+ if (level == -1) return;
+
+ float drawFrac = (float) level / 100f;
+ final int height = mHeight;
+ final int width = (int) (ASPECT_RATIO * mHeight);
+ int px = (mWidth - width) / 2;
+
+ final int buttonHeight = (int) (height * mButtonHeightFraction);
+
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(px, 0);
+
+ // button-frame: area above the battery body
+ mButtonFrame.set(
+ mFrame.left + Math.round(width * 0.25f),
+ mFrame.top,
+ mFrame.right - Math.round(width * 0.25f),
+ mFrame.top + buttonHeight);
+
+ mButtonFrame.top += mSubpixelSmoothingLeft;
+ mButtonFrame.left += mSubpixelSmoothingLeft;
+ mButtonFrame.right -= mSubpixelSmoothingRight;
+
+ // frame: battery body area
+ mFrame.top += buttonHeight;
+ mFrame.left += mSubpixelSmoothingLeft;
+ mFrame.top += mSubpixelSmoothingLeft;
+ mFrame.right -= mSubpixelSmoothingRight;
+ mFrame.bottom -= mSubpixelSmoothingRight;
+
+ // set the battery charging color
+ mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
+
+ if (level >= FULL) {
+ drawFrac = 1f;
+ } else if (level <= mCriticalLevel) {
+ drawFrac = 0f;
+ }
+
+ final float levelTop = drawFrac == 1f ? mButtonFrame.top
+ : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+
+ // define the battery shape
+ mShapePath.reset();
+ mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+
+ if (mPluggedIn) {
+ // define the bolt shape
+ final float bl = mFrame.left + mFrame.width() / 4f;
+ final float bt = mFrame.top + mFrame.height() / 6f;
+ final float br = mFrame.right - mFrame.width() / 4f;
+ final float bb = mFrame.bottom - mFrame.height() / 10f;
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+
+ float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mBoltPath, mBoltPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+ }
+ } else if (mPowerSaveEnabled) {
+ // define the plus shape
+ final float pw = mFrame.width() * 2 / 3;
+ final float pl = mFrame.left + (mFrame.width() - pw) / 2;
+ final float pt = mFrame.top + (mFrame.height() - pw) / 2;
+ final float pr = mFrame.right - (mFrame.width() - pw) / 2;
+ final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
+ if (mPlusFrame.left != pl || mPlusFrame.top != pt
+ || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
+ mPlusFrame.set(pl, pt, pr, pb);
+ mPlusPath.reset();
+ mPlusPath.moveTo(
+ mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+ for (int i = 2; i < mPlusPoints.length; i += 2) {
+ mPlusPath.lineTo(
+ mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
+ }
+ mPlusPath.lineTo(
+ mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+ }
+
+ float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mPlusPath, mPlusPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // compute percentage text
+ boolean pctOpaque = false;
+ float pctX = 0, pctY = 0;
+ String pctText = null;
+ if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
+ mTextPaint.setColor(getColorForLevel(level));
+ mTextPaint.setTextSize(height *
+ (SINGLE_DIGIT_PERCENT ? 0.75f
+ : (mLevel == 100 ? 0.38f : 0.5f)));
+ mTextHeight = -mTextPaint.getFontMetrics().ascent;
+ pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
+ pctX = mWidth * 0.5f;
+ pctY = (mHeight + mTextHeight) * 0.47f;
+ pctOpaque = levelTop > pctY;
+ if (!pctOpaque) {
+ mTextPath.reset();
+ mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+ // cut the percentage text out of the overall shape
+ mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // draw the battery shape background
+ c.drawPath(mShapePath, mFramePaint);
+
+ // draw the battery shape, clipped to charging level
+ mFrame.top = levelTop;
+ mClipPath.reset();
+ mClipPath.addRect(mFrame, Path.Direction.CCW);
+ mShapePath.op(mClipPath, Path.Op.INTERSECT);
+ c.drawPath(mShapePath, mBatteryPaint);
+
+ if (!mPluggedIn && !mPowerSaveEnabled) {
+ if (level <= mCriticalLevel) {
+ // draw the warning text
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
+ } else if (pctOpaque) {
+ // draw the percentage text
+ c.drawText(pctText, pctX, pctY, mTextPaint);
+ }
+ }
+ }
+
+ // Some stuff required by Drawable.
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ mFramePaint.setColorFilter(colorFilter);
+ mBatteryPaint.setColorFilter(colorFilter);
+ mWarningTextPaint.setColorFilter(colorFilter);
+ mBoltPaint.setColorFilter(colorFilter);
+ mPlusPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java b/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java
new file mode 100644
index 000000000000..da865366668d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java
@@ -0,0 +1,66 @@
+/*
+ * 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.settingslib.widget;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewCompat;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.TextView;
+import com.android.settingslib.accessibility.LinkAccessibilityHelper;
+/**
+ * Copied from setup wizard. This TextView performs two functions. The first is to make it so the
+ * link behaves properly and becomes clickable. The second is that it makes the link visible to
+ * accessibility services.
+ */
+public class LinkTextView extends TextView {
+
+ private LinkAccessibilityHelper mAccessibilityHelper;
+
+ public LinkTextView(Context context) {
+ this(context, null);
+ }
+
+ public LinkTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAccessibilityHelper = new LinkAccessibilityHelper(this);
+ ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(text, type);
+ if (text instanceof Spanned) {
+ final ClickableSpan[] spans =
+ ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+ if (spans.length > 0) {
+ setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ }
+ }
+
+ @Override
+ protected boolean dispatchHoverEvent(@NonNull MotionEvent event) {
+ if (mAccessibilityHelper.dispatchHoverEvent(event)) {
+ return true;
+ }
+ return super.dispatchHoverEvent(event);
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 06ea4459b3ff..82e69d8da1e6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -222,21 +222,21 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (isActive() && !other.isActive()) return -1;
if (!isActive() && other.isActive()) return 1;
- // Higher scores go before lower scores
- if (mRankingScore != other.mRankingScore) {
- return (mRankingScore > other.mRankingScore) ? -1 : 1;
- }
-
// Reachable one goes before unreachable one.
if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
- // Configured one goes before unconfigured one.
+ // Configured (saved) one goes before unconfigured one.
if (networkId != WifiConfiguration.INVALID_NETWORK_ID
&& other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
if (networkId == WifiConfiguration.INVALID_NETWORK_ID
&& other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
+ // Higher scores go before lower scores
+ if (mRankingScore != other.mRankingScore) {
+ return (mRankingScore > other.mRankingScore) ? -1 : 1;
+ }
+
// Sort by signal strength, bucketed by level
int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
- WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 8ebea619e4ef..a77c31045662 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-
package com.android.settingslib.wifi;
import android.content.Context;
@@ -21,8 +20,8 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.StateListDrawable;
+import android.net.NetworkBadging;
import android.net.ScoredNetwork;
import android.net.wifi.WifiConfiguration;
import android.os.Looper;
@@ -34,7 +33,9 @@ import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.settingslib.R;
+import com.android.settingslib.TronUtils;
import com.android.settingslib.Utils;
public class AccessPointPreference extends Preference {
@@ -46,12 +47,9 @@ public class AccessPointPreference extends Preference {
R.attr.state_encrypted,
R.attr.state_saved
};
- private static final int[] STATE_NONE = {};
- private static final int[] wifi_signal_attributes = { R.attr.wifi_signal };
private static final int[] wifi_friction_attributes = { R.attr.wifi_friction };
- private final StateListDrawable mWifiSld;
private final StateListDrawable mFrictionSld;
private final int mBadgePadding;
private final UserBadgeCache mBadgeCache;
@@ -63,8 +61,6 @@ public class AccessPointPreference extends Preference {
private int mLevel;
private CharSequence mContentDescription;
private int mDefaultIconResId;
- private int mIconWidth;
- private int mIconHeight;
private int mWifiBadge = ScoredNetwork.BADGING_NONE;
static final int[] WIFI_CONNECTION_STRENGTH = {
@@ -77,7 +73,6 @@ public class AccessPointPreference extends Preference {
// Used for dummy pref.
public AccessPointPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- mWifiSld = null;
mFrictionSld = null;
mBadgePadding = 0;
mBadgeCache = null;
@@ -93,11 +88,6 @@ public class AccessPointPreference extends Preference {
mAccessPoint.setTag(this);
mLevel = -1;
- mWifiSld = (StateListDrawable) context.getTheme()
- .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
- // Save icon width and height to use for creating a badged icon
- setIconWidthAndHeight();
-
TypedArray frictionSld;
try {
frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
@@ -124,11 +114,6 @@ public class AccessPointPreference extends Preference {
mLevel = -1;
mDefaultIconResId = iconResId;
- mWifiSld = (StateListDrawable) context.getTheme()
- .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
- // Save icon width and height to use for creating a badged icon
- setIconWidthAndHeight();
-
TypedArray frictionSld;
try {
frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
@@ -143,13 +128,6 @@ public class AccessPointPreference extends Preference {
.getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
}
- private void setIconWidthAndHeight() {
- // TODO(sghuman): Refactor this defined widths and heights into a dimension resource and
- // reference directly.
- mIconWidth = mWifiSld.getIntrinsicWidth();
- mIconHeight = mWifiSld.getIntrinsicHeight();
- }
-
public AccessPoint getAccessPoint() {
return mAccessPoint;
}
@@ -183,34 +161,15 @@ public class AccessPointPreference extends Preference {
protected void updateIcon(int level, Context context) {
if (level == -1) {
safeSetDefaultIcon();
+ return;
+ }
+ TronUtils.logWifiSettingsBadge(context, mWifiBadge);
+ Drawable drawable = NetworkBadging.getWifiIcon(level, mWifiBadge, getContext().getTheme());
+ if (!mForSavedNetworks && drawable != null) {
+ drawable.setTint(Utils.getColorAccent(getContext()));
+ setIcon(drawable);
} else {
- if (mWifiBadge != ScoredNetwork.BADGING_NONE) {
- // TODO(sghuman): Refactor this to reuse drawable to save memory and add to a
- // special subclass of AccessPointPreference
- LayerDrawable drawable = Utils.getBadgedWifiIcon(context, level, mWifiBadge);
- drawable.setLayerSize(0, mIconWidth, mIconHeight);
- drawable.setLayerSize(1, mIconWidth, mIconHeight);
- drawable.setTint(Utils.getColorAccent(getContext()));
- setIcon(drawable);
- return;
- }
- if (getIcon() == null) {
- // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
- // set the icon (drawable) to that state's drawable.
- // If sld is null then we are indexing and therefore do not have access to
- // (nor need to display) the drawable.
- if (mWifiSld != null) {
- mWifiSld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
- ? STATE_SECURED
- : STATE_NONE);
- Drawable drawable = mWifiSld.getCurrent();
- if (!mForSavedNetworks && drawable != null) {
- setIcon(drawable);
- return;
- }
- }
- safeSetDefaultIcon();
- }
+ safeSetDefaultIcon();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index fabae573e4b0..6f52dcace323 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -12,13 +12,17 @@ package com.android.settingslib.wifi;
import android.content.Intent;
import android.net.NetworkInfo;
+import android.net.NetworkKey;
+import android.net.WifiKey;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.util.Log;
import java.util.List;
public class WifiStatusTracker {
+ private static final String TAG = "WifiStatusTracker";
private final WifiManager mWifiManager;
public boolean enabled;
@@ -26,6 +30,7 @@ public class WifiStatusTracker {
public String ssid;
public int rssi;
public int level;
+ public NetworkKey networkKey;
public WifiStatusTracker(WifiManager wifiManager) {
mWifiManager = wifiManager;
@@ -40,19 +45,32 @@ public class WifiStatusTracker {
final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
connected = networkInfo != null && networkInfo.isConnected();
+ WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
+ ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
+ : mWifiManager.getConnectionInfo();
+
// If Connected grab the signal strength and ssid.
- if (connected) {
- // try getting it out of the intent first
- WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
- ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
- : mWifiManager.getConnectionInfo();
- if (info != null) {
- ssid = getSsid(info);
+ if (connected && info != null) {
+ ssid = getSsid(info);
+ String bssid = info.getBSSID();
+ if ((ssid != null) && (bssid != null)) {
+ // Reuse existing network key object if possible.
+ if ((networkKey == null)
+ || !networkKey.wifiKey.ssid.equals(ssid)
+ || !networkKey.wifiKey.bssid.equals(bssid)) {
+ try {
+ networkKey = new NetworkKey(
+ new WifiKey(ssid, bssid));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Cannot create NetworkKey", e);
+ }
+ }
} else {
- ssid = null;
+ networkKey = null;
}
- } else if (!connected) {
+ } else {
ssid = null;
+ networkKey = null;
}
} else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
// Default to -200 as its below WifiManager.MIN_RSSI.
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 799f388057c1..c6179943b4d3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -16,9 +16,11 @@
package com.android.settingslib.wifi;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -38,6 +40,7 @@ import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.provider.Settings;
import android.support.annotation.WorkerThread;
import android.util.ArraySet;
import android.util.Log;
@@ -136,6 +139,8 @@ public class WifiTracker {
private final NetworkScoreManager mNetworkScoreManager;
private final WifiNetworkScoreCache mScoreCache;
private final Set<NetworkKey> mRequestedScores = new ArraySet<>();
+ private boolean mNetworkScoringUiEnabled;
+ private final ContentObserver mObserver;
@VisibleForTesting
Scanner mScanner;
@@ -215,6 +220,16 @@ public class WifiTracker {
Message.obtain(mWorkHandler, WorkHandler.MSG_UPDATE_NETWORK_SCORES).sendToTarget();
}
});
+
+ mObserver = new ContentObserver(mWorkHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mNetworkScoringUiEnabled =
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1;
+ }
+ };
}
/**
@@ -274,6 +289,11 @@ public class WifiTracker {
}
});
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.NETWORK_SCORING_UI_ENABLED),
+ false /* notifyForDescendants */,
+ mObserver);
+ mObserver.onChange(false /* selfChange */); // Set the initial value for mScoringUiEnabled
resumeScanning();
if (!mRegistered) {
@@ -327,6 +347,7 @@ public class WifiTracker {
unregisterAndClearScoreCache();
}
});
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
}
@WorkerThread
@@ -537,10 +558,11 @@ public class WifiTracker {
}
}
-
- requestScoresForNetworkKeys(scoresToRequest);
- for (AccessPoint ap : accessPoints) {
- ap.updateScores(mScoreCache);
+ if (mNetworkScoringUiEnabled) {
+ requestScoresForNetworkKeys(scoresToRequest);
+ for (AccessPoint ap : accessPoints) {
+ ap.updateScores(mScoreCache);
+ }
}
// Pre-sort accessPoints to speed preference insertion
@@ -641,7 +663,7 @@ public class WifiTracker {
if (ap.update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
reorder = true;
}
- if (ap.updateScores(mScoreCache)) {
+ if (mNetworkScoringUiEnabled && ap.updateScores(mScoreCache)) {
reorder = true;
}
}
@@ -657,6 +679,10 @@ public class WifiTracker {
* <p>Will trigger a resort and notify listeners of changes if applicable.
*/
private void updateNetworkScores() {
+ if (!mNetworkScoringUiEnabled) {
+ return;
+ }
+
// Lock required to prevent accidental copying of AccessPoint states while the modification
// is in progress. see #copyAndNotifyListeners
long before = System.currentTimeMillis();
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 98bce0ca42b2..bd910dd190db 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -28,7 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
espresso-core \
mockito-target-minus-junit4 \
- legacy-android-test
+ legacy-android-test \
+ truth-prebuilt
include frameworks/base/packages/SettingsLib/common.mk
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
new file mode 100644
index 000000000000..8a6ae86e4156
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.settingslib.applications;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.pm.ApplicationInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ApplicationsStateTest {
+ private ApplicationsState.AppEntry mEntry;
+
+ @Before
+ public void setUp() {
+ mEntry = mock(ApplicationsState.AppEntry.class);
+ mEntry.info = mock(ApplicationInfo.class);
+ }
+
+ @Test
+ public void testGamesFilterAcceptsGameDeprecated() {
+ mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME;
+
+ assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
+ }
+
+ @Test
+ public void testGameFilterAcceptsCategorizedGame() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
+
+ assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
+ }
+
+ @Test
+ public void testGameFilterAcceptsCategorizedGameAndDeprecatedIsGame() {
+ mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME;
+ mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
+
+ assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
+ }
+
+ @Test
+ public void testGamesFilterRejectsNotGame() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
+
+ assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isFalse();
+ }
+
+ @Test
+ public void testAudioFilterAcceptsCategorizedAudio() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_AUDIO;
+
+ assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isTrue();
+ }
+
+ @Test
+ public void testAudiosFilterRejectsNotAudio() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
+
+ assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isFalse();
+ }
+
+ @Test
+ public void testAudiosFilterRejectsDefaultCategory() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
+
+ assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isFalse();
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
new file mode 100644
index 000000000000..fab00dab5be7
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -0,0 +1,51 @@
+package com.android.settingslib.graph;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.settingslib.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryMeterDrawableBaseTest {
+ private Context mContext;
+ private Resources mResources;
+ private BatteryMeterDrawableBase mBatteryDrawable;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mResources = mContext.getResources();
+ mBatteryDrawable = new BatteryMeterDrawableBase(mContext, 0);
+ }
+
+ @Test
+ public void testGetIntrinsicSize() {
+ assertThat(mBatteryDrawable.getIntrinsicWidth()).
+ isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_width));
+ assertThat(mBatteryDrawable.getIntrinsicHeight()).
+ isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_height));
+ }
+
+ @Test
+ public void testDrawNothingBeforeOnBatteryLevelChanged() {
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryDrawable.draw(canvas);
+ verify(canvas, never()).drawPath(any(), any());
+ verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index eaf0367822c8..08736c77c409 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -110,7 +110,7 @@ public class WifiTrackerTest {
private HandlerThread mWorkerThread;
private Looper mLooper;
private Looper mMainLooper;
- private int mOriginalSettingValue;
+ private int mOriginalScoringUiSettingValue;
@Before
public void setUp() {
@@ -175,19 +175,23 @@ public class WifiTrackerTest {
}
}).when(mockWifiListener).onAccessPointsChanged();
- mOriginalSettingValue = Settings.Global.getInt(
- InstrumentationRegistry.getTargetContext().getContentResolver(),
- Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
- 0 /* disabled */);
-
+ // Turn on Scoring UI features
+ mOriginalScoringUiSettingValue = Settings.Global.getInt(
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ 0 /* disabled */);
+ Settings.Global.putInt(
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ 1 /* enabled */);
}
@After
public void cleanUp() {
Settings.Global.putInt(
- InstrumentationRegistry.getTargetContext().getContentResolver(),
- Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
- mOriginalSettingValue);
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ mOriginalScoringUiSettingValue);
}
private static ScanResult buildScanResult1() {
@@ -333,9 +337,18 @@ public class WifiTrackerTest {
WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
+ CountDownLatch latch = new CountDownLatch(1);
+ doAnswer(
+ (invocation) -> {
+ latch.countDown();
+ return null;
+ }).when(mockNetworkScoreManager)
+ .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
+
// Test unregister
tracker.stopTracking();
+ latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
verify(mockNetworkScoreManager)
.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
}
@@ -385,7 +398,28 @@ public class WifiTrackerTest {
assertTrue(aps.size() == 2);
assertEquals(aps.get(0).getSsidStr(), SSID_2);
assertEquals(aps.get(1).getSsidStr(), SSID_1);
+ }
+
+ @Test
+ public void scoreCacheUpdateScoresShouldNotChangeSortOrderWhenSortingDisabled()
+ throws InterruptedException {
+ Settings.Global.putInt(
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ 0 /* disabled */);
+
+ WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ List<AccessPoint> aps = tracker.getAccessPoints();
+ assertTrue(aps.size() == 2);
+ assertEquals(aps.get(0).getSsidStr(), SSID_1);
+ assertEquals(aps.get(1).getSsidStr(), SSID_2);
+ updateScoresAndWaitForAccessPointsChangedCallback();
+
+ aps = tracker.getAccessPoints();
+ assertTrue(aps.size() == 2);
+ assertEquals(aps.get(0).getSsidStr(), SSID_1);
+ assertEquals(aps.get(1).getSsidStr(), SSID_2);
}
@Test
@@ -405,6 +439,28 @@ public class WifiTrackerTest {
}
@Test
+ public void noBadgesShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
+ throws InterruptedException {
+ Settings.Global.putInt(
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ 0 /* disabled */);
+
+ WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ updateScoresAndWaitForAccessPointsChangedCallback();
+
+ List<AccessPoint> aps = tracker.getAccessPoints();
+
+ for (AccessPoint ap : aps) {
+ if (ap.getSsidStr().equals(SSID_1)) {
+ assertEquals(ScoredNetwork.BADGING_NONE, ap.getBadge());
+ } else if (ap.getSsidStr().equals(SSID_2)) {
+ assertEquals(ScoredNetwork.BADGING_NONE, ap.getBadge());
+ }
+ }
+ }
+
+ @Test
public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
mRequestScoresLatch = new CountDownLatch(2);
WifiTracker tracker = createTrackerAndInjectInitialScanResults();
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index 7a89884ae747..596d614ba355 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -43,6 +43,12 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay \
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
+LOCAL_JAR_EXCLUDE_FILES := none
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res
+
+
include frameworks/base/packages/SettingsLib/common.mk
include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
new file mode 100644
index 000000000000..1eeafba1bf8f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<optional-steps>
+ <step category="com.android.settings.suggested.category.LOCK_SCREEN" />
+ <step category="com.android.settings.suggested.category.EMAIL" />
+ <step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
+ multiple="true" />
+ <step category="com.android.settings.suggested.category.HOTWORD" />
+ <step category="com.android.settings.suggested.category.DEFAULT"
+ multiple="true" />
+ <step category="com.android.settings.suggested.category.SETTINGS_ONLY"
+ multiple="true" />
+</optional-steps>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java
new file mode 100644
index 000000000000..11c925eb11b8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java
@@ -0,0 +1,48 @@
+/*
+ * 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.settingslib;
+
+import org.junit.runners.model.InitializationError;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.manifest.AndroidManifest;
+import org.robolectric.res.Fs;
+import org.robolectric.res.ResourcePath;
+
+import java.util.List;
+
+public class SettingLibRobolectricTestRunner extends RobolectricTestRunner {
+
+ public SettingLibRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ }
+
+ @Override
+ protected AndroidManifest getAppManifest(Config config) {
+ // Using the manifest file's relative path, we can figure out the application directory.
+ final String appRoot = "frameworks/base/packages/SettingsLib";
+ final String manifestPath = appRoot + "/AndroidManifest.xml";
+ final String resDir = appRoot + "/tests/robotests/res";
+ final String assetsDir = appRoot + config.assetDir();
+
+ final AndroidManifest manifest = new AndroidManifest(Fs.fileFromPath(manifestPath),
+ Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir));
+
+ manifest.setPackageName("com.android.settingslib");
+ return manifest;
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
new file mode 100644
index 000000000000..0032cf083d8d
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.settingslib;
+
+import android.util.Log;
+import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.preference.PreferenceManager;
+
+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;
+import org.robolectric.annotation.Config;
+
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtilsTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SuggestionParserTest {
+
+ @Mock
+ private PackageManager mPackageManager;
+ private Context mContext;
+ private SuggestionParser mSuggestionParser;
+ private SuggestionParser.SuggestionCategory mSuggestioCategory;
+ private List<Tile> mSuggestionsBeforeDismiss;
+ private List<Tile> mSuggestionsAfterDismiss;
+ private SharedPreferences mPrefs;
+ private Tile mSuggestion;
+ private List<ResolveInfo> mInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ mSuggestion = new Tile();
+ mSuggestion.intent = new Intent("action");
+ mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
+ mSuggestion.metaData = new Bundle();
+ mSuggestionParser = new SuggestionParser(
+ mContext, mPrefs, R.xml.suggestion_ordering, "0,0");
+ mSuggestioCategory = new SuggestionParser.SuggestionCategory();
+ mSuggestioCategory.category = "category1";
+ mSuggestioCategory.multiple = true;
+ mInfo = new ArrayList<>();
+ ResolveInfo info1 = TileUtilsTest.newInfo(true, "category1");
+ info1.activityInfo.packageName = "pkg";
+ ResolveInfo info2 = TileUtilsTest.newInfo(true, "category1");
+ info2.activityInfo.packageName = "pkg2";
+ mInfo.add(info1);
+ mInfo.add(info2);
+ when(mPackageManager.queryIntentActivitiesAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(mInfo);
+ }
+
+ @Test
+ public void testDismissSuggestion_withoutSmartSuggestion() {
+ assertThat(mSuggestionParser.dismissSuggestion(mSuggestion, false)).isTrue();
+ }
+
+ @Test
+ public void testDismissSuggestion_withSmartSuggestion() {
+ assertThat(mSuggestionParser.dismissSuggestion(mSuggestion, true)).isFalse();
+ }
+
+ @Test
+ public void testGetSuggestions_withoutSmartSuggestions() {
+ readAndDismissSuggestion(false);
+ mSuggestionParser.readSuggestions(mSuggestioCategory, mSuggestionsAfterDismiss, false);
+ assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
+ assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(1);
+ assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
+ }
+
+ @Test
+ public void testGetSuggestions_withSmartSuggestions() {
+ readAndDismissSuggestion(true);
+ assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
+ assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(2);
+ assertThat(mSuggestionsBeforeDismiss).isEqualTo(mSuggestionsAfterDismiss);
+ }
+
+ private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
+ mSuggestionsBeforeDismiss = new ArrayList<Tile>();
+ mSuggestionsAfterDismiss = new ArrayList<Tile>();
+ mSuggestionParser.readSuggestions(
+ mSuggestioCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
+ if (mSuggestionParser.dismissSuggestion(
+ mSuggestionsBeforeDismiss.get(0), isSmartSuggestionEnabled)) {
+ mInfo.remove(0);
+ }
+ mSuggestionParser.readSuggestions(
+ mSuggestioCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index b209f4ec665a..40353e7489b4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -56,12 +56,11 @@ public class CategoryKeyTest {
allKeys.add(CategoryKey.CATEGORY_SECURITY);
allKeys.add(CategoryKey.CATEGORY_ACCOUNT);
allKeys.add(CategoryKey.CATEGORY_SYSTEM);
- allKeys.add(CategoryKey.CATEGORY_SYSTEM_INPUT);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
// DO NOT REMOVE ANYTHING ABOVE
- assertThat(allKeys.size()).isEqualTo(14);
+ assertThat(allKeys.size()).isEqualTo(13);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index c95cac5c8c67..16839017e03e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -34,10 +34,13 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Pair;
+import com.android.settingslib.SuggestionParser;
import com.android.settingslib.TestConfig;
+import com.android.settingslib.drawer.TileUtilsTest;
import static org.mockito.Mockito.atLeastOnce;
import org.junit.Before;
@@ -156,6 +159,32 @@ public class TileUtilsTest {
}
@Test
+ public void getTilesForIntent_shouldSkipFilteredApps() {
+ final String testCategory = "category1";
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+ URI_GET_SUMMARY);
+ addMetadataToInfo(resolveInfo, "com.android.settings.require_account", "com.google");
+ addMetadataToInfo(resolveInfo, "com.android.settings.require_connection", "true");
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */);
+
+ assertThat(outTiles.size()).isEqualTo(1);
+ SuggestionParser parser = new SuggestionParser(mContext, null);
+ parser.filterSuggestions(outTiles, 0, false);
+ assertThat(outTiles.size()).isEqualTo(0);
+ }
+
+ @Test
public void getCategories_shouldHandleExtraIntentAction() {
final String testCategory = "category1";
final String testAction = "action1";
@@ -275,16 +304,16 @@ public class TileUtilsTest {
assertThat(outTiles.get(0).summary).isEqualTo("dynamic-summary");
}
- private ResolveInfo newInfo(boolean systemApp, String category) {
+ public static ResolveInfo newInfo(boolean systemApp, String category) {
return newInfo(systemApp, category, null);
}
- private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
+ private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
return newInfo(systemApp, category, keyHint, null, null);
}
- private ResolveInfo newInfo(boolean systemApp, String category, String keyHint, String iconUri,
- String summaryUri) {
+ private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
+ String iconUri, String summaryUri) {
ResolveInfo info = new ResolveInfo();
info.system = systemApp;
info.activityInfo = new ActivityInfo();
@@ -309,4 +338,16 @@ public class TileUtilsTest {
}
return info;
}
+
+ private void addMetadataToInfo(ResolveInfo info, String key, String value) {
+ if (!TextUtils.isEmpty(key)) {
+ if (info.activityInfo == null) {
+ info.activityInfo = new ActivityInfo();
+ }
+ if (info.activityInfo.metaData == null) {
+ info.activityInfo.metaData = new Bundle();
+ }
+ info.activityInfo.metaData.putString(key, value);
+ }
+ }
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 720612726a8f..136f17e5a77c 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -38,7 +38,7 @@
<bool name="def_bluetooth_on">true</bool>
<bool name="def_wifi_display_on">false</bool>
- <bool name="def_install_non_market_apps">false</bool>
+ <bool name="def_install_non_market_apps">true</bool>
<bool name="def_package_verifier_enable">true</bool>
<!-- Comma-separated list of location providers.
Network location is off by default because it requires
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 19ce3d008643..4ddafac1aca5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -879,7 +879,7 @@ class SettingsProtoDumpUtil {
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
GlobalSettingsProto.ENABLE_EPHEMERAL_FEATURE);
dumpSetting(s, p,
- Settings.Global.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS,
+ Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
GlobalSettingsProto.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS);
dumpSetting(s, p,
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
@@ -1399,9 +1399,6 @@ class SettingsProtoDumpUtil {
Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME,
SecureSettingsProto.NIGHT_DISPLAY_CUSTOM_END_TIME);
dumpSetting(s, p,
- Settings.Secure.BRIGHTNESS_USE_TWILIGHT,
- SecureSettingsProto.BRIGHTNESS_USE_TWILIGHT);
- dumpSetting(s, p,
Settings.Secure.ENABLED_VR_LISTENERS,
SecureSettingsProto.ENABLED_VR_LISTENERS);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 697999526c23..229979489855 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -80,16 +80,20 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
+import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
@@ -178,6 +182,18 @@ public class SettingsProvider extends ContentProvider {
private static final Bundle NULL_SETTING_BUNDLE = Bundle.forPair(
Settings.NameValueTable.VALUE, null);
+ // Changes to these global settings are synchronously persisted
+ private static final Set<String> CRITICAL_GLOBAL_SETTINGS = new ArraySet<>();
+ static {
+ CRITICAL_GLOBAL_SETTINGS.add(Settings.Global.DEVICE_PROVISIONED);
+ }
+
+ // Changes to these secure settings are synchronously persisted
+ private static final Set<String> CRITICAL_SECURE_SETTINGS = new ArraySet<>();
+ static {
+ CRITICAL_SECURE_SETTINGS.add(Settings.Secure.USER_SETUP_COMPLETE);
+ }
+
// Per user secure settings that moved to the for all users global settings.
static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
static {
@@ -945,18 +961,18 @@ public class SettingsProvider extends ContentProvider {
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
- getCallingPackage(), forceNotify);
+ getCallingPackage(), forceNotify, CRITICAL_GLOBAL_SETTINGS);
}
case MUTATION_OPERATION_DELETE: {
return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_GLOBAL,
- UserHandle.USER_SYSTEM, name, forceNotify);
+ UserHandle.USER_SYSTEM, name, forceNotify, CRITICAL_GLOBAL_SETTINGS);
}
case MUTATION_OPERATION_UPDATE: {
return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
- getCallingPackage(), forceNotify);
+ getCallingPackage(), forceNotify, CRITICAL_GLOBAL_SETTINGS);
}
case MUTATION_OPERATION_RESET: {
@@ -996,7 +1012,7 @@ public class SettingsProvider extends ContentProvider {
continue;
}
- // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+ // As of Android O, the SSAID is read from an app-specific entry in table
// SETTINGS_FILE_SSAID, unless accessed by a system process.
final Setting setting;
if (isNewSsaidSetting(name)) {
@@ -1035,7 +1051,7 @@ public class SettingsProvider extends ContentProvider {
// Get the value.
synchronized (mLock) {
- // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+ // As of Android O, the SSAID is read from an app-specific entry in table
// SETTINGS_FILE_SSAID, unless accessed by a system process.
if (isNewSsaidSetting(name)) {
return getSsaidSettingLocked(owningUserId);
@@ -1152,18 +1168,18 @@ public class SettingsProvider extends ContentProvider {
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
owningUserId, name, value, tag, makeDefault,
- getCallingPackage(), forceNotify);
+ getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
}
case MUTATION_OPERATION_DELETE: {
return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SECURE,
- owningUserId, name, forceNotify);
+ owningUserId, name, forceNotify, CRITICAL_SECURE_SETTINGS);
}
case MUTATION_OPERATION_UPDATE: {
return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SECURE,
owningUserId, name, value, tag, makeDefault,
- getCallingPackage(), forceNotify);
+ getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
}
case MUTATION_OPERATION_RESET: {
@@ -1300,18 +1316,20 @@ public class SettingsProvider extends ContentProvider {
case MUTATION_OPERATION_INSERT: {
validateSystemSettingValue(name, value);
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
- owningUserId, name, value, null, false, getCallingPackage(), false);
+ owningUserId, name, value, null, false, getCallingPackage(),
+ false, null);
}
case MUTATION_OPERATION_DELETE: {
return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SYSTEM,
- owningUserId, name, false);
+ owningUserId, name, false, null);
}
case MUTATION_OPERATION_UPDATE: {
validateSystemSettingValue(name, value);
return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
- owningUserId, name, value, null, false, getCallingPackage(), false);
+ owningUserId, name, value, null, false, getCallingPackage(),
+ false, null);
}
}
@@ -1528,7 +1546,7 @@ public class SettingsProvider extends ContentProvider {
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
- if (ai.isEphemeralApp()) {
+ if (ai.isInstantApp()) {
return new ArrayList<String>(getEphemeralAccessibleSettings(settingsType));
} else {
return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
@@ -1540,7 +1558,7 @@ public class SettingsProvider extends ContentProvider {
return;
}
ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
- if (!ai.isEphemeralApp()) {
+ if (!ai.isInstantApp()) {
return;
}
if (!getEphemeralAccessibleSettings(settingsType).contains(settingName)) {
@@ -1685,7 +1703,7 @@ public class SettingsProvider extends ContentProvider {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
- tag, makeDefault, getCallingPackage(), forceNotify);
+ tag, makeDefault, getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
}
private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
@@ -1978,12 +1996,12 @@ public class SettingsProvider extends ContentProvider {
private void generateUserKeyLocked(int userId) {
// Generate a random key for each user used for creating a new ssaid.
- final byte[] keyBytes = new byte[16];
+ final byte[] keyBytes = new byte[32];
final SecureRandom rand = new SecureRandom();
rand.nextBytes(keyBytes);
// Convert to string for storage in settings table.
- final String userKey = ByteStringUtils.toString(keyBytes);
+ final String userKey = ByteStringUtils.toHexString(keyBytes);
// Store the key in the ssaid table.
final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
@@ -1995,6 +2013,10 @@ public class SettingsProvider extends ContentProvider {
}
}
+ private byte[] getLengthPrefix(byte[] data) {
+ return ByteBuffer.allocate(4).putInt(data.length).array();
+ }
+
public Setting generateSsaidLocked(String packageName, int userId) {
final PackageInfo packageInfo;
try {
@@ -2019,25 +2041,37 @@ public class SettingsProvider extends ContentProvider {
final String userKey = userKeySetting.getValue();
// Convert the user's key back to a byte array.
- final byte[] keyBytes = ByteStringUtils.toByteArray(userKey);
- if (keyBytes == null || keyBytes.length != 16) {
+ final byte[] keyBytes = ByteStringUtils.fromHexToByteArray(userKey);
+
+ // Validate that the key is of expected length.
+ // Keys are currently 32 bytes, but were once 16 bytes during Android O development.
+ if (keyBytes == null || (keyBytes.length != 16 && keyBytes.length != 32)) {
throw new IllegalStateException("User key invalid");
}
- final MessageDigest md;
+ final Mac m;
try {
- // Hash package name and signature.
- md = MessageDigest.getInstance("SHA-256");
+ m = Mac.getInstance("HmacSHA256");
+ m.init(new SecretKeySpec(keyBytes, m.getAlgorithm()));
} catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("HmacSHA256 is not available");
+ throw new IllegalStateException("HmacSHA256 is not available", e);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("Key is corrupted", e);
+ }
+
+ // Mac the package name and each of the signatures.
+ byte[] packageNameBytes = packageInfo.packageName.getBytes(StandardCharsets.UTF_8);
+ m.update(getLengthPrefix(packageNameBytes), 0, 4);
+ m.update(packageNameBytes);
+ for (int i = 0; i < packageInfo.signatures.length; i++) {
+ byte[] sig = packageInfo.signatures[i].toByteArray();
+ m.update(getLengthPrefix(sig), 0, 4);
+ m.update(sig);
}
- md.update(keyBytes);
- md.update(packageInfo.packageName.getBytes(StandardCharsets.UTF_8));
- md.update(packageInfo.signatures[0].toByteArray());
// Convert result to a string for storage in settings table. Only want first 64 bits.
- final String ssaid = ByteStringUtils.toString(md.digest()).substring(0, 16)
- .toLowerCase();
+ final String ssaid = ByteStringUtils.toHexString(m.doFinal()).substring(0, 16)
+ .toLowerCase(Locale.US);
// Save the ssaid in the ssaid table.
final String uid = Integer.toString(packageInfo.applicationInfo.uid);
@@ -2214,7 +2248,8 @@ public class SettingsProvider extends ContentProvider {
}
public boolean insertSettingLocked(int type, int userId, String name, String value,
- String tag, boolean makeDefault, String packageName, boolean forceNotify) {
+ String tag, boolean makeDefault, String packageName, boolean forceNotify,
+ Set<String> criticalSettings) {
final int key = makeKey(type, userId);
boolean success = false;
@@ -2224,13 +2259,18 @@ public class SettingsProvider extends ContentProvider {
tag, makeDefault, packageName);
}
+ if (success && criticalSettings != null && criticalSettings.contains(name)) {
+ settingsState.persistSyncLocked();
+ }
+
if (forceNotify || success) {
notifyForSettingsChange(key, name);
}
return success;
}
- public boolean deleteSettingLocked(int type, int userId, String name, boolean forceNotify) {
+ public boolean deleteSettingLocked(int type, int userId, String name, boolean forceNotify,
+ Set<String> criticalSettings) {
final int key = makeKey(type, userId);
boolean success = false;
@@ -2239,26 +2279,19 @@ public class SettingsProvider extends ContentProvider {
success = settingsState.deleteSettingLocked(name);
}
+ if (success && criticalSettings != null && criticalSettings.contains(name)) {
+ settingsState.persistSyncLocked();
+ }
+
if (forceNotify || success) {
notifyForSettingsChange(key, name);
}
return success;
}
- public Setting getSettingLocked(int type, int userId, String name) {
- final int key = makeKey(type, userId);
-
- SettingsState settingsState = peekSettingsStateLocked(key);
- if (settingsState == null) {
- return null;
- }
-
- // getSettingLocked will return non-null result
- return settingsState.getSettingLocked(name);
- }
-
public boolean updateSettingLocked(int type, int userId, String name, String value,
- String tag, boolean makeDefault, String packageName, boolean forceNotify) {
+ String tag, boolean makeDefault, String packageName, boolean forceNotify,
+ Set<String> criticalSettings) {
final int key = makeKey(type, userId);
boolean success = false;
@@ -2268,6 +2301,10 @@ public class SettingsProvider extends ContentProvider {
makeDefault, packageName);
}
+ if (success && criticalSettings != null && criticalSettings.contains(name)) {
+ settingsState.persistSyncLocked();
+ }
+
if (forceNotify || success) {
notifyForSettingsChange(key, name);
}
@@ -2275,6 +2312,18 @@ public class SettingsProvider extends ContentProvider {
return success;
}
+ public Setting getSettingLocked(int type, int userId, String name) {
+ final int key = makeKey(type, userId);
+
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ if (settingsState == null) {
+ return null;
+ }
+
+ // getSettingLocked will return non-null result
+ return settingsState.getSettingLocked(name);
+ }
+
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
final int key = makeKey(type, userId);
@@ -2286,56 +2335,78 @@ public class SettingsProvider extends ContentProvider {
switch (mode) {
case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
+ boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
if (tag != null && !tag.equals(setting.getTag())) {
continue;
}
- if (settingsState.resetSettingLocked(name, packageName)) {
+ if (settingsState.resetSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
}
+ if (someSettingChanged) {
+ settingsState.persistSyncLocked();
+ }
}
} break;
case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
+ boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (settingsState.resetSettingLocked(name, packageName)) {
+ if (settingsState.resetSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
}
+ if (someSettingChanged) {
+ settingsState.persistSyncLocked();
+ }
}
} break;
case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
for (String name : settingsState.getSettingNamesLocked()) {
+ boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
if (setting.isDefaultFromSystem()) {
- if (settingsState.resetSettingLocked(name, packageName)) {
+ if (settingsState.resetSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
} else if (settingsState.deleteSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
}
+ if (someSettingChanged) {
+ settingsState.persistSyncLocked();
+ }
}
} break;
case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
+ boolean someSettingChanged = false;
if (setting.isDefaultFromSystem()) {
- if (settingsState.resetSettingLocked(name, packageName)) {
+ if (settingsState.resetSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
} else if (settingsState.deleteSettingLocked(name)) {
+ someSettingChanged = true;
notifyForSettingsChange(key, name);
}
+ if (someSettingChanged) {
+ settingsState.persistSyncLocked();
+ }
}
} break;
}
@@ -2664,7 +2735,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 137;
+ private static final int SETTINGS_VERSION = 138;
private final int mUserId;
@@ -3116,6 +3187,18 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 137;
}
+ if (currentVersion == 137) {
+ // Version 138: Settings.Secure#INSTALL_NON_MARKET_APPS is deprecated and its
+ // default value set to 1. The user can no longer change the value of this
+ // setting through the UI.
+ final SettingsState secureSetting = getSecureSettingsLocked(userId);
+ if (!mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserHandle.of(userId))) {
+ secureSetting.insertSettingLocked(Settings.Secure.INSTALL_NON_MARKET_APPS,
+ "1", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 138;
+ }
if (currentVersion != newVersion) {
Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 2d5932492b9a..a6fadf967f9a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -113,7 +113,7 @@ final public class SettingsService extends Binder {
String mKey = null;
String mValue = null;
String mPackageName = null;
- String mToken = null;
+ String mTag = null;
int mResetMode = -1;
boolean mMakeDefault;
@@ -185,7 +185,7 @@ final public class SettingsService extends Binder {
if (peekNextArg() == null) {
valid = true;
} else {
- mToken = getNextArg();
+ mTag = getNextArg();
if (peekNextArg() == null) {
valid = true;
} else {
@@ -218,10 +218,10 @@ final public class SettingsService extends Binder {
// what we have so far is a valid command
valid = true;
// keep going; there may be another PUT arg
- } else if (mToken == null) {
- mToken = arg;
- if ("default".equalsIgnoreCase(mToken)) {
- mToken = null;
+ } else if (mTag == null) {
+ mTag = arg;
+ if ("default".equalsIgnoreCase(mTag)) {
+ mTag = null;
mMakeDefault = true;
if (peekNextArg() == null) {
valid = true;
@@ -282,7 +282,7 @@ final public class SettingsService extends Binder {
pout.println(getForUser(iprovider, mUser, mTable, mKey));
break;
case PUT:
- putForUser(iprovider, mUser, mTable, mKey, mValue, mToken, mMakeDefault);
+ putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault);
break;
case DELETE:
pout.println("Deleted "
@@ -294,7 +294,7 @@ final public class SettingsService extends Binder {
}
break;
case RESET:
- resetForUser(iprovider, mUser, mTable, mToken);
+ resetForUser(iprovider, mUser, mTable, mTag);
break;
default:
perr.println("Unspecified command");
@@ -358,7 +358,7 @@ final public class SettingsService extends Binder {
}
void putForUser(IContentProvider provider, int userHandle, final String table,
- final String key, final String value, String token, boolean makeDefault) {
+ final String key, final String value, String tag, boolean makeDefault) {
final String callPutCommand;
if ("system".equals(table)) {
callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
@@ -378,7 +378,9 @@ final public class SettingsService extends Binder {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- arg.putString(Settings.CALL_METHOD_TAG_KEY, token);
+ if (tag != null) {
+ arg.putString(Settings.CALL_METHOD_TAG_KEY, tag);
+ }
if (makeDefault) {
arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
@@ -409,7 +411,7 @@ final public class SettingsService extends Binder {
}
void resetForUser(IContentProvider provider, int userHandle,
- String table, String token) {
+ String table, String tag) {
final String callResetCommand;
if ("secure".equals(table)) callResetCommand = Settings.CALL_METHOD_RESET_SECURE;
else if ("global".equals(table)) callResetCommand = Settings.CALL_METHOD_RESET_GLOBAL;
@@ -422,7 +424,9 @@ final public class SettingsService extends Binder {
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
arg.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, mResetMode);
- arg.putString(Settings.CALL_METHOD_TAG_KEY, token);
+ if (tag != null) {
+ arg.putString(Settings.CALL_METHOD_TAG_KEY, tag);
+ }
String packageName = mPackageName != null ? mPackageName : resolveCallingPackage();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
provider.call(packageName, callResetCommand, null, arg);
@@ -465,9 +469,9 @@ final public class SettingsService extends Binder {
pw.println(" Print this help text.");
pw.println(" get [--user <USER_ID> | current] NAMESPACE KEY");
pw.println(" Retrieve the current value of KEY.");
- pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TOKEN] [default]");
+ pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default]");
pw.println(" Change the contents of KEY to VALUE.");
- pw.println(" TOKEN to associate with the setting.");
+ pw.println(" TAG to associate with the setting.");
pw.println(" {default} to set as the default, case-insensitive only for global/secure namespace");
pw.println(" delete NAMESPACE KEY");
pw.println(" Delete the entry for KEY.");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index a74be35b3f28..56ae618883b9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -64,6 +64,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* This class contains the state for one type of settings. It is responsible
@@ -129,7 +130,7 @@ final class SettingsState {
private static final String HISTORICAL_OPERATION_INITIALIZE = "initialize";
private static final String HISTORICAL_OPERATION_RESET = "reset";
- private static final String SHELL_PACKAGE_NAME = "shell";
+ private static final String SHELL_PACKAGE_NAME = "com.android.shell";
private static final String ROOT_PACKAGE_NAME = "root";
private static final String NULL_VALUE = "null";
@@ -307,7 +308,7 @@ final class SettingsState {
Setting newState;
if (oldState != null) {
- if (!oldState.update(value, makeDefault, packageName, tag)) {
+ if (!oldState.update(value, makeDefault, packageName, tag, false)) {
return false;
}
newState = oldState;
@@ -351,7 +352,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
- public boolean resetSettingLocked(String name, String packageName) {
+ public boolean resetSettingLocked(String name) {
if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
return false;
}
@@ -362,7 +363,7 @@ final class SettingsState {
String oldValue = setting.getValue();
String oldDefaultValue = setting.getDefaultValue();
- if (!setting.reset(packageName)) {
+ if (!setting.reset()) {
return false;
}
@@ -817,7 +818,7 @@ final class SettingsState {
public Setting(String name, String value, boolean makeDefault, String packageName,
String tag) {
this.name = name;
- update(value, makeDefault, packageName, tag);
+ update(value, makeDefault, packageName, tag, false);
}
public Setting(String name, String value, String defaultValue,
@@ -877,16 +878,18 @@ final class SettingsState {
}
/** @return whether the value changed */
- public boolean reset(String packageName) {
- return update(this.defaultValue, false, packageName, null);
+ public boolean reset() {
+ return update(this.defaultValue, false, packageName, null, true);
}
- public boolean update(String value, boolean setDefault, String packageName, String tag) {
+ public boolean update(String value, boolean setDefault, String packageName, String tag,
+ boolean forceNonSystemPackage) {
if (NULL_VALUE.equals(value)) {
value = null;
}
- final boolean callerSystem = !isNull() && isSystemPackage(mContext, packageName);
+ final boolean callerSystem = !forceNonSystemPackage &&
+ !isNull() && isSystemPackage(mContext, packageName);
// Settings set by the system are always defaults.
if (callerSystem) {
setDefault = true;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index 0454b5121139..ab23af39b98f 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -206,19 +206,22 @@ abstract class BaseSettingsProviderTest {
resetToDefaultsViaShell(type, packageName, null);
}
- protected static void resetToDefaultsViaShell(int type, String packageName, String token)
+ protected static void resetToDefaultsViaShell(int type, String packageName, String tag)
throws IOException {
switch (type) {
case SETTING_TYPE_GLOBAL: {
- executeShellCommand("settings reset global " + packageName + " " + token);
+ executeShellCommand("settings reset global " + packageName + " "
+ + (tag != null ? tag : ""));
} break;
case SETTING_TYPE_SECURE: {
- executeShellCommand("settings reset secure " + packageName + " " + token);
+ executeShellCommand("settings reset secure " + packageName + " "
+ + (tag != null ? tag : ""));
} break;
case SETTING_TYPE_SYSTEM: {
- executeShellCommand("settings reset system " + packageName + " " + token);
+ executeShellCommand("settings reset system " + packageName + " "
+ + (tag != null ? tag : ""));
} break;
default: {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
new file mode 100644
index 000000000000..51e43738b537
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.SystemClock;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+
+@LargeTest
+public class InstallNonMarketAppsDeprecationTest extends BaseSettingsProviderTest {
+
+ private static final String TAG = InstallNonMarketAppsDeprecationTest.class.getSimpleName();
+ private static final long USER_RESTRICTION_CHANGE_TIMEOUT = 5000;
+
+ private UserManager mUm;
+ private boolean mHasUserRestriction;
+ private List<UserInfo> mCurrentUsers;
+
+ private String waitTillValueChanges(String errorMessage, String oldValue) {
+ boolean interrupted = false;
+ final long startTime = SystemClock.uptimeMillis();
+ String newValue = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+ while (newValue.equals(oldValue) && SystemClock.uptimeMillis() <= (startTime
+ + USER_RESTRICTION_CHANGE_TIMEOUT)) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException exc) {
+ interrupted = true;
+ }
+ newValue = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ assertFalse(errorMessage, oldValue.equals(newValue));
+ return newValue;
+ }
+
+ private String getSecureSettingForUserViaShell(int userId) throws IOException {
+ StringBuilder sb = new StringBuilder("settings get --user ");
+ sb.append(userId + " secure ");
+ sb.append(Settings.Secure.INSTALL_NON_MARKET_APPS);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ sb.toString()).getFileDescriptor())));
+ String line = reader.readLine();
+ return line.trim();
+ }
+
+ @Before
+ public void setUp() {
+ mUm = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+ mHasUserRestriction = mUm.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+ mCurrentUsers = mUm.getUsers();
+ }
+
+ @Test
+ public void testValueDefaults() throws Exception {
+ if (mHasUserRestriction) {
+ // Default values don't apply when user restriction is set. Pass.
+ Log.w(TAG, "User restriction for unknown sources set. Skipping testValueDefaults test");
+ return;
+ }
+ String value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+ assertEquals("install_non_market_apps should be 1", value, "1");
+
+ setSettingViaShell(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS, "0",
+ false);
+ resetSettingsViaShell(SETTING_TYPE_SECURE, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+ assertEquals("install_non_market_apps not reset to 1", value, "1");
+ }
+
+ @Test
+ public void testValueForNewUser() throws Exception {
+ UserInfo newUser = mUm.createUser("TEST_USER", 0);
+ String value = getSecureSettingForUserViaShell(newUser.id);
+ assertEquals("install_non_market_apps should be 1 for a new user", value, "1");
+ }
+
+ @Test
+ public void testValueRespectsUserRestriction() {
+ String value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+ assertEquals(value, mHasUserRestriction ? "0" : "1");
+
+ mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, !mHasUserRestriction);
+ value = waitTillValueChanges(
+ "Changing user restriction did not change the value of install_non_market_apps",
+ value);
+ assertTrue("Invalid value", value.equals("1") || value.equals("0"));
+
+ mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, mHasUserRestriction);
+ value = waitTillValueChanges(
+ "Changing user restriction did not change the value of install_non_market_apps",
+ value);
+ assertTrue("Invalid value", value.equals("1") || value.equals("0"));
+ }
+
+ @After
+ public void tearDown() {
+ if (mUm.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
+ != mHasUserRestriction) {
+ mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ mHasUserRestriction);
+ }
+ mUm.getUsers().forEach(user -> {
+ if (!mCurrentUsers.contains(user)) {
+ mUm.removeUser(user.id);
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f72d091607ac..4b8734fd1816 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -500,7 +500,6 @@
android:label="@string/accessibility_desc_work_lock"
android:permission="android.permission.MANAGE_USERS"
android:exported="false"
- android:launchMode="singleTop"
android:excludeFromRecents="true"
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
index b31b199376de..e75ecb7a127b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
@@ -64,7 +64,7 @@ import android.content.Context;
* new PluginListener<OverlayPlugin>() {
* @Override
* public void onPluginConnected(OverlayPlugin plugin) {
- * PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
+ * StatusBar phoneStatusBar = getComponent(StatusBar.class);
* if (phoneStatusBar != null) {
* plugin.setup(phoneStatusBar.getStatusBarWindow(),
* phoneStatusBar.getNavigationBarView());
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 9f44bd4bc331..dd1614b50ca6 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -307,14 +307,14 @@ public class PluginInstanceManager<T extends Plugin> {
mContext.getPackageName());
final int color = Resources.getSystem().getIdentifier(
"system_notification_accent_color", "color", "android");
- final Notification.Builder nb = new Notification.Builder(mContext)
- .setStyle(new Notification.BigTextStyle())
- .setSmallIcon(icon)
- .setWhen(0)
- .setShowWhen(false)
- .setPriority(Notification.PRIORITY_MAX)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(color));
+ final Notification.Builder nb = new Notification.Builder(mContext,
+ PluginManager.NOTIFICATION_CHANNEL_ID)
+ .setStyle(new Notification.BigTextStyle())
+ .setSmallIcon(icon)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(mContext.getColor(color));
String label = cls;
try {
label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index 471454749c2f..cef485e673ad 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -55,6 +55,9 @@ public class PluginManager extends BroadcastReceiver {
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
+ // must be one of the channels created in NotificationChannels.java
+ static final String NOTIFICATION_CHANNEL_ID = "ALR";
+
private static PluginManager sInstance;
private final HandlerThread mBackgroundThread;
@@ -70,7 +73,7 @@ public class PluginManager extends BroadcastReceiver {
private boolean mListening;
private boolean mHasOneShot;
- private PluginManager(Context context) {
+ public PluginManager(Context context) {
this(context, new PluginInstanceManagerFactory(),
Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
}
@@ -191,15 +194,16 @@ public class PluginManager extends BroadcastReceiver {
} catch (NameNotFoundException e) {
}
// Localization not required as this will never ever appear in a user build.
- final Notification.Builder nb = new Notification.Builder(mContext)
- .setSmallIcon(icon)
- .setWhen(0)
- .setShowWhen(false)
- .setPriority(Notification.PRIORITY_MAX)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(color))
- .setContentTitle("Plugin \"" + label + "\" has updated")
- .setContentText("Restart SysUI for changes to take effect.");
+ final Notification.Builder nb =
+ new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(icon)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(mContext.getColor(color))
+ .setContentTitle("Plugin \"" + label + "\" has updated")
+ .setContentText("Restart SysUI for changes to take effect.");
Intent i = new Intent("com.android.systemui.action.RESTART").setData(
Uri.parse("package://" + pkg));
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
@@ -252,13 +256,6 @@ public class PluginManager extends BroadcastReceiver {
return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
}
- public static PluginManager getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new PluginManager(context.getApplicationContext());
- }
- return sInstance;
- }
-
private class AllPluginClassLoader extends ClassLoader {
public AllPluginClassLoader(ClassLoader classLoader) {
super(classLoader);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
new file mode 100644
index 000000000000..93ba39cbba9d
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
@@ -0,0 +1,90 @@
+
+package com.android.systemui.plugins.statusbar;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+import java.util.ArrayList;
+
+import com.android.systemui.plugins.Plugin;
+
+public interface NotificationMenuRowProvider extends Plugin {
+
+ public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
+
+ public static final int VERSION = 1;
+
+ /**
+ * Returns a list of items to populate the menu 'behind' a notification.
+ */
+ public ArrayList<MenuItem> getMenuItems(Context context);
+
+ public interface OnMenuClickListener {
+ public void onMenuClicked(View row, int x, int y, MenuItem menu);
+
+ public void onMenuReset(View row);
+ }
+
+ public interface GutsInteractionListener {
+ public void onInteraction(View view);
+
+ public void closeGuts(View view);
+ }
+
+ public interface GutsContent {
+ public void setInteractionListener(GutsInteractionListener listener);
+
+ public View getContentView();
+
+ public boolean handleCloseControls();
+ }
+
+ public interface SnoozeGutsContent extends GutsContent {
+ public void setSnoozeListener(SnoozeListener listener);
+
+ public void setStatusBarNotification(StatusBarNotification sbn);
+ }
+
+ public interface SnoozeListener {
+ public void snoozeNotification(StatusBarNotification sbn, SnoozeOption snoozeOption);
+ }
+
+ public static class MenuItem {
+ public Drawable icon;
+ public String menuDescription;
+ public View menuView;
+ public GutsContent gutsContent;
+
+ public MenuItem(Drawable i, String s, GutsContent content) {
+ icon = i;
+ menuDescription = s;
+ gutsContent = content;
+ }
+
+ public View getGutsView() {
+ return gutsContent.getContentView();
+ }
+
+ public boolean onTouch(View v, int x, int y) {
+ return false;
+ }
+ }
+
+ public static class SnoozeOption {
+ public SnoozeCriterion criterion;
+ public int snoozeForMinutes;
+ public CharSequence description;
+ public CharSequence confirmation;
+
+ public SnoozeOption(SnoozeCriterion crit, int minsToSnoozeFor, CharSequence desc,
+ CharSequence confirm) {
+ criterion = crit;
+ snoozeForMinutes = minsToSnoozeFor;
+ description = desc;
+ confirmation = confirm;
+ }
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index 072848263a9b..918d6e96784d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -32,6 +32,8 @@ public interface NavGesture extends Plugin {
public boolean onInterceptTouchEvent(MotionEvent event);
public void setBarState(boolean vertical, boolean isRtl);
+
+ public default void destroy() { }
}
}
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 364885a2d6eb..8cc2ce260066 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -11,7 +11,7 @@
}
-keep class com.android.systemui.statusbar.car.CarStatusBar
--keep class com.android.systemui.statusbar.phone.PhoneStatusBar
+-keep class com.android.systemui.statusbar.phone.StatusBar
-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
-keep class com.android.systemui.SystemUIFactory
@@ -38,5 +38,5 @@
-keep class ** extends android.support.v14.preference.PreferenceFragment
-keep class com.android.systemui.tuner.*
-keep class com.android.systemui.plugins.** {
- public protected **;
+ public protected *;
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 000000000000..0615668b6465
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 000000000000..839e5edeead3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 000000000000..1480c865e2dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 000000000000..66e11fb52b30
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 5e08fcbf8f52..abafb689f169 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2016 The Android Open Source Project
+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.
@@ -19,20 +19,22 @@ Copyright (C) 2016 The Android Open Source Project
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#00796B"
- android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
+ android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0"
+ android:fillAlpha="0.066"
+ android:fillColor="#000000"/>
<path
- android:fillColor="#00796B"
- android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
+ android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0"
+ android:fillColor="#FFC107"/>
<path
- android:fillColor="#40000000"
- android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
+ android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z"
+ android:fillColor="#FE9F00"/>
<path
- android:fillColor="#40000000"
- android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
+ android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0"
+ android:fillColor="#FED44F"/>
<path
- android:fillColor="#4DB6AC"
- android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
+ android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z"
+ android:fillColor="#FFC107"/>
+ <path
+ android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0"
+ android:fillColor="#FFFFFF"/>
</vector>
-
-
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 000000000000..d2fe0c32cad3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 000000000000..5923269a882b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 000000000000..d0196e5f8ea3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 000000000000..d3a2b393e685
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 000000000000..726643ca1bb1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 000000000000..31078f6aa42c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_left.xml b/packages/SystemUI/res/drawable/ic_left.xml
new file mode 100644
index 000000000000..cea4cfcb13ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_left.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:fillColor="#FF000000"
+ android:pathData="M15.41,16.09l-4.58,-4.59 4.58,-4.59L14.0,5.5l-6.0,6.0 6.0,6.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_menu.xml b/packages/SystemUI/res/drawable/ic_menu.xml
new file mode 100644
index 000000000000..994bc5e4f12e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_menu.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:fillColor="#FF000000"
+ android:pathData="M3.0,18.0l18.0,0.0l0.0,-2.0L3.0,16.0l0.0,2.0zm0.0,-5.0l18.0,0.0l0.0,-2.0L3.0,11.0l0.0,2.0zm0.0,-7.0l0.0,2.0l18.0,0.0L21.0,6.0L3.0,6.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
index 439ee3bc60d0..6264484a74d8 100644
--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
@@ -16,8 +16,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="17.0dp"
- android:viewportWidth="20.0"
- android:viewportHeight="20.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml b/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
deleted file mode 100644
index 40bfbe694cca..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32dp"
- android:viewportWidth="6.0"
- android:viewportHeight="6.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_remove.xml b/packages/SystemUI/res/drawable/ic_remove.xml
new file mode 100644
index 000000000000..75b27930842c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_remove.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:fillColor="#FF000000"
+ android:pathData="M19.0,13.0L5.0,13.0l0.0,-2.0l14.0,0.0l0.0,2.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_right.xml b/packages/SystemUI/res/drawable/ic_right.xml
new file mode 100644
index 000000000000..35699f733749
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_right.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:fillColor="#FF000000"
+ android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10.0,5.75l6.0,6.0 -6.0,6.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_snooze.xml b/packages/SystemUI/res/drawable/ic_snooze.xml
new file mode 100644
index 000000000000..b0b03a99f4a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_snooze.xml
@@ -0,0 +1,12 @@
+<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="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"
+ android:fillColor="#757575"/>
+ <path
+ android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"
+ android:fillColor="#757575"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/pip_dismiss_background.xml b/packages/SystemUI/res/drawable/pip_dismiss_background.xml
index 3a7529686dfb..8f502318ae14 100644
--- a/packages/SystemUI/res/drawable/pip_dismiss_background.xml
+++ b/packages/SystemUI/res/drawable/pip_dismiss_background.xml
@@ -1,22 +1,22 @@
<!--
-Copyright (C) 2016 The Android Open Source Project
+ 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
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this 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,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <corners
- android:radius="100dp" />
- <solid
- android:color="#66000000" />
+ android:shape="rectangle">
+ <gradient
+ android:startColor="#B3000000"
+ android:endColor="#00000000"
+ android:angle="90"/>
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
index ea03a50e4460..4987f9bcf610 100644
--- a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
+++ b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
@@ -15,5 +15,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#61FFFFFF" />
- <corners android:radius="@dimen/recents_grid_task_view_rounded_corners_radius"/>
+ <corners android:radius="@dimen/recents_grid_task_view_focused_frame_rounded_corners_radius"/>
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
index 694019e98867..ea794d47312f 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
@@ -14,9 +14,10 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="8.5dp"
+ android:autoMirrored="true"
+ android:width="17.0dp"
android:height="17.0dp"
- android:viewportWidth="20.0"
+ android:viewportWidth="40.0"
android:viewportHeight="40.0">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
index 363e231cf03c..4baa472acb88 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
@@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="4.25dp"
+ android:width="8.5dp"
android:height="17dp"
android:viewportWidth="6.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="12.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/>
diff --git a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
deleted file mode 100644
index a430b73d40f8..000000000000
--- a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?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.
--->
-<LinearLayout
- 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:orientation="horizontal">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:elevation="4dp"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:background="@android:color/white"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/preview"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:textColor="?android:attr/colorAccent"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <FrameLayout
- android:id="@+id/nav_preview_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <android.support.v7.widget.RecyclerView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
deleted file mode 100644
index 5479157c5bcd..000000000000
--- a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?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.
--->
-<LinearLayout
- 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:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:elevation="4dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:layout_gravity="bottom"
- android:background="@android:color/white"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/preview"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textColor="?android:attr/colorAccent"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <FrameLayout
- android:id="@+id/nav_preview_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <android.support.v7.widget.RecyclerView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/data_usage.xml b/packages/SystemUI/res/layout/data_usage.xml
index c943f3d2a616..fdc6f146f93f 100644
--- a/packages/SystemUI/res/layout/data_usage.xml
+++ b/packages/SystemUI/res/layout/data_usage.xml
@@ -59,6 +59,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.QS.DataUsage" />
+
</LinearLayout>
<LinearLayout
@@ -82,4 +83,13 @@
android:textAppearance="@style/TextAppearance.QS.DataUsage.Secondary" />
</LinearLayout>
-</com.android.systemui.qs.tiles.DataUsageDetailView> \ No newline at end of file
+ <TextView
+ android:id="@+id/roaming_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:text="@string/accessibility_data_connection_roaming"
+ android:textAppearance="@style/TextAppearance.QS.DataUsage.Secondary"
+ android:visibility="gone" />
+
+</com.android.systemui.qs.tiles.DataUsageDetailView>
diff --git a/packages/SystemUI/res/layout/divider.xml b/packages/SystemUI/res/layout/divider.xml
new file mode 100644
index 000000000000..95814371ed56
--- /dev/null
+++ b/packages/SystemUI/res/layout/divider.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="72dp"
+ android:layout_height="1dp"
+ android:background="?android:attr/colorForeground"
+ android:alpha="?android:attr/disabledAlpha" />
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 5e85ba06beea..6bd79a4b4ae4 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -39,4 +39,13 @@
android:contentDescription="@string/accessibility_ime_switch_button"
android:scaleType="centerInside"
/>
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/accessibility_button"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_accessibility_button"
+ android:scaleType="centerInside"
+ />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index a20ec8e7623d..8b1007497468 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -43,4 +43,15 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
+ <ImageView
+ android:id="@+id/mobile_roaming"
+ android:layout_width="wrap_content"
+ android:layout_height="17dp"
+ android:paddingStart="22dp"
+ android:paddingTop="1.5dp"
+ android:paddingBottom="3dp"
+ android:scaleType="fitCenter"
+ android:src="@drawable/stat_sys_roaming"
+ android:contentDescription="@string/accessibility_data_connection_roaming"
+ android:visibility="gone" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner.xml b/packages/SystemUI/res/layout/nav_bar_tuner.xml
deleted file mode 100644
index 5479157c5bcd..000000000000
--- a/packages/SystemUI/res/layout/nav_bar_tuner.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?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.
--->
-<LinearLayout
- 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:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:elevation="4dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:layout_gravity="bottom"
- android:background="@android:color/white"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/preview"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textColor="?android:attr/colorAccent"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <FrameLayout
- android:id="@+id/nav_preview_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <android.support.v7.widget.RecyclerView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 3948dc4b8771..9d8ef83ab7e6 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -23,125 +23,4 @@
android:visibility="gone"
android:clickable="true"
android:gravity="top|start"
- android:orientation="vertical"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingEnd="8dp"
- android:background="@color/notification_guts_bg_color"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
-
- <!-- header -->
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="20dp"
- android:paddingEnd="8dp"
- android:paddingBottom="15dp"
- android:id="@+id/notification_guts_header">
- <TextView
- android:id="@+id/pkgname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- style="@style/TextAppearance.NotificationGuts.Secondary" />
- <TextView
- android:id="@+id/channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_below="@id/pkgname"
- style="@style/TextAppearance.NotificationGuts.Header" />
- <Switch
- android:id="@+id/channel_enabled_switch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="@null" />
- </RelativeLayout>
- <!-- Importance radio buttons -->
- <LinearLayout
- android:id="@+id/importance"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <RadioGroup
- android:id="@+id/importance_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="@*android:dimen/notification_content_margin_end">
- <RadioButton
- android:id="@+id/high_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/default_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/low_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/min_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- </RadioGroup>
- <LinearLayout
- android:id="@+id/importance_buttons_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- </LinearLayout>
- </LinearLayout>
- <!-- Channel Disabled Text -->
- <TextView
- android:id="@+id/channel_disabled"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationGuts.Secondary" />
- <!-- Settings and Done buttons -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:paddingTop="16dp"
- android:paddingBottom="8dp" >
-
- <TextView
- android:id="@+id/more_settings"
- android:text="@string/notification_more_settings"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- style="@style/TextAppearance.NotificationGuts.Button"
- android:background="@drawable/btn_borderless_rect"
- android:gravity="center"
- android:paddingEnd="8dp"
- android:paddingStart="8dp"
- android:focusable="true" />
-
- <TextView
- android:id="@+id/done"
- android:text="@string/notification_done"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- style="@style/TextAppearance.NotificationGuts.Button"
- android:background="@drawable/btn_borderless_rect"
- android:gravity="center"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:focusable="true"/>
- </LinearLayout>
-</com.android.systemui.statusbar.NotificationGuts>
+ android:theme="@*android:style/Theme.DeviceDefault.Light"/>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
new file mode 100644
index 000000000000..9770eccfd2c1
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -0,0 +1,146 @@
+<?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.
+-->
+
+<com.android.systemui.statusbar.NotificationInfo
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/notification_guts"
+ android:clickable="true"
+ android:gravity="top|start"
+ android:orientation="vertical"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingEnd="8dp"
+ android:background="@color/notification_guts_bg_color"
+ android:theme="@*android:style/Theme.DeviceDefault.Light">
+
+ <!-- header -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="20dp"
+ android:paddingEnd="8dp"
+ android:paddingBottom="15dp"
+ android:id="@+id/notification_guts_header">
+ <TextView
+ android:id="@+id/pkgname"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ style="@style/TextAppearance.NotificationGuts.Secondary" />
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/pkgname"
+ style="@style/TextAppearance.NotificationGuts.Header" />
+ <Switch
+ android:id="@+id/channel_enabled_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="@null" />
+ </RelativeLayout>
+ <!-- Importance radio buttons -->
+ <LinearLayout
+ android:id="@+id/importance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioGroup
+ android:id="@+id/importance_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end">
+ <RadioButton
+ android:id="@+id/high_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/default_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/low_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/min_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ </RadioGroup>
+ <LinearLayout
+ android:id="@+id/importance_buttons_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ </LinearLayout>
+ </LinearLayout>
+ <!-- Channel Disabled Text -->
+ <TextView
+ android:id="@+id/channel_disabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_channel_disabled"
+ style="@style/TextAppearance.NotificationGuts.Secondary" />
+ <!-- Settings and Done buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp" >
+
+ <TextView
+ android:id="@+id/more_settings"
+ android:text="@string/notification_more_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:paddingEnd="8dp"
+ android:paddingStart="8dp"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/notification_done"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:focusable="true"/>
+ </LinearLayout>
+</com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_menu_row.xml
index da3461b906fa..12bcf8176561 100644
--- a/packages/SystemUI/res/layout/notification_settings_icon_row.xml
+++ b/packages/SystemUI/res/layout/notification_menu_row.xml
@@ -14,23 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.statusbar.NotificationSettingsIconRow
+<com.android.systemui.statusbar.NotificationMenuRow
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:visibility="invisible"
- >
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/gear_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/notification_gear_padding"
- android:src="@drawable/ic_settings"
- android:tint="@color/notification_gear_color"
- android:alpha="0"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- />
-
-</com.android.systemui.statusbar.NotificationSettingsIconRow> \ No newline at end of file
+ android:visibility="invisible"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
new file mode 100644
index 000000000000..5bd64defd2d1
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -0,0 +1,65 @@
+<?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.
+-->
+
+<com.android.systemui.statusbar.NotificationSnooze
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/snooze_snackbar_min_height"
+ android:id="@+id/notification_snooze"
+ android:clickable="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:background="@color/snooze_snackbar_bg">
+
+ <TextView
+ android:id="@+id/snooze_option_default"
+ style="@style/TextAppearance.SnoozeSnackBar"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:drawableTint="@android:color/white"
+ android:drawableEnd="@drawable/notification_expand_more"/>
+
+ <android.widget.Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+
+ <TextView
+ android:id="@+id/undo"
+ style="@style/TextAppearance.SnoozeSnackBar.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:background="@drawable/btn_borderless_rect"
+ android:layout_gravity="end"
+ android:text="@string/snooze_undo" />
+
+ <LinearLayout
+ android:id="@+id/snooze_options"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical"/>
+
+</com.android.systemui.statusbar.NotificationSnooze>
diff --git a/packages/SystemUI/res/layout/pip_dismiss_view.xml b/packages/SystemUI/res/layout/pip_dismiss_view.xml
index 141e610d2294..f02a56cd5f81 100644
--- a/packages/SystemUI/res/layout/pip_dismiss_view.xml
+++ b/packages/SystemUI/res/layout/pip_dismiss_view.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
@@ -13,12 +14,44 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pip_dismiss_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/pip_dismiss_background"
- android:foreground="@drawable/pip_dismiss"
- android:alpha="0"
- android:forceHasOverlappingRendering="false" />
+ android:alpha="0">
+
+ <!-- The height of the below view needs to be animated from a window
+ so it needs to be in a container to resize smoothly -->
+ <View
+ android:id="@+id/gradient_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="bottom"
+ android:background="@drawable/pip_dismiss_background" />
+
+ <LinearLayout
+ android:id="@+id/pip_dismiss_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:orientation="horizontal"
+ android:paddingBottom="32dp" >
+
+ <ImageView
+ android:id="@+id/pip_dismiss_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:padding="2dp"
+ android:src="@drawable/pip_dismiss"
+ android:tint="#FFFFFFFF" />
+
+ <TextView
+ android:id="@+id/pip_dismiss_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/pip_phone_close"
+ android:textColor="#FFFFFFFF"
+ android:textSize="16sp" />
+ </LinearLayout>
+
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index cf65f4aa830b..0f5ca9bdf2fc 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -27,7 +27,7 @@
android:layout_height="48dp"
android:layout_gravity="top|end"
android:padding="10dp"
- android:contentDescription="@string/pip_phone_dismiss"
+ android:contentDescription="@string/pip_phone_close"
android:src="@drawable/ic_close_white"
android:background="?android:selectableItemBackgroundBorderless" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 4122707de740..3e8e72a3d100 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -2,23 +2,22 @@
<!--
** Copyright 2012, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this 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,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 RelativeLayout -->
<com.android.systemui.statusbar.phone.QuickStatusBarHeader
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_header_height"
@@ -29,8 +28,7 @@
android:clipToPadding="false"
android:paddingTop="0dp"
android:paddingEnd="0dp"
- android:paddingStart="0dp"
- >
+ android:paddingStart="0dp">
<LinearLayout
android:layout_width="wrap_content"
@@ -148,7 +146,7 @@
android:layout_alignParentTop="true"
android:focusable="true"
android:gravity="center_vertical"
- android:paddingEnd="16dp"
+ android:paddingStart="16dp"
android:paddingTop="6dp"
android:singleLine="true"
android:text="@*android:string/emergency_calls_only"
@@ -190,8 +188,7 @@
android:layout_alignParentBottom="true"
android:alpha="0"
android:background="@color/qs_detail_progress_track"
- android:src="@drawable/indeterminate_anim"
- />
+ android:src="@drawable/indeterminate_anim"/>
<TextView
android:id="@+id/header_debug_info"
@@ -203,7 +200,6 @@
android:textColor="#00A040"
android:textSize="11dp"
android:textStyle="bold"
- android:visibility="invisible"
- />
+ android:visibility="invisible"/>
</com.android.systemui.statusbar.phone.QuickStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index f09657f9e486..0852020e779c 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -3,28 +3,27 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this 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,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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.phone.NotificationPanelView
+<com.android.systemui.statusbar.phone.NotificationPanelView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/notification_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@android:color/transparent"
- >
+ android:background="@android:color/transparent" >
<include
layout="@layout/keyguard_status_view"
@@ -77,8 +76,8 @@
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
<include
- layout="@layout/keyguard_bottom_area"
- android:visibility="gone" />
+ layout="@layout/keyguard_bottom_area"
+ android:visibility="gone" />
<com.android.systemui.statusbar.AlphaOptimizedView
android:id="@+id/qs_navbar_scrim"
@@ -88,4 +87,4 @@
android:visibility="invisible"
android:background="@drawable/qs_navbar_scrim" />
-</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
+</com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index e456984c5f36..d62cc184889c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -24,10 +24,10 @@
>
<ViewStub
- android:layout="@layout/notification_settings_icon_row"
- android:id="@+id/settings_icon_row_stub"
- android:inflatedId="@+id/notification_settings_icon_row"
- android:layout_width="wrap_content"
+ android:layout="@layout/notification_menu_row"
+ android:id="@+id/menu_row_stub"
+ android:inflatedId="@+id/notification_menu_row"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
/>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 285a8ec34abc..c2686f88a11f 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -48,6 +48,7 @@
android:layout_height="match_parent"
android:importantForAccessibility="no"
sysui:ignoreRightInset="true"
+ sysui:scrimColor="@color/scrim_behind_color"
/>
<com.android.systemui.statusbar.AlphaOptimizedView
@@ -72,7 +73,7 @@
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="gone" />
+ android:visibility="invisible" />
<com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/tuner_shortcut_item.xml b/packages/SystemUI/res/layout/tuner_shortcut_item.xml
new file mode 100644
index 000000000000..e9eae3b0e1d6
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_shortcut_item.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
+ android:clickable="true"
+ android:gravity="center"
+ android:background="?android:attr/selectableItemBackground">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="12dp" />
+
+ <TextView android:id="@android:id/title"
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <com.android.systemui.statusbar.phone.ExpandableIndicator
+ android:id="@+id/expand"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="12dp"
+ android:visibility="gone" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tuner_shortcut_list.xml b/packages/SystemUI/res/layout/tuner_shortcut_list.xml
new file mode 100644
index 000000000000..9aaffb49e652
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_shortcut_list.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<android.support.v7.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="200dp"
+ android:gravity="center" />
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9744eb30059b..e647adee4412 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Aandbeligting"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is gedeaktiveer"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is geaktiveer"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Geen onlangse items nie"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Jy het alles toegemaak"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Verdeel skerm na bo"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Verdeel skerm na links"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Verdeel skerm na regs"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Ontkoppel VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Jou toestel word bestuur deur <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> gebruik <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> om jou toestel te bestuur."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Jou admin kan instellings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word en jou toestel se ligginginligting monitor en bestuur."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Kom meer te wete"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Jy is gekoppel aan <xliff:g id="VPN_APP">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Maak VPN-instellings oop"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Jou administrateur het netwerkloglêers aangeskakel wat verkeer op jou toestel monitor.\n\nKontak jou administrateur vir meer inligting."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Jy het \'n program toestemming gegee om \'n VPN-verbinding op te stel.\n\nHierdie program kan jou toestel- en netwerkaktiwiteit monitor, insluitend e-posse, programme en webwerwe."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur.\n\nJou administrateur kan jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, bestuur.\n\nKontak jou administrateur vir meer inligting.\n\nJy is ook aan \'n VPN gekoppel, wat jou netwerkaktiwiteit kan monitor."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g> wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nKontak jou administrateur vir meer inligting."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Toestel sal gesluit bly totdat jy dit handmatig ontsluit"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Kry kennisgewings vinniger"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Maak geluid en spring op op skerm"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
<string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewingkontroles"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kennisgewingkontroles"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"kennisgewing-sluimeropsies"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minute"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minute"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 uur"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Moenie sluimer nie"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ONTDOEN"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Sluimer vir <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batterygebruik"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterybespaarder is nie beskikbaar wanneer gelaai word nie"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterybespaarder"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aan"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Af"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigasiebalk"</string>
- <string name="start" msgid="6873794757232879664">"Begin"</string>
- <string name="center" msgid="4327473927066010960">"Middel"</string>
- <string name="end" msgid="125797972524818282">"Einde"</string>
- <string name="space" msgid="804232271282109749">"Spasieerder"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Uitleg"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Links"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Regs"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Soort knoppie"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(verstek)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Knipbord"</item>
+ <item msgid="5742013440802239414">"Sleutelkode"</item>
+ <item msgid="8748101184830239843">"Kieslys / Sleutelbordwisselaar"</item>
+ <item msgid="8175437057325747277">"Geen"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Verdeel (verstek)"</item>
+ <item msgid="6210279084134579668">"Gesentreer"</item>
+ <item msgid="89143234390889289">"Linksbelyn"</item>
+ <item msgid="7715533883382410603">"Regsbelyn"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Kieslys / Sleutelbordwisselaar"</string>
- <string name="select_button" msgid="1597989540662710653">"Kies knoppie om by te voeg"</string>
- <string name="add_button" msgid="4134946063432258161">"Voeg knoppie by"</string>
<string name="save" msgid="2311877285724540644">"Stoor"</string>
<string name="reset" msgid="2448168080964209908">"Stel terug"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Geen tuisknoppie is gevind nie"</string>
- <string name="no_home_message" msgid="5408485011659260911">"\'n Tuisknoppie word vereis sodat daar op hierdie toestel genavigeer kan word. Voeg asseblief \'n tuisknoppie by voordat jy stoor."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Verstel knoppiebreedte"</string>
<string name="clipboard" msgid="1313879395099896312">"Knipbord"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Die knipbord laat toe dat items direk na die knipbord getrek word. Items kan ook direk vanaf die knipbord getrek word, indien dit daar is."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Gepasmaakte navigasieknoppie"</string>
<string name="keycode" msgid="7335281375728356499">"Sleutelkode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Sleutelbordknoppies maak dit moontlik dat sleutelbordsleutels by die navigasiebalk gevoeg kan word. Wanneer hulle gedruk word, doen hulle dieselfde as die gekose sleutelbordsleutel. Eers moet die sleutel vir die knoppie gekies word, gevolg deur \'n prent wat op die knoppie gewys sal word."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Kies Sleutelbordknoppie"</string>
- <string name="preview" msgid="9077832302472282938">"Voorskou"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikoon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om teëls by te voeg"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hierheen om te verwyder"</string>
<string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeer"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Maak toe"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Foon raak warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Sommige kenmerke is beperk terwyl foon afkoel"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Links"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Regs"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Pasmaak kortpad"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Kortpad"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Aanporboodskap vir wagwoord"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Opletberigte"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skermkiekies"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Algemene boodskappe"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Berging"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index b3354f1ce676..392cd0171af7 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"የሥራ ሁነታ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"የምሽት ብርሃን"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"ኤንኤፍሲ"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"ኤንኤፍሲ ተሰናክሏል"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"ኤንኤፍሲ ነቅቷል"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ሁሉንም ነገር አጽድተዋል"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ማያ ገጽ ወደ ላይ ክፈል"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ማያ ገጽ ወደ ግራ ክፈል"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ማያ ገጽ ወደ ቀኝ ክፈል"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"የVPN ግንኙነት አቋርጥ"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"የእርስዎ መሣሪያ በ<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ነው የሚቀናበረው።"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> የእርስዎን መሣሪያ ለማቀናበር <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ን ይጠቀማል።"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"የእርስዎ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከዚህ መሣሪያ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎን አካባቢ መከታተል እና ማቀናበር ይችላሉ።"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"የበለጠ ለመረዳት"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="VPN_APP">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"የVPN ቅንብሮችን ይክፈቱ"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"የእርስዎ አስተዳዳሪ የአውታረ መረብ ምዝግብ ማስታወሻ መያዝን አብርተዋል፣ ይህም በመሣሪያዎ ላይ ያለውን ትራፊክ ይከታተላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"አንድ መተግበሪያ የVPN ግንኙነት እንዲያዋቅር ፍቃድ ሰጥተውታል።\n\nይህ መተግበሪያ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የመሣሪያዎን እና የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"የእርስዎ የስራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚቀናበረው።\n\nየእርስዎ አስተዳዳሪ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።\n\nእርስዎ እንዲሁም የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችል ቪፒኤን ጋር ተገናኝተዋል።"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"የእርስዎ የስራ መገለጫ በ<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="4946600443852045903">"የስራ መገለጫዎ በ<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_disabled" msgid="7412534203633528135">"እራስዎ እስኪከፍቱት ድረስ መሣሪያ እንደተቆለፈ ይቆያል"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ማሳወቂያዎችን ፈጥነው ያግኙ"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ድምፅ ፍጠር እና በማያ ገጽ ላይ ብቅ በል"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
<string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያ ቁጥጥሮች"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"የማሳወቂያ መቆጣጠሪያዎች"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"የማሳወቂያ ማሸለቢያ አማራጮች"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 ደቂቃዎች"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 ደቂቃዎች"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ሰዓት"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"አታሸልብ"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ቀልብስ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"ለ<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> አሸልቧል"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"የባትሪ አጠቃቀም"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ አይገኝም"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ባትሪ ቆጣቢ"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"በርቷል"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ጠፍቷል"</string>
<string name="nav_bar" msgid="1993221402773877607">"የአሰሳ አሞሌ"</string>
- <string name="start" msgid="6873794757232879664">"ጀምር"</string>
- <string name="center" msgid="4327473927066010960">"መሃል"</string>
- <string name="end" msgid="125797972524818282">"መጨረሻ"</string>
- <string name="space" msgid="804232271282109749">"ክፍተት ሰጪ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"አቀማመጥ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ግራ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ቀኝ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"የአዝራር አይነት"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ነባሪ)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"የቅንጥብ ሰሌዳ"</item>
+ <item msgid="5742013440802239414">"የቁልፍ ኮድ"</item>
+ <item msgid="8748101184830239843">"ምናሌ / የቁልፍ ሰሌዳ መቀየሪያ"</item>
+ <item msgid="8175437057325747277">"ምንም የለም"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"የተከፈለ (ነባሪ)"</item>
+ <item msgid="6210279084134579668">"መሃል ላይ የሆነ"</item>
+ <item msgid="89143234390889289">"በግራ የተሰለፈ"</item>
+ <item msgid="7715533883382410603">"በቀኝ የተሰለፈ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"ምናሌ / የቁልፍ ሰሌዳ መቀየሪያ"</string>
- <string name="select_button" msgid="1597989540662710653">"የሚታከል አዝራር ይምረጡ"</string>
- <string name="add_button" msgid="4134946063432258161">"አዝራር አክል"</string>
<string name="save" msgid="2311877285724540644">"አስቀምጥ"</string>
<string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ምንም የመነሻ አዝራር አልተገኘም"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ይህን መሣሪያ ማሰስ ለመቻል የመነሻ አዝራር ያስፈልጋል። እባክዎ ከማስቀመጥዎ በፊት የመነሻ አዝራር ያክሉ።"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"የአዝራር ስፋት አስተካክል"</string>
<string name="clipboard" msgid="1313879395099896312">"የቅንጥብ ሰሌዳ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"የቅንጥብ ሰሌዳው ንጥሎች በቀጥታ ወደ ቅንጥብ ሰሌዳው እንዲጎተቱ ያስችላል። እንዲሁም ሲኖር ንጥሎች በቀጥታ ከቅንጥብ ሰሌዳው ውጭ ሊጎተቱ ይችላሉ።"</string>
<string name="accessibility_key" msgid="5701989859305675896">"ብጁ የአሰሳ አዝራር"</string>
<string name="keycode" msgid="7335281375728356499">"የቁልፍ ኮድ"</string>
- <string name="keycode_description" msgid="1403795192716828949">"የቁልፍ ኮድ አዝራሮች የቁልፍ ሰሌዳ ቁልፎች ወደ የአሰሳ አሞሌው እንዲታከሉ ያስችላሉ። ሲጫኑ የተመረጠውን የቁልፍ ሰሌዳ ቁልፍ ያስመስላሉ። መጀመሪያ ቁልፉ ለአዝራሩ መመረጥ አለበት፣ ከዚያ በመቀጠል በአዝራሩ ላይ የሚታየው ምስል መመረጥ አለበት።"</string>
- <string name="select_keycode" msgid="7413765103381924584">"የቁልፍ ሰሌዳ አዝራር ይምረጡ"</string>
- <string name="preview" msgid="9077832302472282938">"ቅድመ-እይታ"</string>
+ <string name="icon" msgid="8732339849035837289">"አዶ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ሰቆችን ለማከል ይጎትቱ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
<string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"አሳንስ"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"አሰናብት"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ስልኩ እየሞቀ ነው"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ስልኩ እየቀዘቀዘ ሳለ አንዳንድ ባህሪዎች ይገደባሉ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ግራ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ቀኝ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"አቋራጭን አብጅ"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"አቋራጭ"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"የይለፍ ቃል ጠይቅ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ማንቂያዎች"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ቅጽበታዊ ገጽ እይታዎች"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"አጠቃላይ መልዕክቶች"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ማከማቻ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1a92e671fda5..f9073f534626 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -329,12 +329,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"وضع العمل"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"إضاءة ليلية"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"‏الاتصال القريب المدى (NFC)"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"تم تعطيل الاتصال القريب المدى"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"تم تمكين الاتصال القريب المدى"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"لقد محوتَ كل شيء"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
@@ -348,16 +345,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"تقسيم الشاشة بمحاذاة الجزء العلوي"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"تقسيم الشاشة بمحاذاة اليسار"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"تقسيم الشاشة بمحاذاة اليمين"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
@@ -438,24 +428,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"‏قطع الاتصال بشبكة VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"تتم إدارة جهازك بواسطة <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"تستخدم <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> تطبيق <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> لإدارة جهازك."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"يمكن للمشرف مراقبة الإعدادات وإدارتها والدخول إلى المؤسسة والتطبيقات والبيانات المرتبطة بجهازك ومعلومات موقع الجهاز."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"مزيد من المعلومات"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"لقد اتصلت بتطبيق <xliff:g id="VPN_APP">%1$s</xliff:g>، الذي يمكن أن يراقب نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏فتح إعدادات الشبكة الظاهرية الخاصة (VPN)"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"شغَّل المشرف ميزة تسجيل بيانات الشبكة، والتي يتم من خلالها مراقبة حركة البيانات على جهازك.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"‏لقد منحت تطبيقًا الإذن لإعداد اتصال شبكة ظاهرية خاصة (VPN).\n\nيمكن لهذا التطبيق مراقبة أنشطتك على الجهاز والشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"تتم إدارة ملفك الشخصي للعمل بواسطة <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nويمكن للمشرف مراقبة نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف.\n\nوتجدر الإشارة إلى أنك متصل أيضًا بشبكة ظاهرية خاصة يمكن أن تراقب نشاط الشبكة."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"تتم إدارة ملفك الشخصي للعمل بواسطة <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="4946600443852045903">"تتم إدارة ملفك الشخصي للعمل عن طريق <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_disabled" msgid="7412534203633528135">"سيظل الجهاز مقفلاً إلى أن يتم إلغاء قفله يدويًا"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"الحصول على الإشعارات بشكل أسرع"</string>
@@ -548,7 +534,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"إصدار تنبيه صوتي والظهور بسرعة على الشاشة"</string>
<string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
<string name="notification_done" msgid="5279426047273930175">"تم"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"عناصر التحكم في إشعارات <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"عناصر التحكم في الإشعارات"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"خيارات تأجيل الإشعارات"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"١٥ دقيقة"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"٣۰ دقيقة"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"ساعة واحدة"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"عدم التأجيل"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"تراجع"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"تم تأجيل الإشعار لمدة <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"استخدام البطارية"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"وضع توفير شحن البطارية غير متاح أثناء الشحن."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"توفير شحن البطارية"</string>
@@ -610,25 +604,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"تشغيل"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"إيقاف"</string>
<string name="nav_bar" msgid="1993221402773877607">"شريط التنقل"</string>
- <string name="start" msgid="6873794757232879664">"البدء"</string>
- <string name="center" msgid="4327473927066010960">"وسط"</string>
- <string name="end" msgid="125797972524818282">"النهاية"</string>
- <string name="space" msgid="804232271282109749">"أداة المباعدة"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"التنسيق"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"يسار"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"يمين"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"نوع الزر"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(افتراضي)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"الحافظة"</item>
+ <item msgid="5742013440802239414">"رمز المفتاح"</item>
+ <item msgid="8748101184830239843">"مبدِّل القوائم / لوحة المفاتيح"</item>
+ <item msgid="8175437057325747277">"بدون"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"مقسّم (افتراضي)"</item>
+ <item msgid="6210279084134579668">"تم التوسيط"</item>
+ <item msgid="89143234390889289">"تمت المحاذاة إلى اليسار"</item>
+ <item msgid="7715533883382410603">"تمت المحاذاة إلى اليمين"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"مبدِّل القوائم / لوحة المفاتيح"</string>
- <string name="select_button" msgid="1597989540662710653">"تحديد الزر لإضافته"</string>
- <string name="add_button" msgid="4134946063432258161">"إضافة زر"</string>
<string name="save" msgid="2311877285724540644">"حفظ"</string>
<string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
- <string name="no_home_title" msgid="1563808595146071549">"لم يُعثر على زر صفحة رئيسية"</string>
- <string name="no_home_message" msgid="5408485011659260911">"زر الصفحة الرئيسية مطلوب لكي تتمكن من التنقل في هذا الجهاز، الرجاء إضافة زر صفحة رئيسية قبل الحفظ."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ضبط عرض الزر"</string>
<string name="clipboard" msgid="1313879395099896312">"الحافظة"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"تتيح الحافظة إمكانية سحب العناصر مباشرة إلى الحافظة، وكذلك يمكن سحب العناصر مباشرة خارج الحافظة عند وجودها."</string>
<string name="accessibility_key" msgid="5701989859305675896">"زر التنقل المخصص"</string>
<string name="keycode" msgid="7335281375728356499">"رمز المفتاح"</string>
- <string name="keycode_description" msgid="1403795192716828949">"تتيح أزرار رموز المفاتيح إمكانية إضافة مفاتيح لوحة المفاتيح إلى شريط التنقل. وعند الضغط عليها، تحاكي الأزرار مفتاح لوحة المفاتيح المحدد. ويجب أولاً تحديد المفتاح للزر، وبعد ذلك تحديد صورة لكي يتم عرضها على الزر."</string>
- <string name="select_keycode" msgid="7413765103381924584">"تحديد زر لوحة المفاتيح"</string>
- <string name="preview" msgid="9077832302472282938">"معاينة"</string>
+ <string name="icon" msgid="8732339849035837289">"رمز"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"اسحب لإضافة مربعات"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"اسحب هنا للإزالة"</string>
<string name="qs_edit" msgid="2232596095725105230">"تعديل"</string>
@@ -679,8 +679,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"تصغير"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"تجاهل"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"تزداد درجة حرارة الهاتف"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"يسار"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"يمين"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"تخصيص الاختصار"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"اختصار"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"طلب إدخال كلمة المرور"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"لقطات الشاشة"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"رسائل عامة"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 89500344f2a8..ba67b3a56dc8 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"İş rejimi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gecə işığı"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC deaktiv edilib"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC aktiv edilib"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Son elementlər yoxdur"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hərşeyi təmizlədiniz"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Tətbiq haqqında"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Üfüqi Böl"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Şaquli Böl"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Fərdi Böl"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranı yuxarıdan ayırın"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranı soldan ayırın"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranı sağdan ayırın"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Dolub"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN-i bağlantıdan ayırın"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Cihaz <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tərəfindən idarə olunur."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> istifadə edir."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrator ayarlara, korporativ girişə, tətbiqlərə, cihaz ilə əlaqədar dataya və cihazın məkan məlumatına nəzarət və idarə edə bilər."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" ("</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ətraflı məlumat"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" ("</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN Ayarlarını açın"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Admin, cihazdakı trafikə nəzarət edən şəbəkə loqlarını aktiv etdi.\n\nƏtraflı məlumat üçün administrator ilə əlaqə saxlayın."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN bağlantısı quraşdırmağa icazə vermisiniz.\n\nBu tətbiq cihazınızı və şəbəkə fəaliyyətinizi, həmçinin, e-məktubları, tətbiq və veb saytları izləyə bilər."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur.\n\nAdmin e-poçt, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyətinizə nəzarət etməyə qadirdir.\n\nƏtraflı məlumat üçün administrator ilə əlaqə saxlayın.\n\nEyni zamanda, şəbəkə fəaliyyətinizə nəzarət edən VPN\'ə qoşulusunuz."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur və e-poçt, tətbiq, veb saytlar daxil olmaqla iş şəbəkə fəaliyyətinizə nəzarət edən <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqinə qoşuludur.\n\nƏtraflı məlumat üçün admin ilə əlaqə saxlayın."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizi idarə edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir\n\nSiz, həmçinin, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə də qoşulsunuz və o, şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirişləri daha sürətlə əldə edin"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Səsli və ekranda pəncərə ilə"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
<string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildiriş nəzarəti"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"bildiriş nəzarəti"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildiriş təxirə salma seçimləri"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 dəqiqə"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 dəqiqə"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 saat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Təxirə salmayın"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"GERİ QAYTARIN"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> üçün təxirə salınıb"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batareya istifadəsi"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Enerji Qənaəti doldurulma zamanı əlçatan deyil"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Enerji Qənaəti"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aktiv"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Deaktiv"</string>
<string name="nav_bar" msgid="1993221402773877607">"Naviqasiya paneli"</string>
- <string name="start" msgid="6873794757232879664">"Başladın"</string>
- <string name="center" msgid="4327473927066010960">"Mərkəz"</string>
- <string name="end" msgid="125797972524818282">"Son"</string>
- <string name="space" msgid="804232271282109749">"Boşluq"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Tərtibat"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Sol"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Sağ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Düymə növü"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(defolt)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Mübadilə buferi"</item>
+ <item msgid="5742013440802239414">"Açar kodu"</item>
+ <item msgid="8748101184830239843">"Menyu / Klaviatura Keçirici"</item>
+ <item msgid="8175437057325747277">"Heç bir"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Bölünmüş (defolt)"</item>
+ <item msgid="6210279084134579668">"Mərkəzi"</item>
+ <item msgid="89143234390889289">"Soldan düzülmüş"</item>
+ <item msgid="7715533883382410603">"Sağdan düzülmüş"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menyu / Klaviatura Keçirici"</string>
- <string name="select_button" msgid="1597989540662710653">"Əlavə etmək üçün düymə seçin"</string>
- <string name="add_button" msgid="4134946063432258161">"Düymə əlavə edin"</string>
<string name="save" msgid="2311877285724540644">"Saxlayın"</string>
<string name="reset" msgid="2448168080964209908">"Sıfırlayın"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Heç bir əsas ekran düyməsi tapılmadı"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Bu cihazı idarə etmək üçün əsas düymə tələb olunur. Yaddaşda saxlamadan əvvəl əsas düyməni əlavə edin."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Düymənin enini nizamlayın"</string>
<string name="clipboard" msgid="1313879395099896312">"Pano"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Elementlərin sürüşdürərək birbaşa panoya əlavə olunmasına icazə verir. Mövcud olduqda elementlər pano kənarından da sürüşdürərək birbaşa panoya əlavə oluna bilər."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Fərdi naviqasiya düyməsi"</string>
<string name="keycode" msgid="7335281375728356499">"Açar kodu"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Açar kodu düymələri klaviatura açarlarının Naviqasiya Panelinə əlavə olunmasına icazə verir. Basıldıqda seçilmiş klaviatura açarını yaradır. İlk olaraq düymə üçün düymə üzərində göstərilən şəkilə uyğun açar seçilməlidir."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Klaviatura Düyməsi Seçin"</string>
- <string name="preview" msgid="9077832302472282938">"Önizləmə"</string>
+ <string name="icon" msgid="8732339849035837289">"İkona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Xanalar əlavə etmək üçün sürüşdürün"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Silmək üçün bura sürüşdürün"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Kiçildin"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Yığışdırın"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon qızmağa başlayır"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Sol"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Sağ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Qısayolu fərdiləşdirin"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Qısayol"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Parol üçün bildiriş"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Siqnallar"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinşotlar"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Ümumi Mesajlar"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Yaddaş"</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 2313487f253f..2e01995b77ad 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Režim rada"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svetlo"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC je onemogućen"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC je omogućen"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Obrisali ste sve"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podeli vertikalno"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođeno deljenje"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podeli ekran nagore"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podeli ekran nalevo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podeli ekran nadesno"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjena je"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Prekini vezu sa VPN-om"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Uređajem upravlja <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> koristi <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje uređajem."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvorite podešavanja VPN-a"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administrator je uključio evidentiranje mreže, koje prati saobraćaj na uređaju.\n\nKontaktirajte administratora za više informacija."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Dali ste dozvolu aplikaciji da podešava VPN vezu.\n\nTa aplikacija može da nadgleda aktivnosti na uređaju i mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> upravlja profilom za Work.\n\nAdministrator može da prati aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nKontaktirajte administratora za više informacija.\n\nPovezani ste i sa VPN-om, koji može da prati aktivnosti na mreži."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> upravlja profilom za Work. On je povezan sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da prati aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nKontaktirajte administratora za više informacija."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Brže dobijajte obaveštenja"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emituje se zvučni signal i prikazuje se na ekranu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obaveštenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obaveštenja"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije za odlaganje obaveštenja"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuta"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuta"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 sat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne odlaži"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"OPOZOVI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Odloženo je za <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije nije dostupna tokom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Isključeno"</string>
<string name="nav_bar" msgid="1993221402773877607">"Traka za navigaciju"</string>
- <string name="start" msgid="6873794757232879664">"Pokreni"</string>
- <string name="center" msgid="4327473927066010960">"Centar"</string>
- <string name="end" msgid="125797972524818282">"Dno"</string>
- <string name="space" msgid="804232271282109749">"Oznaka za razmak"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Raspored"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Levo"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Desno"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tip dugmeta"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(podrazumevano)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Memorija"</item>
+ <item msgid="5742013440802239414">"Kôd tastera"</item>
+ <item msgid="8748101184830239843">"Prebacivač meni/tastatura"</item>
+ <item msgid="8175437057325747277">"Ništa"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Podeljeno (podrazumevano)"</item>
+ <item msgid="6210279084134579668">"Centrirano"</item>
+ <item msgid="89143234390889289">"Poravnato ulevo"</item>
+ <item msgid="7715533883382410603">"Poravnato udesno"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Meni/Tastatura prebacivač"</string>
- <string name="select_button" msgid="1597989540662710653">"Izaberite dugme za dodavanje"</string>
- <string name="add_button" msgid="4134946063432258161">"Dodaj dugme"</string>
<string name="save" msgid="2311877285724540644">"Sačuvaj"</string>
<string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nismo pronašli dugme Početna"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Dugme Početna je neophodno za navigaciju na ovom uređaju. Dodajte dugme Početna pre nego što sačuvate izmene."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Prilagodi širinu dugmeta"</string>
<string name="clipboard" msgid="1313879395099896312">"Privremena memorija"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Privremena memorija omogućava da se stavke prevlače direktno u privremenu memoriju. Postojeće stavke mogu da se prevlače i direktno iz privremene memorije."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Prilagođeno dugme za navigaciju"</string>
<string name="keycode" msgid="7335281375728356499">"Kôd tastera"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Dugmad za kodove tastera omogućava da se na traku za navigaciju dodaju tasteri na tastaturi. Kada pritisnete dugme, simulira se izabrani taster na tastaturi. Prvo morate da izaberete taster za dugme, pa sliku koju će se prikazivati na dugmetu."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Izaberite dugme za tastaturu"</string>
- <string name="preview" msgid="9077832302472282938">"Pregled"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Prevucite da biste dodali pločice"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovde da biste uklonili"</string>
<string name="qs_edit" msgid="2232596095725105230">"Izmeni"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon se zagrejao"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Neke funkcije su ograničene dok se telefon ne ohladi"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Levo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Desno"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Prilagodi prečicu"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Prečica"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Upit za lozinku"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Obaveštenja"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Opšte poruke"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Memorijski prostor"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 083342a123d6..60f042e167ff 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рэжым працы"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Начная падсветка"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC адключаны"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC уключаны"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Няма нядаўніх элементаў"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы ачысцілі усё"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Звесткі аб праграме"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Падзяліць гарызантальна"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Падзяліць вертыкальна"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Падзяліць іншым чынам"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Падзяліць экран зверху"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Падзяліць экран злева"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Падзяліць экран справа"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зараджаны"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Адлучыць VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> выкарыстоўвае <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> для кіравання вашай прыладай."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Адміністратар кантралюе налады, праграмы, карпаратыўны доступ, звязаныя з прыладай даныя і перадачу геаданых."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Даведацца больш"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Вы падключаны да праграмы <xliff:g id="VPN_APP">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" ,"</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Адкрыйце налады VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Ваш адміністратар уключыў вядзенне журнала сеткі, з дапамогай якога адсочваецца трафік на вашай прыладзе.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Вы далі праграме дазвол на наладжванне злучэння VPN.\n\nГэта праграма можа сачыць за актыўнасцю вашай прылады і вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць за вашай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара.\n\nВы таксама падключаны да сеткі VPN, якая можа сачыць за вашай сеткавай дзейнасцю."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Ваш працоўны профіль знаходзіцца пад кіраваннем <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="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <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_disabled" msgid="7412534203633528135">"Прылада будзе заставацца заблакіраванай, пакуль вы не разблакіруеце яе ўручную"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Атрымлівайце апавяшчэнні хутчэй"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Прайграваць гук і паказваць на экране"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
<string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Элементы кантролю апавяшчэнняў <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"кіраванне апавяшчэннямі"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"параметры адкладвання апавяшчэнняў"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 хвілін"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 хвілін"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 гадзіна"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Не адкладваць"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"АДРАБІЦЬ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Адкладзена на <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Выкарыстанне зараду"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Эканомія зараду акумулятара недаступная падчас зарадкі"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Эканомія зараду"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Уключана"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Выключана"</string>
<string name="nav_bar" msgid="1993221402773877607">"Панэль навігацыі"</string>
- <string name="start" msgid="6873794757232879664">"Пачатак"</string>
- <string name="center" msgid="4327473927066010960">"Цэнтр"</string>
- <string name="end" msgid="125797972524818282">"Завяршыць"</string>
- <string name="space" msgid="804232271282109749">"Падзяляльнік"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Раскладка"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Злева"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Справа"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тып кнопкі"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(стандартная)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Буфер абмену"</item>
+ <item msgid="5742013440802239414">"Код клавішы"</item>
+ <item msgid="8748101184830239843">"Пераключальнік Меню / Клавіятура"</item>
+ <item msgid="8175437057325747277">"Няма"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Падзеленая (стандартная)"</item>
+ <item msgid="6210279084134579668">"У цэнтры"</item>
+ <item msgid="89143234390889289">"Выраўнаваная злева"</item>
+ <item msgid="7715533883382410603">"Выраўнаваная справа"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Пераключальнік Меню/Клавіятура"</string>
- <string name="select_button" msgid="1597989540662710653">"Выберыце, якую кнопку дадаць"</string>
- <string name="add_button" msgid="4134946063432258161">"Дадаць кнопку"</string>
<string name="save" msgid="2311877285724540644">"Захаваць"</string>
<string name="reset" msgid="2448168080964209908">"Скінуць"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Кнопка гал. экр. не знойдзена"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Для навігацыі па гэтай прыладзе патрабуецца кнопка галоўнага экрана. Калі ласка, дадайце кнопку галоўнага экрана перад захаваннем."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Адрэгуляваць шырыню кнопкі"</string>
<string name="clipboard" msgid="1313879395099896312">"Буфер абмену"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"З дапамогай кнопкі Буфер абмену можна перацягваць элементы непасрэдна ў буфер абмену. Элементы можна таксама перацягваць непасрэдна з буфера абмену, калі яны там ёсць."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Кнопка карыстальніцкай навігацыі"</string>
<string name="keycode" msgid="7335281375728356499">"Код клавішы"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Кнопка Код клавішы дазваляе дадаваць клавішы ў Панэль навігацыі. Пры націску гэтай кнопкі эмулюецца выбраная клавіша. Спачатку трэба выбраць клавішу для кнопкі, а потым відарыс, які будзе паказвацца на кнопцы."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Выберыце клавішу клавіятуры"</string>
- <string name="preview" msgid="9077832302472282938">"Перадпрагляд"</string>
+ <string name="icon" msgid="8732339849035837289">"Значок"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перацягніце, каб дадаць пліткі"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
<string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Згарнуць"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Адхіліць"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Тэлефон награваецца"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Некаторыя функцыі абмежаваны, пакуль тэлефон астывае"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Налева"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Направа"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Наладзіць ярлык"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Ярлык"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Запыт пароля"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Абвесткi"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Здымкі экрана"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Агульныя паведамленні"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Захоўванне"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 8382e381c0ef..2ebac751eb09 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Работен режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нощно осветление"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"КБП"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"КБП е деактивирана"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"КБП е активирана"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Няма скорошни елементи"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Изчистихте всичко"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Разделяне на екрана нагоре"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Разделяне на екрана наляво"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Разделяне на екрана надясно"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Прекратяване на връзката с VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Устройството ви се управлява от <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> използва <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>, за да управлява устройството ви."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Администраторът ви може да набл. и управл. настройките, корпор. достъп, прилож., данните, свързани с у-вото, както и информ. за местоп. му."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Научете повече"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Установена е връзка с приложението <xliff:g id="VPN_APP">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, вкл. имейли, приложения и уебсайтове."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отваряне на настройките за VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Администраторът ви е включил функцията за регистриране на мрежовата активност, която следи трафика на устройството ви.\n\nЗа повече информация се свържете с администратора си."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Разрешихте на приложение да настрои връзка с виртуална частна мрежа (VPN).\n\nТова приложение може да наблюдава активността ви на устройството и в мрежата, включително имейли, приложения и уебсайтове."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа повече информация се свържете с администратора си.\n\nСъщо така е установена връзка с виртуална частна мрежа (VPN) и активността ви в нея може да се наблюдава."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Служебният ви потребителски профил се управлява от <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="4946600443852045903">"Служебният ви потребителски профил се управлява от <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_disabled" msgid="7412534203633528135">"Устройството ще остане заключено, докато не го отключите ръчно"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Получавайте известия по-бързо"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Възпроизвеждане на звук и показване на изскачащ прозорец на екрана"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известията от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"контроли за известията"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"опции за отлагане на известията"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минути"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минути"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 час"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Без отлагане"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ОТМЯНА"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Отложено за <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Ползв. на батерията"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режимът за запазване на батерията не е налице при зареждане"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим за запазване на батерията"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Вкл."</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Изкл."</string>
<string name="nav_bar" msgid="1993221402773877607">"Лента за навигация"</string>
- <string name="start" msgid="6873794757232879664">"Начало"</string>
- <string name="center" msgid="4327473927066010960">"Център"</string>
- <string name="end" msgid="125797972524818282">"Край"</string>
- <string name="space" msgid="804232271282109749">"Разстояние между бутоните"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Оформление"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Вляво"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Вдясно"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тип бутон"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(по подразбиране)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Буферна памет"</item>
+ <item msgid="5742013440802239414">"Клавишен код"</item>
+ <item msgid="8748101184830239843">"Превключвател на менюто/клавиатурата"</item>
+ <item msgid="8175437057325747277">"Няма"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Разделено (по подразбиране)"</item>
+ <item msgid="6210279084134579668">"Центрирано"</item>
+ <item msgid="89143234390889289">"Подравнено вляво"</item>
+ <item msgid="7715533883382410603">"Подравнено вдясно"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Превкл. на менюто/клавиатурата"</string>
- <string name="select_button" msgid="1597989540662710653">"Избиране на бутон за добавяне"</string>
- <string name="add_button" msgid="4134946063432258161">"Добавяне на бутон"</string>
<string name="save" msgid="2311877285724540644">"Запазване"</string>
<string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Няма намерен бутон „Начало“"</string>
- <string name="no_home_message" msgid="5408485011659260911">"За да се придвижвате в това устройство, е необходим бутон „Начало“. Моля, добавете такъв, преди да запазите."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Коригиране на ширината на бутона"</string>
<string name="clipboard" msgid="1313879395099896312">"Буферна памет"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Този бутон ви дава възможност да премествате с плъзгане елементи директно в буферната памет, а също и извън нея."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Персонализиран бутон за навигация"</string>
<string name="keycode" msgid="7335281375728356499">"Клавишен код"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Бутоните с клавишни кодове ви дават възможност да добавяте клавиши от клавиатурата към лентата за навигация. При докосване на такъв бутон се симулира натискане на съответния клавиш. Първо, трябва да изберете клавиш за бутона, а след това – изображение, което да се показва върху него."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Избиране на клавиш от клавиатурата"</string>
- <string name="preview" msgid="9077832302472282938">"Визуализация"</string>
+ <string name="icon" msgid="8732339849035837289">"Икона"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Преместете с плъзгане, за да добавите плочки"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Преместете тук с плъзгане за премахване"</string>
<string name="qs_edit" msgid="2232596095725105230">"Редактиране"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Намаляване"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Отхвърляне"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефонът загрява"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Някои функции са ограничени, докато телефонът се охлажда"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Вляво"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Вдясно"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Персонализиране на прекия път"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Пряк път"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Подкана за парола"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Сигнали"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Екранни снимки"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Общи съобщения"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f732279a728b..ed86d3d9ce40 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -156,7 +156,7 @@
<string name="accessibility_cell_data_off" msgid="8000803571751407635">"সেলুলার ডেটা বন্ধ আছে"</string>
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ব্লুটুথ টিথারিং৷"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"বিমান মোড৷"</string>
- <string name="accessibility_no_sims" msgid="3957997018324995781">"কোনো SIM কার্ড নেই।"</string>
+ <string name="accessibility_no_sims" msgid="3957997018324995781">"কোনো সিম কার্ড নেই।"</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তিত হচ্ছে।"</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"ব্যাটারির বিশদ বিবরণ খুলুন"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ ব্যাটারি রয়েছে৷"</string>
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"কাজের মোড"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"নাইট লাইট"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC অক্ষম করা আছে"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC সক্ষম করা আছে"</string>
<string name="recents_empty_message" msgid="808480104164008572">"কোনো সাম্প্রতিক আইটেম নেই"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"আপনি সবকিছু সাফ করেছেন"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"স্ক্রিনটি উপরের দিকে বিভক্ত করুন"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"স্ক্রিনটি বাঁদিকে বিভক্ত করুন"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"স্ক্রিনটি ডানদিকে বিভক্ত করুন"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"চার্জ হয়েছে"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN এর সংযোগ বিচ্ছিন্ন করুন"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"আপনার ডিভাইসটি <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> এর দ্বারা পরিচালিত৷"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> আপনার ডিভাইস পরিচালনা করার জন্য <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ব্যবহার করে৷"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"আপনার প্রশাসক আপনার ডিভাইসের অবস্থান তথ্য সহ এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্স, ডেটা নিরীক্ষণ ও পরিচালনা করতে পারেন।"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"আরো জানুন"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করবে৷"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN সেটিংস খুলুন"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিক নিরীক্ষণ করে।\n\nআরো তথ্যের জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"আপনি VPN সংযোগ সেট আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে।"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"আপনার কর্মস্থলের প্রোফাইলটি <xliff:g id="ORGANIZATION">%1$s</xliff:g> দ্বারা পরিচালিত হয়।\n\nআপনার প্রশাসক আপনার ইমেল, অ্যাপ্স ও ওয়েবসাইট সহ কর্মস্থলের নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারেন।\n\nআরো তথ্যের জন্য আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়া আপনি একটি VPN এর সাথেও সংযুক্ত যা আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে।"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"আপনার কর্মস্থলের প্রোফাইলটি <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="4946600443852045903">"<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_disabled" msgid="7412534203633528135">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"বিজ্ঞপ্তিগুলি আরো দ্রুত পান"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"শব্দ করে ও স্ক্রীনে ভেসে ওঠে"</string>
<string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
<string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"বিজ্ঞপ্তি মনে করিয়ে দেওয়ার বিকল্পগুলি"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"১৫ মিনিট"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"৩০ মিনিট"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"১ ঘণ্টা"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"মনে করানো হবে না"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"পূর্বাবস্থায় ফিরুন"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> পরে আবার মনে করানো হবে"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ব্যাটারির ব্যবহার"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"চালু আছে"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"বন্ধ আছে"</string>
<string name="nav_bar" msgid="1993221402773877607">"নেভিগেশন দন্ড"</string>
- <string name="start" msgid="6873794757232879664">"শুরু করুন"</string>
- <string name="center" msgid="4327473927066010960">"কেন্দ্র"</string>
- <string name="end" msgid="125797972524818282">"শেষ"</string>
- <string name="space" msgid="804232271282109749">"স্পেসার"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"লেআউট"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"বাঁ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ডান"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"বোতামের ধরণ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ডিফল্ট)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ক্লিপবোর্ড"</item>
+ <item msgid="5742013440802239414">"কীকোড"</item>
+ <item msgid="8748101184830239843">"মেনু / কীবোর্ড স্যুইচার"</item>
+ <item msgid="8175437057325747277">"কোনো কিছুই নয়"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"ভাগ করা (ডিফল্ট)"</item>
+ <item msgid="6210279084134579668">"কেন্দ্রস্থ"</item>
+ <item msgid="89143234390889289">"বাঁ দিকে সারিবদ্ধ"</item>
+ <item msgid="7715533883382410603">"ডান দিকে সারিবদ্ধ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"মেনু / কীবোর্ড স্যুইচার"</string>
- <string name="select_button" msgid="1597989540662710653">"যোগ করার জন্য বোতাম নির্বাচন করুন"</string>
- <string name="add_button" msgid="4134946063432258161">"বোতাম যোগ করুন"</string>
<string name="save" msgid="2311877285724540644">"সংরক্ষণ করুন"</string>
<string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string>
- <string name="no_home_title" msgid="1563808595146071549">"কোনো হোম বোতাম পাওয়া যায় নি"</string>
- <string name="no_home_message" msgid="5408485011659260911">"এই ডিভাইসটিকে নেভিগেট করার জন্য একটি হোম বোতামের প্রয়োজন। সংরক্ষণ করার আগে অনুগ্রহ করে একটি হোম বোতাম যোগ করুন।"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"বোতামের প্রস্থ সমন্বয় করুন"</string>
<string name="clipboard" msgid="1313879395099896312">"ক্লিপবোর্ড"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ক্লিপবোর্ড আইটেমগুলিকে সরাসরি ক্লিপবোর্ডে টেনে আনার অনুমতি দেয়। ক্লিপবোর্ডের বাইরে হাজির থাকার সময়েও আইটেমগুলিকে সরাসরি টেনে আনা যায়।"</string>
<string name="accessibility_key" msgid="5701989859305675896">"কাস্টম নেভিগেশান বোতাম"</string>
<string name="keycode" msgid="7335281375728356499">"কীকোড"</string>
- <string name="keycode_description" msgid="1403795192716828949">"কীকোড বোতামগুলি নেভিগেশান দন্ডে কীবোর্ডের কীগুলি যোগ করার অনুমতি দেয়। চাপ দেওয়ার সময়ে সেগুলি নির্বাচিত কীবোর্ডের কী কে অনুকরণ করে। বোতামে দেখানো হয়েছে এমন একটি চিত্রকে অনুসরণ করে অবশ্যই প্রথমে বোতামের জন্য কী নির্বাচন করতে হবে।"</string>
- <string name="select_keycode" msgid="7413765103381924584">"কীবোর্ডের বোতাম নির্বাচন করুন"</string>
- <string name="preview" msgid="9077832302472282938">"পূর্বরূপ দেখুন"</string>
+ <string name="icon" msgid="8732339849035837289">"আইকন"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"টাইলগুলি যোগ করার জন্য টেনে আনুন"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"সরানোর জন্য এখানে টেনে আনুন"</string>
<string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"প্রসারিত করুন"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ছোটো করুন"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"খারিজ করুন"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ফোনটি গরম হচ্ছে"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠান্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠান্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠান্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"বাঁ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ডান"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"কাস্টমাইজ করার শর্টকাট"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"শর্টকাট"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"পাসওয়ার্ড জানতে চান"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"সতর্কতাগুলি"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"স্ক্রীনশটস"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"সাধারণ বার্তাগুলি"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়স্থান"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 948fccdbfedd..d17775cba5af 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Poslovni režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC je onemogućen"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC je omogućen"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Sve ste obrisali"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli ekran nagore"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli ekran nalijevo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli ekran nadesno"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Prekini VPN vezu"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vašim uređajem upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> koristi aplikaciju <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje vašim uređajem."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Vaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane s vašim uređajem i informacije o lokaciji vašeg uređaja."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poruke i web lokacije."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Postavke otvorene VPN mreže"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Vaš administrator je uključio zapisivanje na mreži, čime se prati saobraćaj na vašem uređaju.\n\nZa više informacija, obratite se administratoru."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Jednoj aplikaciji ste dali odobrenje da uspostavi VPN vezu.\n\nTa aplikacija može pratiti vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nZa više informacija, obratite se administratoru.\n\nPovezani ste i na VPN, koji može pratiti vašu aktivnost na mreži."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nZa više informacija, obratite se svom administratoru."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Brže primaj obavještenja"</string>
@@ -462,7 +448,7 @@
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je prikačen"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
- <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikzan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
+ <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"Jasno mi je"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -544,7 +530,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Pusti zvuk i prikaži na ekranu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole <xliff:g id="APP_NAME">%1$s</xliff:g> obavještenja"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obavještenja"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije za odgodu obavještenja"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuta"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuta"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 sat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne odgađaj"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"OPOZOVI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Odgođeno za <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Upotreba baterije"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije je isključena prilikom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
@@ -606,25 +600,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Isključi"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigaciona traka"</string>
- <string name="start" msgid="6873794757232879664">"Početak"</string>
- <string name="center" msgid="4327473927066010960">"Sredina"</string>
- <string name="end" msgid="125797972524818282">"Kraj"</string>
- <string name="space" msgid="804232271282109749">"Razmaknica"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Raspored"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Lijevo"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Desno"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tip dugmeta"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(zadano)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Međumemorija"</item>
+ <item msgid="5742013440802239414">"Kôd tipke"</item>
+ <item msgid="8748101184830239843">"Prebacivač Meni / Tastatura"</item>
+ <item msgid="8175437057325747277">"Nema"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Podijeljeno (zadano)"</item>
+ <item msgid="6210279084134579668">"Centrirano"</item>
+ <item msgid="89143234390889289">"Poredano nalijevo"</item>
+ <item msgid="7715533883382410603">"Poredano nadesno"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Izbornik / Prebacivač tipkovn."</string>
- <string name="select_button" msgid="1597989540662710653">"Odaberite dugme koje želite dodati"</string>
- <string name="add_button" msgid="4134946063432258161">"Dodaj dugme"</string>
<string name="save" msgid="2311877285724540644">"Sačuvaj"</string>
<string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Dugme za početak nije pronađeno."</string>
- <string name="no_home_message" msgid="5408485011659260911">"Dugme za početak je neophodno za navigaciju ovim uređajem. Dodajte dugme za početak prije pohranjivanja."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Podesite širinu dugmeta"</string>
<string name="clipboard" msgid="1313879395099896312">"Međumemorija"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Međumorija omogućava direktno prebacivanje sadržaja u nju. Sadržaj se isto tako može povući direktno iz međumemorije ako ga ima."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Prilagođeno dugme za navigaciju"</string>
<string name="keycode" msgid="7335281375728356499">"Kod tipke"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Dugmad za kodiranje tipki omogućavaju da se tipke sa tipkovnice dodaju u navigacionu traku. Kada se pritisnu, oni oponašaju izabranu tipku tastature. Kao prvo, tipka mora biti izabrana za dugme, a nakon toga se bira slika koja će biti prikazana na njemu."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
- <string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da dodate polja"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
@@ -675,8 +675,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon se pregrijava"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Neke funkcije su ograničene dok se telefon hladi"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Lijevo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Desno"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Prilagodite prečicu"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Prečica"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Traži lozinku"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index fd10d12c3423..009942c5119e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode de feina"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Llum nocturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"L\'NFC està desactivada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"L\'NFC està activada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hi ha cap element recent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ho has esborrat tot"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Divideix la pantalla cap amunt"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Divideix la pantalla cap a l\'esquerra"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divideix la pantalla cap a la dreta"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconnecta la VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> gestiona el teu dispositiu."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilitza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> per gestionar el teu dispositiu."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"L\'administrador pot supervisar i gestionar la configuració, l\'accés corporatiu, les aplicacions, la ubicació i les dades del dispositiu."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Més informació"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estàs connectat a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Obre la configuració de la VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"L\'administrador ha activat el registre de xarxa, que supervisa el trànsit del teu dispositiu.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Has donat permís a una aplicació per configurar una connexió VPN.\n\nAquesta aplicació pot supervisar el dispositiu i l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional.\n\nL\'administrador pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador.\n\nA més, estàs connectat a una VPN, que també pot supervisar la teva activitat a la xarxa."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nA més, estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que també pot supervisar la teva activitat personal a la xarxa."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositiu continuarà bloquejat fins que no el desbloquegis manualment."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Obtén notificacions més ràpidament"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Amb so i amb una finestra emergent"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
<string name="notification_done" msgid="5279426047273930175">"Fet"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controls de notificació de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controls de notificació"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcions per posposar la notificació"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuts"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuts"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"No posposis"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESFÉS"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"S\'ha posposat <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Ús de la bateria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activat"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desactivat"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegació"</string>
- <string name="start" msgid="6873794757232879664">"Inici"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"Final"</string>
- <string name="space" msgid="804232271282109749">"Separador"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Disseny"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Esquerra"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Dreta"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipus de botó"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predeterminat)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Porta-retalls"</item>
+ <item msgid="5742013440802239414">"Codi de tecla"</item>
+ <item msgid="8748101184830239843">"Commutador del teclat/menú"</item>
+ <item msgid="8175437057325747277">"Cap"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividit (predeterminat)"</item>
+ <item msgid="6210279084134579668">"Centrat"</item>
+ <item msgid="89143234390889289">"Alineat a l\'esquerra"</item>
+ <item msgid="7715533883382410603">"Alineat a la dreta"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Commutador del teclat/menú"</string>
- <string name="select_button" msgid="1597989540662710653">"Tria un botó per afegir-lo"</string>
- <string name="add_button" msgid="4134946063432258161">"Afegeix un botó"</string>
<string name="save" msgid="2311877285724540644">"Desa"</string>
<string name="reset" msgid="2448168080964209908">"Restableix"</string>
- <string name="no_home_title" msgid="1563808595146071549">"No s\'ha trobat cap botó d\'inici"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Per poder navegar per aquest dispositiu, cal un botó d\'inici. Afegeix-ne un abans de desar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajusta l\'amplada del botó"</string>
<string name="clipboard" msgid="1313879395099896312">"Porta-retalls"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Pots arrossegar elements al porta-retalls directament. Si conté elements, també els pots treure directament arrossegant-los."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botó de navegació personalitzat"</string>
<string name="keycode" msgid="7335281375728356499">"Codi de tecla"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Amb els botons de codi de tecla es poden afegir tecles del teclat a la barra de navegació. En prémer aquests botons es duen a terme les mateixes accions que quan es prem la tecla corresponent. Primer cal seleccionar la tecla del botó i, a continuació, triar la imatge que es mostrarà."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botó de teclat"</string>
- <string name="preview" msgid="9077832302472282938">"Previsualització"</string>
+ <string name="icon" msgid="8732339849035837289">"Icona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrossega per afegir funcions"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrossega aquí per suprimir una funció"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edita"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimitza"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignora"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"El telèfon s\'està escalfant"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Algunes funcions estaran limitades mentre el telèfon es refreda"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Esquerra"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Dreta"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalitza la drecera"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Drecera"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Sol·licita la contrasenya"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures de pantalla"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Missatges generals"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Emmagatzematge"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 51fb53002213..dc3df04fa023 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovní režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noční režim"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC je vypnuto"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC je zapnuto"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Žádné nedávné položky"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vše je vymazáno"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Rozdělit obrazovku nahoru"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Rozdělit obrazovku vlevo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Rozdělit obrazovku vpravo"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Odpojit VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vaše zařízení je spravováno aplikací <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Organizace <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> používá ke správě tohoto zařízení aplikaci <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrátor může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a jeho polohu."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Další informace"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Jste připojeni k aplikaci <xliff:g id="VPN_APP">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otevřít nastavení VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administrátor zapnul protokolování sítě, které monitoruje síťový provoz v zařízení.\n\nDalší informace vám poskytne administrátor."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Udělili jste aplikaci oprávnění k nastavení připojení VPN.\n\nTato aplikace může sledovat vaši aktivitu v zařízení a v síti, včetně e-mailů, aplikací a webů."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může monitorovat vaši síťovou aktivitu, včetně e-mailů, aplikací a webů.\n\nDalší informace vám poskytne administrátor.\n\nJste také připojeni k síti VPN, která může sledovat vaši aktivitu v síti."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nDalší informace vám poskytne administrátor."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Zařízení zůstane uzamčeno, dokud je ručně neodemknete"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Čtěte si oznámení rychleji"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Vydat zvukový signál a vyskočit na obrazovku"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Nastavení oznámení aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"Nastavení oznámení"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Možnosti odložení oznámení"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minut"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minut"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hodina"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Neodkládat"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"VRÁTIT ZPĚT"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Odloženo o <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Využití baterie"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Spořič baterie při nabíjení není k dispozici."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Spořič baterie"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Zapnuto"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Vypnuto"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigační panel"</string>
- <string name="start" msgid="6873794757232879664">"Začátek"</string>
- <string name="center" msgid="4327473927066010960">"Střed"</string>
- <string name="end" msgid="125797972524818282">"Konec"</string>
- <string name="space" msgid="804232271282109749">"Mezerník"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Rozvržení"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Vlevo"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Vpravo"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Typ tlačítka"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(výchozí)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Schránka"</item>
+ <item msgid="5742013440802239414">"Klávesa"</item>
+ <item msgid="8748101184830239843">"Přepínač nabídky/klávesnice"</item>
+ <item msgid="8175437057325747277">"Žádné"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Rozděleno (výchozí)"</item>
+ <item msgid="6210279084134579668">"Zarovnáno na střed"</item>
+ <item msgid="89143234390889289">"Zarovnáno doleva"</item>
+ <item msgid="7715533883382410603">"Zarovnáno doprava"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Přepínač nabídky/klávesnice"</string>
- <string name="select_button" msgid="1597989540662710653">"Vyberte tlačítko"</string>
- <string name="add_button" msgid="4134946063432258161">"Přidat tlačítko"</string>
<string name="save" msgid="2311877285724540644">"Uložit"</string>
<string name="reset" msgid="2448168080964209908">"Resetovat"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nebylo nalezeno tlačítko plochy"</string>
- <string name="no_home_message" msgid="5408485011659260911">"K navigaci v zařízení je potřeba tlačítko plochy. Před uložením toto tlačítko přidejte."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Upravit šířku tlačítka"</string>
<string name="clipboard" msgid="1313879395099896312">"Schránka"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Tlačítko Schránka umožňuje přetahovat položky přímo do schránky. Položky vložené do schránky lze také přetáhnout ven."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Vlastní navigační tlačítko"</string>
<string name="keycode" msgid="7335281375728356499">"Klávesa"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tlačítka Klávesa umožňují přidat na navigační panel klávesy z klávesnice. Když na ně klepnete, budou emulovat vybranou klávesu. K tlačítku je nejprve nutné přiřadit klávesu a poté přidat obrázek tlačítka."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Vyberte klávesu na klávesnici"</string>
- <string name="preview" msgid="9077832302472282938">"Náhled"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice přidáte přetažením"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Přetažením sem dlaždice odstraníte"</string>
<string name="qs_edit" msgid="2232596095725105230">"Upravit"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovat"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Zrušit"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon se zahřívá"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Některé funkce jsou při chladnutí omezeny"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vlevo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Vpravo"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Přizpůsobit zkratku"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Zkratka"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Výzva k zadání hesla"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornění"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovek"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné zprávy"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Úložiště"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5c603a8ef55a..dda65e2e0c3b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbejdstilstand"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattelys"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC er deaktiveret"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC er aktiveret"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ingen nye elementer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har ryddet alt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delt skærm øverst"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delt skærm til venstre"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delt skærm til højre"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Afbryd VPN-forbindelse"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Din enhed administreres af <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> bruger <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til at administrere din enhed."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Din administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps og data, der er knyttet til denne enhed, samt enhedens placeringsoplysninger."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Få flere oplysninger"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du har forbindelse til <xliff:g id="VPN_APP">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Åbn VPN-indstillinger"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Din administrator har aktiveret netværksregistrering, som overvåger trafik på din enhed.\n\nKontakt din administrator for at få flere oplysninger."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Du gav en app tilladelse til at konfigurere en VPN-forbindelse.\n\nDenne app kan overvåge din enhed og netværksaktivitet, bl.a. e-mails, apps og websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger.\n\nDu har også forbindelse til et VPN, som kan overvåge din netværksaktivitet."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet med <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din aktivitet på arbejdsnetværket, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Med lyd og pop op-visning"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til underretninger"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Indstillinger for udsættelse"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutter"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutter"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 time"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Udsæt ikke"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"FORTRYD"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Udsat i <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteriforbrug"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparefunktion"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Til"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Fra"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigationslinje"</string>
- <string name="start" msgid="6873794757232879664">"Start"</string>
- <string name="center" msgid="4327473927066010960">"I midten"</string>
- <string name="end" msgid="125797972524818282">"For enden"</string>
- <string name="space" msgid="804232271282109749">"Mellemrumstast"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Til venstre"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Til højre"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Knaptype"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(standard)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Udklipsholder"</item>
+ <item msgid="5742013440802239414">"Tastekode"</item>
+ <item msgid="8748101184830239843">"Menu/tastaturskifter"</item>
+ <item msgid="8175437057325747277">"Ingen"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Opdelt (standard)"</item>
+ <item msgid="6210279084134579668">"Centreret"</item>
+ <item msgid="89143234390889289">"Venstrejusteret"</item>
+ <item msgid="7715533883382410603">"Højrejusteret"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu/tastaturskifter"</string>
- <string name="select_button" msgid="1597989540662710653">"Vælg den knap, du vil tilføje"</string>
- <string name="add_button" msgid="4134946063432258161">"Tilføj knap"</string>
<string name="save" msgid="2311877285724540644">"Gem"</string>
<string name="reset" msgid="2448168080964209908">"Nulstil"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ingen startknap blev fundet"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Du skal have en startknap for at kunne navigere rundt på denne enhed. Tilføj en startknap, før du gemmer."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Juster knappens bredde"</string>
<string name="clipboard" msgid="1313879395099896312">"Udklipsholder"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Med Udklipsholder kan elementerne trækkes direkte til udklipsholderen. Elementerne kan også trækkes direkte ud af udklipsholderen, når den er åben."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Tilpasset navigationsknap"</string>
<string name="keycode" msgid="7335281375728356499">"Tastekode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tastekodeknapper gør det muligt at føje tastaturtaster til navigationslinjen. Når der trykkes på dem, efterligner de den valgte tastaturtast. Først vælges tasten til knappen, og derefter vælges det billede, der skal vises på knappen."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Vælg tastaturknap"</string>
- <string name="preview" msgid="9077832302472282938">"Eksempelvisning"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Træk for at tilføje felter"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Træk herhen for at fjerne"</string>
<string name="qs_edit" msgid="2232596095725105230">"Rediger"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Afvis"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefonen er ved at blive varm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Nogle funktioner er begrænsede, mens telefonen køler ned"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Venstre"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Højre"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Tilpas genvej"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Genvej"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Spørg om adgangskode"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Lagerplads"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8da6e9c0777b..5509a5774fec 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeitsmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtlicht"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ist deaktiviert"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ist aktiviert"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Keine kürzlich verwendeten Elemente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du hast alles gelöscht"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Geteilten Bildschirm oben anzeigen"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Geteilten Bildschirm auf linker Seite anzeigen"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Geteilten Bildschirm auf der rechten Seite anzeigen"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN-Verbindung trennen"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Dein Gerät wird von <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> verwaltet."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> verwaltet dein Gerät mit <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Dein Administrator kann Einstellungen, Zugriffsrechte, Apps und Daten deines Geräts und dessen Standortinformationen überwachen und verwalten."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Weitere Informationen"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du bist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden. Die VPN-App kann deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-Einstellungen öffnen"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"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="4445150119515393526">"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>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"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>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"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>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du bist mit der App \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" verbunden. Diese kann deine persönlichen Netzwerkaktivitäten erfassen, einschließlich E-Mails, Apps und Websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Es ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine berufliche Netzwerkaktivitäten einschließlich E-Mails, Apps und Websites erfassen kann.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Das Gerät bleibt gesperrt, bis du es manuell entsperrst."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Benachrichtigungen schneller erhalten"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Akustisches Signal und Bildschirmbenachrichtigung"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
<string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-Benachrichtigungseinstellungen"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> – <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"Benachrichtigungseinstellungen"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Optionen für spätere Erinnerung bei Benachrichtigungen"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 Minuten"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 Minuten"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 Stunde"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Nicht später erinnern"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"RÜCKGÄNGIG"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Erinnerung in <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akkunutzung"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Der Energiesparmodus ist beim Aufladen nicht verfügbar."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Energiesparmodus"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"An"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Aus"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigationsleiste"</string>
- <string name="start" msgid="6873794757232879664">"Beim Start"</string>
- <string name="center" msgid="4327473927066010960">"Mitte"</string>
- <string name="end" msgid="125797972524818282">"Ende"</string>
- <string name="space" msgid="804232271282109749">"Leerzeichen"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Links"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Rechts"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Schaltflächentyp"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(Standard)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Zwischenablage"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Menü-/Tastaturwechsler"</item>
+ <item msgid="8175437057325747277">"Keine"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Geteilt (Standard)"</item>
+ <item msgid="6210279084134579668">"Zentriert"</item>
+ <item msgid="89143234390889289">"Linksbündig"</item>
+ <item msgid="7715533883382410603">"Rechtsbündig"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menü-/Tastaturwechsler"</string>
- <string name="select_button" msgid="1597989540662710653">"Schaltfläche auswählen"</string>
- <string name="add_button" msgid="4134946063432258161">"Schaltfläche hinzufügen"</string>
<string name="save" msgid="2311877285724540644">"Speichern"</string>
<string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Startbildschirmtaste fehlt"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Um dieses Gerät bedienen zu können, braucht man eine Startbildschirmtaste. Bitte füge vor dem Speichern eine entsprechende Schaltfläche hinzu."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Schaltflächenbreite anpassen"</string>
<string name="clipboard" msgid="1313879395099896312">"Zwischenablage"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Elemente können direkt in die Zwischenablage gezogen werden. Ebenso können sie direkt aus der Zwischenablage gezogen werden, sofern diese geöffnet ist."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Benutzerdefinierte Navigationsschaltfläche"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Mit den Keycode-Schaltflächen kann man der Navigationsleiste Tasten hinzufügen. Wird eine Keycode-Schaltfläche ausgewählt, führt sie die Aktion der entsprechenden Taste aus. Wähle zuerst die Taste für die Schaltfläche aus und dann ein Bild, das auf der Schaltfläche erscheinen soll."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Taste auswählen"</string>
- <string name="preview" msgid="9077832302472282938">"Vorschau"</string>
+ <string name="icon" msgid="8732339849035837289">"Symbol"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Zum Hinzufügen von Kacheln ziehen"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zum Entfernen hierher ziehen"</string>
<string name="qs_edit" msgid="2232596095725105230">"Bearbeiten"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimieren"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Schließen"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Smartphone wird warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Links"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Rechts"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Verknüpfung anpassen"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Verknüpfung"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Zur Passworteingabe auffordern"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Warnmeldungen"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Nachrichten"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Speicher"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bc9d264674fa..1de2dae33f8c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Λειτουργία εργασίας"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Νυχτερινός φωτισμός"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Το NFC είναι απενεργοποιημένο"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Το NFC είναι ενεργοποιημένο"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει διαγραφή όλων των στοιχείων"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Διαχωρισμός οθόνης στην κορυφή"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Διαχωρισμός οθόνης στα αριστερά"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Διαχωρισμός οθόνης στα δεξιά"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Αποσύνδεση VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Η διαχείριση της συσκευής σας γίνεται από <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> χρησιμοποιεί <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> για τη διαχείριση της συσκευής σας."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Ο διαχειριστής μπορεί να παρακολουθεί και να διαχειρίζεται ρυθμίσεις, εταιρική πρόσβαση, εφαρμογές και δεδομένα που σχετίζονται με τη συσκευή, καθώς και τις πληροφορίες τοποθεσίας."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Μάθετε περισσότερα"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="VPN_APP">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Άνοιγμα Ρυθμίσεων VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Ο διαχειριστής σας έχει ενεργοποιήσει την καταγραφή δικτύου, η οποία παρακολουθεί την επισκεψιμότητα στη συσκευή σας.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή σας."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Παραχωρήσατε σε μια εφαρμογή άδεια για τη ρύθμιση σύνδεσης VPN.\n\nΑυτή η εφαρμογή μπορεί να παρακολουθεί τη δραστηριότητα της συσκευής και του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής έχει τη δυνατότητα παρακολούθησης της δραστηριότητας του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή.\n\nΕπίσης, είστε συνδεδεμένοι σε VPN, το οποίο μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <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="4946600443852045903">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <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_disabled" msgid="7412534203633528135">"Η συσκευή θα παραμείνει κλειδωμένη έως ότου την ξεκλειδώσετε μη αυτόματα"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Λάβετε ειδοποιήσεις γρηγορότερα"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Αναπαραγωγή ήχου και εμφάνιση στην οθόνη"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
<string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Στοιχεία ελέγχου κοινοποίησης <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"στοιχεία ελέγχου ειδοποιήσεων"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"επιλογές αφύπνισης ειδοποιήσεων"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 λεπτά"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 λεπτά"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ώρα"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Χωρίς αφύπνιση"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ΑΝΑΙΡΕΣΗ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Σε αφύπνιση για <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Χρήση της μπαταρίας"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Η εξοικονόμηση μπαταρίας δεν είναι διαθέσιμη κατά τη διάρκεια της φόρτισης"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Εξοικονόμηση μπαταρίας"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Ενεργή"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Απενεργοποίηση"</string>
<string name="nav_bar" msgid="1993221402773877607">"Γραμμή πλοήγησης"</string>
- <string name="start" msgid="6873794757232879664">"Έναρξη"</string>
- <string name="center" msgid="4327473927066010960">"Κέντρο"</string>
- <string name="end" msgid="125797972524818282">"Λήξη"</string>
- <string name="space" msgid="804232271282109749">"Διαχωριστικό"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Διάταξη"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Αριστερά"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Δεξιά"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Τύπος κουμπιού"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(προεπιλογή)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Πρόχειρο"</item>
+ <item msgid="5742013440802239414">"Κωδικός-πλήκτρο"</item>
+ <item msgid="8748101184830239843">"Εναλλαγή μενού/πληκτρολογίου"</item>
+ <item msgid="8175437057325747277">"Κανένα"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Διαχωρισμένο (προεπιλογή)"</item>
+ <item msgid="6210279084134579668">"Στοίχιση στο κέντρο"</item>
+ <item msgid="89143234390889289">"Στοίχιση αριστερά"</item>
+ <item msgid="7715533883382410603">"Στοίχιση δεξιά"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Εναλλαγή μενού/πληκτρολογίου"</string>
- <string name="select_button" msgid="1597989540662710653">"Επιλογή κουμπιού για προσθήκη"</string>
- <string name="add_button" msgid="4134946063432258161">"Προσθήκη κουμπιού"</string>
<string name="save" msgid="2311877285724540644">"Αποθήκευση"</string>
<string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Δεν βρέθηκε κουμπί αρχ. οθόνης"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Απαιτείται κουμπί αρχικής οθόνης για να είναι δυνατή η πλοήγηση σε αυτήν τη συσκευή. Προσθέστε ένα κουμπί αρχικής οθόνης πριν από την αποθήκευση."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Προσαρμογή πλάτους κουμπιού"</string>
<string name="clipboard" msgid="1313879395099896312">"Πρόχειρο"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Το Πρόχειρο επιτρέπει να σύρετε στοιχεία απευθείας στο πρόχειρο. Μπορείτε, επίσης, να σύρετε στοιχεία από το πρόχειρο, όταν υπάρχουν στοιχεία σε αυτό."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Προσαρμοσμένο κουμπί πλοήγησης"</string>
<string name="keycode" msgid="7335281375728356499">"Κωδικός-πλήκτρο"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Τα κουμπιά κωδικού-πλήκτρου επιτρέπουν την προσθήκη πλήκτρου πληκτρολογίου στη γραμμή πλοήγησης. Όταν τα πατάτε, τα κουμπιά προσομοιώνουν το επιλεγμένη πλήκτρο πληκτρολογίου. Πρώτα πρέπει να επιλεγεί το πλήκτρο για το κουμπί. Στη συνέχεια, εμφανίζεται μια εικόνα στο κουμπί."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Επιλογή κουμπιού πληκτρολογίου"</string>
- <string name="preview" msgid="9077832302472282938">"Προεπισκόπηση"</string>
+ <string name="icon" msgid="8732339849035837289">"Εικονίδιο"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Σύρετε για να προσθέσετε πλακίδια"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Σύρετε εδώ για κατάργηση"</string>
<string name="qs_edit" msgid="2232596095725105230">"Επεξεργασία"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Ελαχιστοποίηση"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Παράβλεψη"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Αύξηση θερμοκρασίας τηλεφώνου"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Αριστερά"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Δεξιά"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Προσαρμογή συντόμευσης"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Συντόμευση"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Προτροπή για κωδικό πρόσβασης"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Ειδοποιήσεις"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Στιγμιότυπα οθόνης"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Γενικά μηνύματα"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Αποθηκευτικός χώρος"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index a19ac0b495c5..a79caad47130 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Split screen to the top"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Split screen to the left"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Split screen to the right"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Make sound and pop on screen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Done"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"notification controls"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"notification snooze options"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hour"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Don\'t snooze"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"UNDO"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Snoozed for <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
- <string name="start" msgid="6873794757232879664">"Start"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"End"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Left"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Right"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Button type"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(default)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Clipboard"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Menu/Keyboard Switcher"</item>
+ <item msgid="8175437057325747277">"None"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Divided (default)"</item>
+ <item msgid="6210279084134579668">"Centred"</item>
+ <item msgid="89143234390889289">"Left-aligned"</item>
+ <item msgid="7715533883382410603">"Right-aligned"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu / Keyboard Switcher"</string>
- <string name="select_button" msgid="1597989540662710653">"Select button to add"</string>
- <string name="add_button" msgid="4134946063432258161">"Add button"</string>
<string name="save" msgid="2311877285724540644">"Save"</string>
<string name="reset" msgid="2448168080964209908">"Reset"</string>
- <string name="no_home_title" msgid="1563808595146071549">"No home button found"</string>
- <string name="no_home_message" msgid="5408485011659260911">"A home button is required to be able to navigate this device. Please add a home button before saving."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Adjust button width"</string>
<string name="clipboard" msgid="1313879395099896312">"Clipboard"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Customised navigation button"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Keycode buttons allow keyboard keys to be added to the Navigation Bar. When pressed they emulate the selected keyboard key. First the key must be selected for the button, followed by an image to be shown on the button."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
- <string name="preview" msgid="9077832302472282938">"Preview"</string>
+ <string name="icon" msgid="8732339849035837289">"Icon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Left"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Right"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Customise shortcut"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Shortcut"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a19ac0b495c5..a79caad47130 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Split screen to the top"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Split screen to the left"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Split screen to the right"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Make sound and pop on screen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Done"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"notification controls"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"notification snooze options"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hour"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Don\'t snooze"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"UNDO"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Snoozed for <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
- <string name="start" msgid="6873794757232879664">"Start"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"End"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Left"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Right"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Button type"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(default)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Clipboard"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Menu/Keyboard Switcher"</item>
+ <item msgid="8175437057325747277">"None"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Divided (default)"</item>
+ <item msgid="6210279084134579668">"Centred"</item>
+ <item msgid="89143234390889289">"Left-aligned"</item>
+ <item msgid="7715533883382410603">"Right-aligned"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu / Keyboard Switcher"</string>
- <string name="select_button" msgid="1597989540662710653">"Select button to add"</string>
- <string name="add_button" msgid="4134946063432258161">"Add button"</string>
<string name="save" msgid="2311877285724540644">"Save"</string>
<string name="reset" msgid="2448168080964209908">"Reset"</string>
- <string name="no_home_title" msgid="1563808595146071549">"No home button found"</string>
- <string name="no_home_message" msgid="5408485011659260911">"A home button is required to be able to navigate this device. Please add a home button before saving."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Adjust button width"</string>
<string name="clipboard" msgid="1313879395099896312">"Clipboard"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Customised navigation button"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Keycode buttons allow keyboard keys to be added to the Navigation Bar. When pressed they emulate the selected keyboard key. First the key must be selected for the button, followed by an image to be shown on the button."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
- <string name="preview" msgid="9077832302472282938">"Preview"</string>
+ <string name="icon" msgid="8732339849035837289">"Icon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Left"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Right"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Customise shortcut"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Shortcut"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index a19ac0b495c5..a79caad47130 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Split screen to the top"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Split screen to the left"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Split screen to the right"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Make sound and pop on screen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Done"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"notification controls"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"notification snooze options"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hour"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Don\'t snooze"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"UNDO"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Snoozed for <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Battery usage"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
- <string name="start" msgid="6873794757232879664">"Start"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"End"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Left"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Right"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Button type"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(default)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Clipboard"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Menu/Keyboard Switcher"</item>
+ <item msgid="8175437057325747277">"None"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Divided (default)"</item>
+ <item msgid="6210279084134579668">"Centred"</item>
+ <item msgid="89143234390889289">"Left-aligned"</item>
+ <item msgid="7715533883382410603">"Right-aligned"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu / Keyboard Switcher"</string>
- <string name="select_button" msgid="1597989540662710653">"Select button to add"</string>
- <string name="add_button" msgid="4134946063432258161">"Add button"</string>
<string name="save" msgid="2311877285724540644">"Save"</string>
<string name="reset" msgid="2448168080964209908">"Reset"</string>
- <string name="no_home_title" msgid="1563808595146071549">"No home button found"</string>
- <string name="no_home_message" msgid="5408485011659260911">"A home button is required to be able to navigate this device. Please add a home button before saving."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Adjust button width"</string>
<string name="clipboard" msgid="1313879395099896312">"Clipboard"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Customised navigation button"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Keycode buttons allow keyboard keys to be added to the Navigation Bar. When pressed they emulate the selected keyboard key. First the key must be selected for the button, followed by an image to be shown on the button."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
- <string name="preview" msgid="9077832302472282938">"Preview"</string>
+ <string name="icon" msgid="8732339849035837289">"Icon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Left"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Right"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Customise shortcut"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Shortcut"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 7379347148cf..1c4d42ad94a5 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"La tecnología NFC está inhabilitada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"La tecnología NFC está habilitada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Todo borrado"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir pantalla en la parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir pantalla a la izquierda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir pantalla a la derecha"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> administra tu dispositivo."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para administrar tu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Tu administrador controla la configuración, el acceso corporativo, las apps, los datos asociados a tu dispositivo y la información de ubicación."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Más información"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estás conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que puede controlar la actividad de tu red, incluidos los correos electrónicos, las apps y los sitios web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configuración de VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"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="4445150119515393526">"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>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<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>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"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>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Te conectaste a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de tu red personal, incluidos los correos electrónicos, las apps y los sitios web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede controlar la actividad de tu red laboral, como los correos electrónicos, las apps y los sitios web.\n\nPara obtener más información, comunícate con tu administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién tienes conexión a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar la actividad de la red personal."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositivo permanecerá bloqueado hasta que lo desbloquees manualmente."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Recibe notificaciones más rápido"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controles de notificación"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opciones para posponer notificaciones"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"No posponer"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESHACER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Posponer <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no está disponible durante la carga"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activado"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desactivado"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
- <string name="start" msgid="6873794757232879664">"Iniciar"</string>
- <string name="center" msgid="4327473927066010960">"Centro"</string>
- <string name="end" msgid="125797972524818282">"Finalizar"</string>
- <string name="space" msgid="804232271282109749">"Separador"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Diseño"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Izquierda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Derecha"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botón"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predeterminada)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Portapapeles"</item>
+ <item msgid="5742013440802239414">"Clave de código"</item>
+ <item msgid="8748101184830239843">"Cambio de teclado/menú"</item>
+ <item msgid="8175437057325747277">"Ninguno"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividido (predeterminado)"</item>
+ <item msgid="6210279084134579668">"Centrado"</item>
+ <item msgid="89143234390889289">"Alineado a la izquierda"</item>
+ <item msgid="7715533883382410603">"Alineado a la derecha"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menú/Cambio de teclado"</string>
- <string name="select_button" msgid="1597989540662710653">"Elige un botón para agregar"</string>
- <string name="add_button" msgid="4134946063432258161">"Agregar botón"</string>
<string name="save" msgid="2311877285724540644">"Guardar"</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
- <string name="no_home_title" msgid="1563808595146071549">"No se encontró botón de inicio"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Se requiere un botón de inicio para navegar en este dispositivo. Agrega un botón de inicio antes de guardar el contenido."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustar ancho del botón"</string>
<string name="clipboard" msgid="1313879395099896312">"Portapapeles"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"El botón de Portapapeles permite arrastrar elementos directamente hacia el portapapeles, y fuera de él cuando estén presentes."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botón de navegación personalizado"</string>
<string name="keycode" msgid="7335281375728356499">"Clave de código"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Los botones de las claves de código permiten agregar las teclas del teclado a la Barra de navegación. Al presionarlas, emulan la tecla seleccionada. Primero, debes elegir la tecla para el botón y, luego, asignarle una imagen."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón del teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
+ <string name="icon" msgid="8732339849035837289">"Ícono"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastra los mosaicos para agregarlos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Descartar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"El teléfono se está calentando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Se limitarán algunas funciones mientras se enfría el teléfono"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Izquierda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Derecha"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar acceso directo"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Acceso directo"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar contraseña"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ea1d08f18ebf..28299b7acf12 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -212,10 +212,10 @@
<string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"Bluetooth conectado."</string>
<string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"Bluetooth desactivado."</string>
<string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"Bluetooth activado."</string>
- <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Informes de Ubicación desactivados."</string>
- <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Informes de Ubicación activados."</string>
- <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Informes de Ubicación desactivados."</string>
- <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Informes de Ubicación activados."</string>
+ <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Informes de ubicación desactivados."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Informes de ubicación activados."</string>
+ <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Informes de ubicación desactivados."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Informes de ubicación activados."</string>
<string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"La alarma sonará a la(s) <xliff:g id="TIME">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Cerrar panel."</string>
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo."</string>
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"La conexión NFC está inhabilitada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"La conexión NFC está habilitada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Has rechazado todo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir la pantalla en la parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir la pantalla a la izquierda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir la pantalla a la derecha"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Tu dispositivo está administrado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para administrar tu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Tu administrador puede controlar y gestionar su configuración, acceso corporativo y aplicaciones, así como los datos y la ubicación del dispositivo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Más información"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Te has conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que puede controlar tu actividad de red, como los correos electrónicos, las aplicaciones y los sitios web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir Ajustes de red VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Tu administrador ha activado el registro de la red para supervisar el tráfico en tu dispositivo.\n\nPonte en contacto con él para obtener más información."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Has concedido permiso a una aplicación para configurar una conexión VPN.\n\nEsta aplicación puede controlar tu dispositivo y tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>,\n\n que puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador.\n\nTambién estás conectado a una red VPN, que puede supervisar tu actividad de red."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar tu actividad de red en el trabajo, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nTú también estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositivo permanecerá bloqueado hasta que se desbloquee manualmente"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Recibe notificaciones más rápido"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"Controles de las notificaciones"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Opciones para posponer las notificaciones"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"No posponer"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESHACER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Volverá a mostrarse en <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
- <string name="start" msgid="6873794757232879664">"Inicio"</string>
- <string name="center" msgid="4327473927066010960">"Centro"</string>
- <string name="end" msgid="125797972524818282">"Fin"</string>
- <string name="space" msgid="804232271282109749">"Espacio"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Diseño"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Izquierda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Derecha"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botón"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predeterminada)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Portapapeles"</item>
+ <item msgid="5742013440802239414">"Código de teclado"</item>
+ <item msgid="8748101184830239843">"Menú/Cambio de teclado"</item>
+ <item msgid="8175437057325747277">"Ninguno"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividida (predeterminada)"</item>
+ <item msgid="6210279084134579668">"Centrada"</item>
+ <item msgid="89143234390889289">"Alineada a la izquierda"</item>
+ <item msgid="7715533883382410603">"Alineada a la derecha"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menú/Cambio de teclado"</string>
- <string name="select_button" msgid="1597989540662710653">"Selecciona botón para añadirlo"</string>
- <string name="add_button" msgid="4134946063432258161">"Añadir botón"</string>
<string name="save" msgid="2311877285724540644">"Guardar"</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Botón de inicio no encontrado"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Se necesita un botón de inicio para poder navegar por el dispositivo. Añádelo antes de guardar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustar el ancho del botón"</string>
<string name="clipboard" msgid="1313879395099896312">"Portapapeles"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Con este botón puedes arrastrar los elementos directamente al portapapeles y, si está presente, fuera de él."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botón de navegación personalizada"</string>
<string name="keycode" msgid="7335281375728356499">"Código de teclado"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Con los botones del código de teclado puedes añadir teclas a la barra de navegación que, al pulsarlas, emulan la tecla seleccionada. Primero debes seleccionar la tecla para el botón y, a continuación, la imagen que se va a mostrar en él."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón de teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
+ <string name="icon" msgid="8732339849035837289">"Icono"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastra para añadir funciones"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar una función"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Rechazar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"El teléfono se está calentando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Se limitan algunas funciones mientras el teléfono se enfría"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Izquierda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Derecha"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar el acceso directo"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Acceso directo"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar contraseña"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index e6f03a1515e4..9a888c55dc20 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Töörežiim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Öövalgus"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC on keelatud"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC on lubatud"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hiljutisi üksusi pole"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Olete kõik ära kustutanud"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Poolita ekraan üles"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Poolita ekraan vasakule"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Poolita ekraan paremale"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Katkesta VPN-i ühendus"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Teie seadet haldab rakendus <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Organisatsioon <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> kasutab teie seadme haldamiseks rakendust <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administraator saab jälgida ja hallata teie seadmega seotud seadeid, ettevõtte juurdepääsu, rakendusi ja andmeid ning seadme asukohateavet."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Lisateave"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Olete ühendatud rakendusega <xliff:g id="VPN_APP">%1$s</xliff:g>, mis saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ava VPN-i seaded"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Teie administraator on sisse lülitanud võrgu logimise funktsiooni, mis jälgib teie seadmes liiklust.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Andsite rakendusele loa VPN-i ühenduse seadistamiseks.\n\nSee rakendus võib jälgida teie seadet ja võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Teie tööprofiili haldab <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga.\n\nTeil on ühendus ka VPN-iga, mis saab teie võrgutegevusi jälgida."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Teie tööprofiili haldab <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nTeie seade on ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Seade jääb lukku, kuni selle käsitsi avate"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Saate märguandeid kiiremini"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Esita heli ja tõsta märguanne esile"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtnupud"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"märguannete juhtnupud"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"märguannete edasilükkamise valikud"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutit"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutit"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"Üks tund"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ära lükka edasi"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"VÕTA TAGASI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Edasi lükatud <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akukasutus"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akusäästja pole laadimise ajal saadaval"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akusäästja"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Sees"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Väljas"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigeerimisriba"</string>
- <string name="start" msgid="6873794757232879664">"Algus"</string>
- <string name="center" msgid="4327473927066010960">"Keskkoht"</string>
- <string name="end" msgid="125797972524818282">"Lõpp"</string>
- <string name="space" msgid="804232271282109749">"Tühik"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Paigutus"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Vasak"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Parem"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Nupu tüüp"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(vaikeseade)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Lõikelaud"</item>
+ <item msgid="5742013440802239414">"Võtmekood"</item>
+ <item msgid="8748101184830239843">"Menüü/klaviatuuri vahetaja"</item>
+ <item msgid="8175437057325747277">"Mitte ükski"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Jagatud (vaikeseade)"</item>
+ <item msgid="6210279084134579668">"Keskel"</item>
+ <item msgid="89143234390889289">"Vasakule joondatud"</item>
+ <item msgid="7715533883382410603">"Paremale joondatud"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menüü / klaviatuuri vahetaja"</string>
- <string name="select_button" msgid="1597989540662710653">"Lisatava nupu valimine"</string>
- <string name="add_button" msgid="4134946063432258161">"Lisa nupp"</string>
<string name="save" msgid="2311877285724540644">"Salvesta"</string>
<string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Avaekraani nuppu ei leitud"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Seadmes navigeerimiseks on vajalik avaekraani nupp. Lisage enne salvestamist avaekraani nupp."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Nupu laiuse reguleerimine"</string>
<string name="clipboard" msgid="1313879395099896312">"Lõikelaud"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Lõikelaud võimaldab üksused lohistada otse lõikelauale. Kui üksused on lõikelaual, saab need sealt ka ära lohistada."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Kohandatud navigeerimisnupp"</string>
<string name="keycode" msgid="7335281375728356499">"Võtmekood"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Võtmekoodi nupud võimaldavad klaviatuuriklahvid lisada navigeerimisribale. Nupu vajutamisel jäljendavad need valitud klaviatuuriklahvi. Esmalt tuleb nupu jaoks valida klahv ja seejärel kujutis, mis nupul kuvada."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Klaviatuuri nupu valimine"</string>
- <string name="preview" msgid="9077832302472282938">"Eelvaade"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikoon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lohistage paanide lisamiseks"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lohistage eemaldamiseks siia"</string>
<string name="qs_edit" msgid="2232596095725105230">"Muutmine"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeeri"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Loobu"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon soojeneb"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Mõned funktsioonid on piiratud, kuni telefon jahtub"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vasak"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Parem"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Otsetee kohandamine"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Otsetee"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Parooli viip"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Teatised"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekraanipildid"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Üldised sõnumid"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Salvestusruum"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index eff5931bdd23..45ec067e55d9 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Lan modua"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gaueko argia"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Desgaituta dago NFC"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Gaituta dago NFC"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ez dago azkenaldi honetako ezer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Dena garbitu duzu"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Banandu pantaila eta ezarri goian"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Banandu pantaila eta ezarri ezkerrean"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Banandu pantaila eta ezarri eskuinean"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Deskonektatu VPN sarea"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> aplikazioak kudeatzen du gailu hau."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundeak <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> erabiltzen du gailua kudeatzeko."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Gailuko ezarpenak, enpresa-sarbidea, aplikazioak eta datuak gainbegira eta kudea ditzake administratzaileak, baita gailuaren kokapen-informazioa ere."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Informazio gehiago"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ireki VPN ezarpenak"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikazio bati VPN konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen du zure laneko profila.\n\nAdministratzaileak sareko jarduerak kontrola diezazkizuke, besteak beste, posta elektronikoa, aplikazioak eta webguneak.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nHorrez gain, VPN batera zaude konektatuta, eta hark ere kontrola ditzake zure sareko jarduerak."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN konexioa"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen du zure laneko profila. Erakundea <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora dago konektatuta, bera arduratzen baita laneko sareko jarduerak kontrolatzeaz, besteak beste, posta elektronikoa, aplikazioak eta webguneak.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nHorrez gain, sarean egiten dituzun jarduera pertsonalak kontrola ditzakeen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora konektatuta zaude."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Gailua blokeatuta egongo da eskuz desblokeatu arte"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Eskuratu jakinarazpenak azkarrago"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Egin soinua eta erakutsi pantailan"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
<string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"jakinarazpena kontrolatzeko aukerak"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"jakinarazpena atzeratzeko aukerak"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutu"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutu"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ordu"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ez atzeratu"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESEGIN"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>z atzeratu da"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Bateriaren erabilera"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Bateria-aurrezlea"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aktibatuta"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desaktibatuta"</string>
<string name="nav_bar" msgid="1993221402773877607">"Nabigazio-barra"</string>
- <string name="start" msgid="6873794757232879664">"Hasi"</string>
- <string name="center" msgid="4327473927066010960">"Erdiratu"</string>
- <string name="end" msgid="125797972524818282">"Amaitu"</string>
- <string name="space" msgid="804232271282109749">"Bereizgailua"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Diseinua"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Ezkerrera botoia"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Eskuinera botoia"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Botoi mota"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(lehenetsia)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Arbela"</item>
+ <item msgid="5742013440802239414">"Tekla-kodea"</item>
+ <item msgid="8748101184830239843">"Menu- edo teklatu-aldatzailea"</item>
+ <item msgid="8175437057325747277">"Bat ere ez"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Zatitua (lehenetsia)"</item>
+ <item msgid="6210279084134579668">"Erdiratua"</item>
+ <item msgid="89143234390889289">"Ezkerrean lerrokatua"</item>
+ <item msgid="7715533883382410603">"Eskuinean lerrokatua"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu- edo teklatu-aldatzailea"</string>
- <string name="select_button" msgid="1597989540662710653">"Hautatu gehitu beharreko botoia"</string>
- <string name="add_button" msgid="4134946063432258161">"Gehitu botoia"</string>
<string name="save" msgid="2311877285724540644">"Gorde"</string>
<string name="reset" msgid="2448168080964209908">"Berrezarri"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ez da aurkitu hasiera-botoirik"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Hasiera-botoia behar da gailuan ibiltzeko. Gorde aurretik, gehi ezazu bat."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Doitu botoiaren zabalera"</string>
<string name="clipboard" msgid="1313879395099896312">"Arbela"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Arbelari esker, elementuak arbelera zuzenean arrasta daitezke. Elementuak arbelean daudenean, handik zuzenean atera daitezke."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Nabigazio-botoi pertsonalizatua"</string>
<string name="keycode" msgid="7335281375728356499">"Tekla-kodea"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tekla-kodeko botoiekin, teklatuko teklak gehi daitezke nabigazio-barran. Sakatzen direnean, hautatutako teklaren funtzioa gauzatzen dute. Lehendabizi, botoiaren tekla hautatu behar da eta, gero, botoian agertuko den irudia."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Hautatu teklatuko botoia"</string>
- <string name="preview" msgid="9077832302472282938">"Aurrebista"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikonoa"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastatu lauzak hemen gehitzeko"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kentzeko, arrastatu hona"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editatu"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizatu"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Baztertu"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Berotzen ari da telefonoa"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Ezkerraldea"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Eskuinaldea"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Pertsonalizatu lasterbidea"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Lasterbidea"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Eskatu pasahitza"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Abisuak"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Pantaila-argazkiak"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mezu orokorrak"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 8cba6a9ef88f..cd125b566284 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"حالت کار"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"نور شب"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"‏NFC غیرفعال است"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"‏NFC فعال است"</string>
<string name="recents_empty_message" msgid="808480104164008572">"بدون موارد اخیر"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"همه‌چیز را پاک کرده‌اید"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"تقسیم کردن صفحه به بالا"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"تقسیم کردن صفحه به چپ"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"تقسیم کردن صفحه به راست"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"‏قطع اتصال VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> دستگاه شما را مدیریت می‌کند."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> با استفاده از <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> دستگاهتان را مدیریت می‌کند."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"سرپرست سیستم شما می‌تواند تنظیمات، دسترسی شرکتی، برنامه‌ها، داده‌های مرتبط با دستگاه و اطلاعات مکان دستگاه شما را مدیریت کند و بر آن‌ها نظارت داشته باشد."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"بیشتر بدانید"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"به <xliff:g id="VPN_APP">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏باز کردن تنظیمات VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"سرپرست سیستم شما گزارش‌گیری شبکه را (که بر ترافیک دستگاهتان نظارت می‌کند) روشن کرده است.\n\nبرای اطلاعات بیشتر، با سرپرست خود تماس بگیرید."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"‏شما به برنامه‌ای برای تنظیم اتصال VPN اجازه دادید.\n\n این برنامه می‌تواند دستگاه و فعالیت شبکه‌تان را کنترل کند، از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"‏نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود.\n\nسرپرست سیستم شما می‌تواند بر فعالیت شبکه شما (ازجمله رایانامه‌ها، برنامه‌ها و وب‌سایت‌ها) نظارت داشته باشد.\n\nبرای اطلاعات بیشتر، با سرپرست خود تماس بگیرید.\n\nهمچنین به VPN متصل هستید که می‌تواند بر فعالیت شبکه شما نظارت داشته باشد."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"نمایه کاری شما توسط <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="4946600443852045903">"نمایه کاری شما توسط <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_disabled" msgid="7412534203633528135">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"دریافت سریع‌تر اعلان‌ها"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"پخش صدا و صفحه بازشو"</string>
<string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
<string name="notification_done" msgid="5279426047273930175">"تمام"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"کنترل‌های اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"کنترل‌های اعلان"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"گزینه‌های تعویق اعلان"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"۱۵ دقیقه"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"۳۰ دقیقه"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"۱ ساعت"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"به تعویق نیفتد"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"واگرد"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> به تعویق افتاد"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"مصرف باتری"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"هنگام شارژ شدن، «بهینه‌سازی باتری» در دسترس نیست"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"بهینه‌سازی باتری"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"روشن"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"خاموش"</string>
<string name="nav_bar" msgid="1993221402773877607">"نوار پیمایش"</string>
- <string name="start" msgid="6873794757232879664">"شروع"</string>
- <string name="center" msgid="4327473927066010960">"وسط"</string>
- <string name="end" msgid="125797972524818282">"پایان"</string>
- <string name="space" msgid="804232271282109749">"جداکننده"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"طرح‌بندی"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"چپ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"راست"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"نوع دکمه"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(پیش‌فرض)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"کلیپ‌بورد"</item>
+ <item msgid="5742013440802239414">"کد کلید"</item>
+ <item msgid="8748101184830239843">"جابه‌جاکننده منو / صفحه‌کلید"</item>
+ <item msgid="8175437057325747277">"هیچ‌کدام"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"تقسیم‌شده (پیش‌فرض)"</item>
+ <item msgid="6210279084134579668">"ترازشده در مرکز"</item>
+ <item msgid="89143234390889289">"ترازشده در چپ"</item>
+ <item msgid="7715533883382410603">"ترازشده در راست"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"جابه‌جاکننده منو / صفحه‌کلید"</string>
- <string name="select_button" msgid="1597989540662710653">"دکمه را برای افزودن انتخاب کنید"</string>
- <string name="add_button" msgid="4134946063432258161">"دکمه افزودن"</string>
<string name="save" msgid="2311877285724540644">"ذخیره کردن"</string>
<string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
- <string name="no_home_title" msgid="1563808595146071549">"دکمه صفحه اصلی‌ای پیدا نشد"</string>
- <string name="no_home_message" msgid="5408485011659260911">"برای پیمایش در این دستگاه به دکمه صفحه اصلی نیاز است. لطفاً قبل از ذخیره کردن، یک دکمه صفحه اصلی اضافه کنید."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"تنظیم پهنای دکمه"</string>
<string name="clipboard" msgid="1313879395099896312">"کلیپ‌بورد"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"«کلیپ‌بورد» امکان می‌دهد موارد به‌طور مستقیم به کلیپ‌بورد کشیده شوند. اگر مواردی در کلیپ‌بورد وجود داشته باشند می‌توانند به‌طور مستقیم به خارج از آن نیز کشیده شوند."</string>
<string name="accessibility_key" msgid="5701989859305675896">"دکمه پیمایش سفارشی"</string>
<string name="keycode" msgid="7335281375728356499">"کد کلید"</string>
- <string name="keycode_description" msgid="1403795192716828949">"دکمه «کد دکمه» به کلیدهای صفحه‌کلید امکان می‌دهند به «نوار پیمایش» اضافه شوند. وقتی فشار داده می‌شوند رفتار کلید صفحه‌کلید انتخاب‌شده را تقلید می‌کنند. ابتدا باید کلید را برای دکمه انتخاب کرد و به دنبال آن باید تصویری برای نشان داده شدن روی دکمه انتخاب شود."</string>
- <string name="select_keycode" msgid="7413765103381924584">"کلید صفحه‌کلید را انتخاب کنید"</string>
- <string name="preview" msgid="9077832302472282938">"پیش‌نمایش"</string>
+ <string name="icon" msgid="8732339849035837289">"نماد"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"برای افزودن کاشی، بکشید"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"برای حذف، به اینجا بکشید"</string>
<string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"کوچک کردن"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"نپذیرفتن"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"تلفن درحال گرم شدن است"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"وقتی تلفن درحال خنک شدن است، بعضی از قابلیت‌ها محدود می‌شوند"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"تلفنتان به‌طور خودکار سعی می‌کند خنک شود. همچنان می‌توانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادی‌اش از سرگرفته می‌شود."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"چپ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"راست"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"سفارشی کردن میان‌بر"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"میان‌بر"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"درخواست وارد کردن گذرواژه"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"هشدارها"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"عکس‌های صفحه‌نمایش"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"پیام‌های عمومی"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"فضای ذخیره‌سازی"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 89178d61086a..623ee51ebe0c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Työtila"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Yövalo"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC on poistettu käytöstä"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC on käytössä"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ei viimeaikaisia kohteita"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Kaikki on hoidettu."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Jaa näyttö ylös"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Jaa näyttö vasemmalle"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Jaa näyttö oikealle"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Katkaise VPN-yhteys"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Laitettasi hallinnoi <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> hallinnoi laitettasi sovelluksen <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> avulla."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Järjestelmänvalvoja voi valvoa ja hallita asetuksia, yrityskäyttöä, sovelluksia sekä laitteeseen yhdistettyjä tietoja ja sen sijaintitietoja."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Lisätietoja"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Olet yhteydessä sovellukseen <xliff:g id="VPN_APP">%1$s</xliff:g>, joka voi valvoa verkkotoimintaasi, esimerkiksi sähköposteja, sovelluksia ja verkkosivustoja."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Avaa VPN-asetukset"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Järjestelmänvalvoja on ottanut käyttöön verkkolokitietojen tallentamisen. Sen avulla seurataan laitteellasi tapahtuvaa liikennettä.\n\nPyydä lisätietoja järjestelmänvalvojalta."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Olet myöntänyt sovellukselle oikeuden VPN-yhteyden muodostamiseen.\n\nSovellus voi valvoa laitettasi ja toimintaasi verkossa, esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Työprofiiliasi hallitsee <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvoja voi valvoa sähköpostin, sovellusten ja verkkosivustojen käyttöä sekä muuta toimintaasi verkossa.\n\nPyydä lisätietoja järjestelmänvalvojalta.\n\nOlet myös yhteydessä VPN:ään, joka voi valvoa toimintaasi verkossa."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi esimerkiksi seurata avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Työprofiiliasi hallitsee <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profiili on yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa sähköpostin, sovellusten ja verkkosivustojen käyttöä sekä muuta toimintaasi verkossa.\n\nPyydä lisätietoja järjestelmänvalvojalta."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Laite pysyy lukittuna, kunnes se avataan käsin"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Näe ilmoitukset nopeammin"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Ääni, ilmoitus näkyy näytöllä"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ilmoitusten hallinta"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"Ilmoitusten hallinta"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Ilmoitusten torkkuasetukset"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuuttia"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuuttia"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 tunti"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ei torkkua"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"KUMOA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Torkku: <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akun käyttö"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Virransäästö ei ole käytettävissä latauksen aikana."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Virransäästö"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Käytössä"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Pois käytöstä"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigointipalkki"</string>
- <string name="start" msgid="6873794757232879664">"Alussa"</string>
- <string name="center" msgid="4327473927066010960">"Keskellä"</string>
- <string name="end" msgid="125797972524818282">"Lopussa"</string>
- <string name="space" msgid="804232271282109749">"Tyhjä väli"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Asettelu"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Vasen"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Oikea"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Painikkeen tyyppi"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(oletus)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Leikepöytä"</item>
+ <item msgid="5742013440802239414">"Näppäinkoodi"</item>
+ <item msgid="8748101184830239843">"Valikko/näppäimistövalitsin"</item>
+ <item msgid="8175437057325747277">"Ei mitään"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Jaettu (oletus)"</item>
+ <item msgid="6210279084134579668">"Keskitetty"</item>
+ <item msgid="89143234390889289">"Tasattu vasemmalle"</item>
+ <item msgid="7715533883382410603">"Tasattu oikealle"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Valikko/Näppäimistövalitsin"</string>
- <string name="select_button" msgid="1597989540662710653">"Valitse lisättävä painike"</string>
- <string name="add_button" msgid="4134946063432258161">"Lisää painike"</string>
<string name="save" msgid="2311877285724540644">"Tallenna"</string>
<string name="reset" msgid="2448168080964209908">"Palauta"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ei aloitusnäyttöpainiketta"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Laitteessa navigointi edellyttää aloitusnäyttöpainiketta. Lisää aloitusnäyttöpainike ennen tallentamista."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Muokkaa painikkeen leveyttä"</string>
<string name="clipboard" msgid="1313879395099896312">"Leikepöytä"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Leikepöytä sallii kohteiden vetämisen suoraan leikepöydälle. Kohteet voi vetää myös suoraan pois leikepöydältä, kun se on käytössä."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Muokattu navigointipainike"</string>
<string name="keycode" msgid="7335281375728356499">"Näppäinkoodi"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Näppäinkoodi-painikkeet sallivat näppäimistön näppäimien lisäämisen navigointipalkkiin. Kun painiketta painetaan, se jäljittelee valittua näppäintä. Valitse ensin painikkeen kohteena oleva näppäin, sitten painikkeessa näkyvä kuva."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Valitse näppäimistön näppäin"</string>
- <string name="preview" msgid="9077832302472282938">"Esikatselu"</string>
+ <string name="icon" msgid="8732339849035837289">"Kuvake"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lisää osioita vetämällä"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Poista vetämällä tähän."</string>
<string name="qs_edit" msgid="2232596095725105230">"Muokkaa"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Pienennä"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ohita"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Puhelin lämpenee"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana."</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vasen"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Oikea"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Muokkaa pikakuvaketta"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Pikakuvake"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Kysy salasanaa"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Ilmoitukset"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Kuvakaappaukset"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Yleiset viestit"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Tallennustila"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a26f15504d2b..5d4867c0d27b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC désactivée"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC activée"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Écran partagé dans le haut"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Écran partagé à la gauche"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Écran partagé à la droite"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Déconnecter le RPV"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Votre appareil est géré par <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilise <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pour gérer votre appareil."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"L\'admin. de l\'entreprise peut surv. et gérer les param., l\'accès, les applis et les données de cet app., y compris sa localisation"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"En savoir plus"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Vous êtes connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>, qui peut contrôler votre activité réseau, y compris les courriels, les applications et les sites Web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Paramètres RPV ouverts"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, communiquez avec lui."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Vous avez autorisé une application à configurer une connexion RPV.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut surveiller votre activité sur le réseau, y compris les courriels que vous échangez, les applications que vous utilisez et les sites Web que vous visitez.\n\nPour en savoir plus, communiquez avec votre administrateur.\n\nVous êtes aussi connecté à un RPV, qui peut surveiller votre activité sur le réseau."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"RPV"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>, qui peut surveiller votre activité professionnelle sur le réseau, y compris les courriels que vous échangez, les applications que vous utilisez et les sites Web que vous visitez.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Voir les notifications plus rapidement"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Émettre un son et s\'afficher à l\'écran"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"paramètres des notifications"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"options de répétition des notifications"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 heure"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne pas répéter"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANNULER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Reporté pour <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilisation de la pile"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Le mode Économie d\'énergie n\'est pas accessible pendant la charge"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Économie d\'énergie"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activé"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Désactivé"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barre de navigation"</string>
- <string name="start" msgid="6873794757232879664">"Démarrer"</string>
- <string name="center" msgid="4327473927066010960">"Centrer"</string>
- <string name="end" msgid="125797972524818282">"Fin"</string>
- <string name="space" msgid="804232271282109749">"Espace"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Disposition"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"À gauche"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"À droite"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Type de bouton"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(par défaut)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Presse-papiers"</item>
+ <item msgid="5742013440802239414">"Code de touche"</item>
+ <item msgid="8748101184830239843">"Sélecteur menu/clavier"</item>
+ <item msgid="8175437057325747277">"Aucun"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Divisé (par défaut)"</item>
+ <item msgid="6210279084134579668">"Centré"</item>
+ <item msgid="89143234390889289">"Aligné à gauche"</item>
+ <item msgid="7715533883382410603">"Aligné à droite"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Sélecteur menu/clavier"</string>
- <string name="select_button" msgid="1597989540662710653">"Sélectionnez le bouton à ajouter"</string>
- <string name="add_button" msgid="4134946063432258161">"Ajouter un bouton"</string>
<string name="save" msgid="2311877285724540644">"Enregistrer"</string>
<string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Aucune touche d\'accueil"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Une touche d\'accueil est nécessaire pour naviguer sur cet appareil. Veuillez ajouter une touche d\'accueil avant d\'enregistrer."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajuster la largeur du bouton"</string>
<string name="clipboard" msgid="1313879395099896312">"Presse-papiers"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Vous pouvez faire glisser des éléments directement dans le presse-papiers, et inversement."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Bouton de navigation personnalisé"</string>
<string name="keycode" msgid="7335281375728356499">"Code de touche"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Les boutons de codes de touche permettent d\'ajouter des touches du clavier à la barre de navigation. Lorsque vous appuyez sur l\'un de ces boutons, il reproduit la fonction du clavier correspondante. Vous devez d\'abord sélectionner la touche pour le bouton, puis l\'image à afficher sur celui-ci."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Sélectionnez la touche du clavier"</string>
- <string name="preview" msgid="9077832302472282938">"Aperçu"</string>
+ <string name="icon" msgid="8732339849035837289">"Icône"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles pour les ajouter"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
@@ -673,8 +673,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorer"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Le téléphone commence à chauffer"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Les fonctionnalités sont limitées pendant que le téléphone refroidit"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"À gauche"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"À droite"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personnaliser le raccourci"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Raccourci"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Demander le mot de passe"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Saisies d\'écran"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Stockage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4090aedcdd08..97748a2b6d4a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"La technologie NFC est désactivée"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"La technologie NFC est activée"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Infos application"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Partager l\'écran en haut"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Partager l\'écran sur la gauche"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Partager l\'écran sur la droite"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Déconnecter le VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Votre appareil est géré par <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilise <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pour gérer votre appareil."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Votre administrateur peut contrôler et gérer paramètres, accès contenus entreprise, applications, données associées à appareil et ses données de localisation."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"En savoir plus"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Vous êtes connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>, qui peut contrôler votre activité sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ouvrir les paramètres VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, contactez-le."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Vous avez autorisé une application à configurer une connexion VPN.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler votre activité sur le réseau, y compris au niveau des e-mails, des applications et des sites Web.\n\nPour en savoir plus, contactez-le.\n\nVous êtes également connecté à un VPN qui peut contrôler votre activité sur le réseau."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g> et associé à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris au niveau des e-mails, des applications et des sites Web.\n\nPour en savoir plus, contactez votre administrateur."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut surveiller votre activité personnelle sur le réseau."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Recevoir les notifications plus vite"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Alerte sonore et affichage à l\'écran"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> : <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"paramètres des notifications"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"options de répétition des notifications"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 heure"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne pas répéter"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANNULER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Répétée après <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilisation batterie"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"L\'économiseur de batterie n\'est pas disponible lorsque l\'appareil est en charge."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Économiseur de batterie"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activé"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Désactivé"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barre de navigation"</string>
- <string name="start" msgid="6873794757232879664">"Début"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"Fin"</string>
- <string name="space" msgid="804232271282109749">"Espace"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Disposition"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Gauche"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Droite"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Type de bouton"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(par défaut)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Presse-papiers"</item>
+ <item msgid="5742013440802239414">"Code de touche"</item>
+ <item msgid="8748101184830239843">"Sélecteur menu/clavier"</item>
+ <item msgid="8175437057325747277">"Aucun"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Divisée (par défaut)"</item>
+ <item msgid="6210279084134579668">"Centrée"</item>
+ <item msgid="89143234390889289">"Alignée à gauche"</item>
+ <item msgid="7715533883382410603">"Alignée à droite"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Sélecteur menu/clavier"</string>
- <string name="select_button" msgid="1597989540662710653">"Sélectionner le bouton à ajouter"</string>
- <string name="add_button" msgid="4134946063432258161">"Ajouter un bouton"</string>
<string name="save" msgid="2311877285724540644">"Enregistrer"</string>
<string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Aucun bouton d\'accueil trouvé"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Un bouton d\'accueil est nécessaire pour naviguer sur cet appareil. Veuillez ajouter un bouton d\'accueil avant d\'enregistrer."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajuster la largeur du bouton"</string>
<string name="clipboard" msgid="1313879395099896312">"Presse-papiers"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Vous pouvez faire glisser des éléments directement dans le Presse-papiers et inversement."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Bouton de navigation personnalisé"</string>
<string name="keycode" msgid="7335281375728356499">"Code de touche"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Les boutons de codes de touche permettent d\'ajouter des touches du clavier à la barre de navigation. Lorsque vous appuyez sur l\'un de ces boutons, il reproduit la fonction de la touche du clavier correspondante. Vous devez d\'abord sélectionner la touche pour le bouton, puis l\'image à afficher sur celui-ci."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Sélectionner la touche du clavier"</string>
- <string name="preview" msgid="9077832302472282938">"Aperçu"</string>
+ <string name="icon" msgid="8732339849035837289">"Icône"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles ici pour les ajouter"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer."</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorer"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Le téléphone chauffe"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Fonctionnalités limitées pendant le refroidissement du téléphone"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Gauche"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Droite"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personnaliser le raccourci"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Raccourci"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Demander le mot de passe"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures d\'écran"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Nouveaux messages"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 881d9674b827..5821bb96a0c5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de traballo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"A opción NFC está desactivada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"A opción NFC está activada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Non hai elementos recentes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Borraches todo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir pantalla na parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir pantalla á esquerda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir pantalla á dereita"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"O teu dispositivo está xestionado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para xestionar o teu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Para este dispositivo, o administrador pode controlar e xestionar: configuración, acceso, aplicacións, datos e información de localización."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Máis información"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estás conectado a <xliff:g id="VPN_APP">%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_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configuración da VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"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="4445150119515393526">"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>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<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>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que 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_app_personal" msgid="484599052118316268">"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>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"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>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> xestiona o teu perfil de traballo. Este está conectado coa aplicación <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode controlar a túa actividade na rede de traballo, mesmo os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode supervisar a túa actividade persoal na rede."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado ata que o desbloquees manualmente"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Recibir notificacións máis rápido"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir son e aparecer na pantalla"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
<string name="notification_done" msgid="5279426047273930175">"Feito"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controis de notificacións de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controis de notificacións"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcións para adiar notificacións"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Non adiar"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESFACER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Adiouse <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de batería"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A función aforro de batería non está dispoñible durante a carga"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Aforro de batería"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activar"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desactivar"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
- <string name="start" msgid="6873794757232879664">"Inicio"</string>
- <string name="center" msgid="4327473927066010960">"Centro"</string>
- <string name="end" msgid="125797972524818282">"Fin"</string>
- <string name="space" msgid="804232271282109749">"Barra espazadora"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Deseño"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Esquerda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Dereita"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botón"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predeterminado)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Portapapeis"</item>
+ <item msgid="5742013440802239414">"Código de teclas"</item>
+ <item msgid="8748101184830239843">"Conmutador menú/teclado"</item>
+ <item msgid="8175437057325747277">"Ningún"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividido (predeterminado)"</item>
+ <item msgid="6210279084134579668">"Centrado"</item>
+ <item msgid="89143234390889289">"Aliñado á esquerda"</item>
+ <item msgid="7715533883382410603">"Aliñado á dereita"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Conmutador menú/teclado"</string>
- <string name="select_button" msgid="1597989540662710653">"Selecciona o botón a engadir"</string>
- <string name="add_button" msgid="4134946063432258161">"Engadir botón"</string>
<string name="save" msgid="2311877285724540644">"Gardar"</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Botón de inicio non encontrado"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Necesítase un botón de inicio para navegar neste dispositivo. Engade un botón de inicio antes da acción de gardar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Axustar o ancho do botón"</string>
<string name="clipboard" msgid="1313879395099896312">"Portapapeis"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Pódense arrastrar elementos directamente ao portapapeis. Tamén se poden arrastrar directamente fóra del."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botón de navegación personalizada"</string>
<string name="keycode" msgid="7335281375728356499">"Código de teclas"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Os botóns de código de teclas permiten engadir teclas do teclado á barra de navegación. Ao premelos, emulan a tecla seleccionada. Primeiro, debes seleccionar unha tecla para o botón e escoller a imaxe que se mostrará nel."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selecciona o botón do teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
+ <string name="icon" msgid="8732339849035837289">"Icona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastrar para engadir funcións"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra o elemento ata aquí para eliminalo"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"O teléfono está quentando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Esquerda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Dereita"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar atallo"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Atallo"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitude de contrasinal"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensaxes xerais"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 1b9ea1d45596..5fedb2dbceba 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"કાર્ય મોડ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"રાત્રિ પ્રકાશ"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC અક્ષમ કરેલ છે"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC સક્ષમ કરેલ છે"</string>
<string name="recents_empty_message" msgid="808480104164008572">"કોઇ તાજેતરની આઇટમ્સ નથી"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"તમે બધું સાફ કર્યું"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ઍપ્લિકેશન માહિતી"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ઊભું વિભક્ત કરો"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"કસ્ટમ વિભક્ત કરો"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"સ્ક્રીનને ઉપરની તરફ વિભાજિત કરો"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"સ્ક્રીનને ડાબી તરફ વિભાજિત કરો"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"સ્ક્રીનને જમણી તરફ વિભાજિત કરો"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ચાર્જ થઈ ગયું"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ડિસ્કનેક્ટ કરો"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"તમારું ઉપકરણ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સંબંદ્ધ ડેટા અને ઉપકરણની સ્થાન માહિતીનું નિરીક્ષણ અને સંચાલન કરી શકે છે."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"વધુ જાણો"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN સેટિંગ્સ ખોલો"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યુ છે, જે તમારા ઉપકરણ પર ટ્રાફિકનું નિરીક્ષણ કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"તમે VPN કનેક્શન સેટ કરવા માટે ઍપ્લિકેશન પરવાનગી આપી.\n\nઆ ઍપ્લિકેશન ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારા ઉપકરણ અને નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"તમારી કાર્ય પ્રોફાઇલનું સંચાલન <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા કરવામાં આવે છે.\n\n તમારા વ્યવસ્થાપક ઇમેઇલ, ઍપ્લિકેશનો, અને વેબસાઇટો સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરવામાં સક્ષમ છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો.\n\nતમે VPN સાથે પણ કનેક્ટ કરેલ છે, જે તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"તમારી કાર્ય પ્રોફાઇલનું સંચાલન <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="4946600443852045903">"તમારી કાર્ય પ્રોફાઇલ <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_disabled" msgid="7412534203633528135">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"વધુ ઝડપથી સૂચનાઓ મેળવો"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"અવાજ કરો અને સ્ક્રીન પર બતાવો"</string>
<string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
<string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> સૂચના નિયંત્રણો"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"સૂચના નિયંત્રણો"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"સૂચના સ્નૂઝ કરવાના વિકલ્પો"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 મિનિટ"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 મિનિટ"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 કલાક"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"સ્નૂઝ કરશો નહીં"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"પૂર્વવત્ કરો"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> માટે સ્નૂઝ કરો"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"બૅટરી વપરાશ"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ચાર્જિંગ દરમિયાન બૅટરી બચતકર્તા ઉપલબ્ધ નથી"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"બૅટરી બચતકર્તા"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ચાલુ"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"બંધ"</string>
<string name="nav_bar" msgid="1993221402773877607">"નેવિગેશન બાર"</string>
- <string name="start" msgid="6873794757232879664">"પ્રારંભ કરો"</string>
- <string name="center" msgid="4327473927066010960">"મધ્ય"</string>
- <string name="end" msgid="125797972524818282">"સમાપ્ત"</string>
- <string name="space" msgid="804232271282109749">"સ્પેસર"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"લેઆઉટ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ડાબે"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"જમણે"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"બટનનો પ્રકાર"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ડિફૉલ્ટ)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ક્લિપબોર્ડ"</item>
+ <item msgid="5742013440802239414">"કીકોડ"</item>
+ <item msgid="8748101184830239843">"મેનૂ / કીબોર્ડ સ્વિચર"</item>
+ <item msgid="8175437057325747277">"કોઈ નહીં"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"વિભાજીત (ડિફૉલ્ટ)"</item>
+ <item msgid="6210279084134579668">"કેન્દ્રિત"</item>
+ <item msgid="89143234390889289">"ડાબે-સંરેખિત"</item>
+ <item msgid="7715533883382410603">"જમણે-સંરેખિત"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"મેનૂ / કીબોર્ડ સ્વિચર"</string>
- <string name="select_button" msgid="1597989540662710653">"ઉમેરવા માટે બટન પસંદ કરો"</string>
- <string name="add_button" msgid="4134946063432258161">"બટન ઉમેરો"</string>
<string name="save" msgid="2311877285724540644">"સાચવો"</string>
<string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string>
- <string name="no_home_title" msgid="1563808595146071549">"કોઈ હોમ બટન મળ્યું નથી"</string>
- <string name="no_home_message" msgid="5408485011659260911">"આ ઉપકરણને નેવિગેટ કરવા માટે હોમ બટન આવશ્યક. કૃપા કરીને સાચવતાં પહેલાં એક હોમ બટન ઉમેરો."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"બટનની પહોળાઈ સમાયોજિત કરો"</string>
<string name="clipboard" msgid="1313879395099896312">"ક્લિપબોર્ડ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ક્લિપબોર્ડ આઇટમ્સને સીધા જ ક્લિપબોર્ડ પર ખેંચવાની મંજૂરી આપે છે. જ્યારે હાજર હોય ત્યારે આઇટમ્સ ક્લિપબોર્ડ પરથી સીધી જ બહાર પણ ખેંચી શકાય છે."</string>
<string name="accessibility_key" msgid="5701989859305675896">"કસ્ટમ નેવિગેશન બટન"</string>
<string name="keycode" msgid="7335281375728356499">"કીકોડ"</string>
- <string name="keycode_description" msgid="1403795192716828949">"કીકોડ બટન કીબોર્ડની કીઝને નેવિગેશન બારમાં ઉમેરવાની મંજૂરી આપે છે. જ્યારે દબાવવામાં આવે ત્યારે તે પસંદ કરેલ કીબોર્ડની કીનું અનુસરણ કરે છે. બટન માટે પહેલા કીબોર્ડની કીઝને પસંદ કરવી આવશ્યક છે, તે પછી બટન પર બતાવવામાં આવેલ છબી પસંદ કરવી આવશ્યક છે."</string>
- <string name="select_keycode" msgid="7413765103381924584">"કીબોર્ડ બટન પસંદ કરો"</string>
- <string name="preview" msgid="9077832302472282938">"પૂર્વાવલોકન કરો"</string>
+ <string name="icon" msgid="8732339849035837289">"આઇકન"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ટાઇલ્સ ઉમેરવા માટે ખેંચો"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"દૂર કરવા માટે અહીં ખેંચો"</string>
<string name="qs_edit" msgid="2232596095725105230">"સંપાદિત કરો"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"નાનું કરો"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"છોડી દો"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ફોન ગરમ થઈ રહ્યો છે"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ફોન ઠંડો થાય ત્યાં સુધી કેટલીક સુવિધાઓ મર્યાદિત હોય છે"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"તમારો ફોન આપમેળે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ડાબે"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"જમણે"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"શૉર્ટકટ કસ્ટમાઇઝ કરો"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"શૉર્ટકટ"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"પાસવર્ડ માટેનો સંકેત આપો"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ચેતવણીઓ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"સ્ક્રીનશૉટ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"સામાન્ય સંદેશા"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"સ્ટોરેજ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 84dc2c4b8482..b6cba3c34784 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"नाइट लाइट"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC बंद है"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC चालू है"</string>
<string name="recents_empty_message" msgid="808480104164008572">"हाल ही का कोई आइटम नहीं"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपने सब कुछ साफ़ कर दिया है"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्‍टम रूप से विभाजित करें"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ऊपर की ओर दो स्क्रीन बनाएं"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"बाईं ओर दो स्क्रीन बनाएं"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"दाईं ओर दो स्क्रीन बनाएं"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN डिस्‍कनेक्‍ट करें"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> आपका डिवाइस प्रबंधित करता है."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> आपका डिवाइस प्रबंधित करने के लिए <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> का उपयोग करता है."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"आपका व्यवस्थापक आपके डिवाइस से जुड़ी सेटिंग, कॉर्पोरेट एक्सेस, ऐप्लिकेशन, डेटा और आपके डिवाइस की स्थान जानकारी की निगरानी और उसका प्रबंधन कर सकता है."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"अधिक जानें"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"आप <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सेटिंग खोलें"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"आपके व्‍यवस्‍थापक ने नेटवर्क लॉग करना चालू कर दिया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है.\n\nअधिक जानकारी के लिए अपने व्‍यवस्‍थापक से संपर्क करें."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"आपने किसी ऐप को VPN कनेक्‍शन सेट करने की अनुमति दी है.\n\nयह ऐप ईमेल, ऐप्‍स और सुरक्षित वेबसाइटों सहित आपके डिवाइस और नेटवर्क की गतिविधि की निगरानी कर सकता है."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> आपकी कार्य प्रोफ़ाइल को प्रबंधित करता है.\n\nआपका व्‍यवस्‍थापक ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए अपने व्‍यवस्‍थापक से संपर्क करें.\n\nआप ऐसे VPN से भी कनेक्‍ट हैं, जो आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<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="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <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_disabled" msgid="7412534203633528135">"जब तक कि आप मैन्‍युअल रूप से अनलॉक नहीं करते तब तक डिवाइस लॉक रहेगा"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"सूचनाएं अधिक तेज़ी से प्राप्त करें"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ध्वनि करें और स्क्रीन पर दिखाएं"</string>
<string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
<string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> नोटिफ़िकेशन नियंत्रण"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"नोटिफ़िकेशन नियंत्रण"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"नोटिफ़िकेशन की याद दिलाने के विकल्प"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 मिनट"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 मिनट"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 घंटा"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"याद नहीं दिलाएं"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"पहले जैसा करें"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> के लिए याद दिलाया गया"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"बैटरी उपयोग"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज किए जाने के दौरान बैटरी सेवर उपलब्ध नहीं है"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"बैटरी सेवर"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
<string name="nav_bar" msgid="1993221402773877607">"नेविगेशन बार"</string>
- <string name="start" msgid="6873794757232879664">"प्रारंभ करें"</string>
- <string name="center" msgid="4327473927066010960">"मध्‍य"</string>
- <string name="end" msgid="125797972524818282">"समाप्त"</string>
- <string name="space" msgid="804232271282109749">"स्‍पेसर"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"बाएं"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"दाएं"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"बटन प्रकार"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(डिफ़ॉल्ट)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"क्लिपबोर्ड"</item>
+ <item msgid="5742013440802239414">"कुंजी कोड"</item>
+ <item msgid="8748101184830239843">"मेनू / कीबोर्ड स्‍विचर"</item>
+ <item msgid="8175437057325747277">"कोई नहीं"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"विभाजित (डिफ़ॉल्ट)"</item>
+ <item msgid="6210279084134579668">"केंद्रित"</item>
+ <item msgid="89143234390889289">"बायां-संरेखित"</item>
+ <item msgid="7715533883382410603">"दायां-संरेखित"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"मेनू / कीबोर्ड स्‍विचर"</string>
- <string name="select_button" msgid="1597989540662710653">"जोड़ने के लिए बटन चुनें"</string>
- <string name="add_button" msgid="4134946063432258161">"बटन जोड़ें"</string>
<string name="save" msgid="2311877285724540644">"सहेजें"</string>
<string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
- <string name="no_home_title" msgid="1563808595146071549">"कोई होम बटन नहीं मिला"</string>
- <string name="no_home_message" msgid="5408485011659260911">"इस डिवाइस को नेविगट करने के लिए होम बटन आवश्‍यक है. कृपया सहेजने के पहले होम बटन जोड़ें."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"बटन की चौड़ाई समायोजित करें"</string>
<string name="clipboard" msgid="1313879395099896312">"क्लिपबोर्ड"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"क्‍लिपबोर्ड आइटम सीधे क्‍लिपबोर्ड में खींचने देता है. मौजूद होने पर आइटम क्‍लिपबोर्ड से सीधे बाहर भी खींचे जा सकते हैं."</string>
<string name="accessibility_key" msgid="5701989859305675896">"कस्‍टम मार्गदर्शक बटन"</string>
<string name="keycode" msgid="7335281375728356499">"कुंजी कोड"</string>
- <string name="keycode_description" msgid="1403795192716828949">"कुंजी कोड बटन कीबोर्ड कुंजियों को मार्गदर्शक बार में जोड़ने देती हैं. दबाए जाने पर वे चयनित कीबोर्ड कुंजी का अनुकरण करते हैं. सबसे पहले, बटन के लिए कुंजी का चयन करना चाहिए, उसके बाद बटन पर दिखाए जाने वाले चित्र का चयन करना चाहिए."</string>
- <string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटन चुनें"</string>
- <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
+ <string name="icon" msgid="8732339849035837289">"आइकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलों को जोड़ने के लिए खींचें"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"निकालने के लिए यहां खींचें"</string>
<string name="qs_edit" msgid="2232596095725105230">"संपादित करें"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करें"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"छोटा करें"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"खारिज करें"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"फ़ोन गर्म हो रहा है"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"फ़ोन के ठंडा होने के दौरान कुछ सुविधाएं सीमित होती हैं"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अभी भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"बाएं"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"दाएं"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"शॉर्टकट कस्टमाइज़ करें"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"शॉर्टकट"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"पासवर्ड के लिए संकेत दें"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचनाएं"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्‍क्रीनशॉट"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"सामान्य संदेश"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"जगह"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 8d626c8bb273..85a744d9292e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način rada"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC je onemogućen"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC je omogućen"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Izbrisali ste sve"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli zaslon na vrhu"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli zaslon slijeva"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli zaslon zdesna"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Prekini vezu s VPN-om"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vašim uređajem upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> upotrebljava aplikaciju <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje vašim uređajem."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrator može nadzirati postavke, korporacijski pristup, aplikacije, podatke o uređaju i lokaciji uređaja te upravljati njima"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvorite postavke VPN-a"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"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="4445150119515393526">"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>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"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="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"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-poštu, aplikacije i web-lokacije."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"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>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"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>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nViše informacija možete saznati od administratora."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Primajte obavijesti brže"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Reproduciraj zvuk i prikaži na zaslonu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obavijesti"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije odgode obavijesti"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuta"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuta"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 sat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne odgađaj"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"PONIŠTI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Odgođeno <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Štednja baterije nije dostupna tijekom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Štednja baterije"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Isključeno"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigacijska traka"</string>
- <string name="start" msgid="6873794757232879664">"Početak"</string>
- <string name="center" msgid="4327473927066010960">"Sredina"</string>
- <string name="end" msgid="125797972524818282">"Kraj"</string>
- <string name="space" msgid="804232271282109749">"Razmak"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Izgled"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Lijevo"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Desno"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Vrsta gumba"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(zadano)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Međuspremnik"</item>
+ <item msgid="5742013440802239414">"Kôd tipke"</item>
+ <item msgid="8748101184830239843">"Izmjena izbornika/tipkovnice"</item>
+ <item msgid="8175437057325747277">"Ništa"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Podijeljeno (zadano)"</item>
+ <item msgid="6210279084134579668">"Centrirano"</item>
+ <item msgid="89143234390889289">"Lijevo poravnanje"</item>
+ <item msgid="7715533883382410603">"Desno poravnanje"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Izmjena izbornika/tipkovnice"</string>
- <string name="select_button" msgid="1597989540662710653">"Odaberite gumb za dodavanje"</string>
- <string name="add_button" msgid="4134946063432258161">"Dodaj gumb"</string>
<string name="save" msgid="2311877285724540644">"Spremi"</string>
<string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nema gumba početnog zaslona"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Da biste se mogli kretati ovim uređajem, potreban je gumb početnog zaslona. Dodajte gumb početnog zaslona prije spremanja."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Prilagodite širinu gumba"</string>
<string name="clipboard" msgid="1313879395099896312">"Međuspremnik"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Međuspremnik omogućuje povlačenje stavki izravno u međuspremnik. Stavke se mogu i izravno povlačiti iz međuspremnika ako se nalaze u njemu."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Prilagođeni navigacijski gumb"</string>
<string name="keycode" msgid="7335281375728356499">"Kôd tipke"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Gumbi koda tipke omogućuju dodavanje tipki tipkovnice na navigacijsku traku. Kada ih se pritisne, oni emuliraju odabranu tipku tipkovnice. Prvo se mora odabrati tipka za gumb, a nakon toga na gumbu će se pojaviti slika."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Odaberite gumb tipkovnice"</string>
- <string name="preview" msgid="9077832302472282938">"Pregled"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali pločice"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Povucite ovdje za uklanjanje"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiziraj"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon se zagrijava"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Neke su značajke ograničene dok se telefon hladi"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Lijevo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Desno"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Prilagodi prečac"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Prečac"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Upit za zaporku"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimke zaslona"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b18d5942108d..81f3d5e158ca 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Munka mód"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éjszakai fény"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Az NFC ki van kapcsolva"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Az NFC be van kapcsolva"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nincsenek mostanában használt elemek"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Mindent törölt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Osztott képernyő felülre"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Osztott képernyő balra"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Osztott képernyő jobbra"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN-kapcsolat bontása"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Az eszközt a(z) <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> kezeli."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"A(z) <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> a(z) <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> alkalmazást használja az eszközkezeléshez."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"A rendszergazda figyelheti és kezelheti az eszköz beállításait, vállalati hozzáférését, alkalmazásait, adatait és helyadatait."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"További információ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ön kapcsolódik ehhez: <xliff:g id="VPN_APP">%1$s</xliff:g>, amely figyelheti hálózati tevékenységét, köztük a levelezést, az alkalmazás- és webhelyhasználatot."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-beállítások megnyitása"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"A rendszergazda bekapcsolta az eszköz forgalmát figyelő hálózati naplózást.\n\nHa további információra van szüksége, forduljon a rendszergazdához."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Engedélyezte egy alkalmazásnak, hogy VPN-kapcsolatot létesítsen.\n\nEz az alkalmazás (az e-mailekre, alkalmazásokra és a webhelyekre is kiterjedően) figyelemmel kísérheti az Ön eszközét és hálózati tevékenységét."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> kezeli.\n\nA rendszergazda figyelheti hálózati tevékenységét, köztük az e-maileket, az alkalmazásokat és a webhelyeket.\n\nHa további információra van szüksége, forduljon a rendszergazdához.\n\nVPN-hez is kapcsolódik, amely szintén figyelheti hálózati tevékenységét."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ön a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz csatlakozik, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, alkalmazásokat és webhelyeket."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> kezeli. A munkaprofil össze van kapcsolva a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazással, amely figyelheti az Ön munkahelyi hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nHa további információra van szüksége, forduljon a rendszergazdához."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely szintén figyelemmel kísérheti személyes hálózati tevékenységét."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Az eszköz addig zárolva marad, amíg kézileg fel nem oldja"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Gyorsabban megkaphatja az értesítéseket"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Hangjelzés és felugró értesítés a képernyőn"</string>
<string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
<string name="notification_done" msgid="5279426047273930175">"Kész"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-értesítések vezérlői"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> – <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"értesítésvezérlők"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"értesítések halasztási beállításai"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 perc"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 perc"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 óra"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne halasszon"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"VISSZAVONÁS"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Elhalasztva: <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akkumulátorhasználat"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Az Akkumulátorkímélő módot töltés közben nem lehet használni"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akkumulátorkímélő mód"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Be"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Ki"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigációs sáv"</string>
- <string name="start" msgid="6873794757232879664">"Kezdés"</string>
- <string name="center" msgid="4327473927066010960">"Igazítás középre"</string>
- <string name="end" msgid="125797972524818282">"Vége"</string>
- <string name="space" msgid="804232271282109749">"Távtartó"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Elrendezés"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Balra"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Jobbra"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Gombtípus"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(alapértelmezett)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Vágólap"</item>
+ <item msgid="5742013440802239414">"Billentyűkód"</item>
+ <item msgid="8748101184830239843">"Menü/Billentyűzetváltó"</item>
+ <item msgid="8175437057325747277">"Nincs"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Osztott (alapértelmezett)"</item>
+ <item msgid="6210279084134579668">"Középre igazított"</item>
+ <item msgid="89143234390889289">"Balra igazított"</item>
+ <item msgid="7715533883382410603">"Jobbra igazított"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menü/Billentyűzetváltó"</string>
- <string name="select_button" msgid="1597989540662710653">"Hozzáadni kívánt gomb kiválasztása"</string>
- <string name="add_button" msgid="4134946063432258161">"Gomb hozzáadása"</string>
<string name="save" msgid="2311877285724540644">"Mentés"</string>
<string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nem található főoldal gomb"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Az eszközön történő navigáláshoz főoldal gomb szükséges. Kérjük, a mentés előtt adjon hozzá egy főoldal gombot."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Gombszélesség beállítása"</string>
<string name="clipboard" msgid="1313879395099896312">"Vágólap"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"A Vágólap lehetővé teszi az elemek áthúzását közvetlenül a vágólapra. Ha vannak elemek a vágólapon, közvetlenül lehúzhatók onnan."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Személyre szabott navigációs gomb"</string>
<string name="keycode" msgid="7335281375728356499">"Billentyűkód"</string>
- <string name="keycode_description" msgid="1403795192716828949">"A billentyűkód gombok lehetővé teszik gombok hozzáadását a navigációs sávhoz. A gombok megnyomásuk esetén a kiválasztott billentyűt imitálják. Először ki kell választani a gombhoz tartozó billentyűt, majd a gombon megjeleníteni kívánt képet."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Billentyűgomb kiválasztása"</string>
- <string name="preview" msgid="9077832302472282938">"Előnézet"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Húzza csempe hozzáadásához"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Húzza ide az eltávolításhoz"</string>
<string name="qs_edit" msgid="2232596095725105230">"Szerkesztés"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Kis méret"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Elvetés"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"A telefon melegszik"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Bizonyos funkciók korlátozottan működnek a telefon hűlése közben"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Balra"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Jobbra"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Billentyűparancs személyre szabása"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Billentyűparancs"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Jelszókérés"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Értesítések"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Képernyőképek"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Általános üzenetek"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Tárhely"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index fa7cbe19316e..e5169f255201 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Աշխատանքային ռեժիմ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Գիշերային լույս"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC-ն անջատված է"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC-ն միացված է"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Վերջին տարրեր չկան"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Դուք ջնջել եք ամենը"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Տրոհել էկրանը վերևից"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Տրոհել էկրանը ձախից"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Տրոհել էկրանն աջից"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Անջատել VPN-ը"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Ձեր սարքը կառավարվում է <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> հավելվածի կողմից:"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>-ը ձեր սարքը կառավարելու համար օգտագործում է <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> հավելվածը:"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Ձեր ադմինիստրատորը կարող է վերահսկել և կառավարել ձեր սարքի հետ կապակցված կարգավորումները, կորպորատիվ մուտքը, հավելվածները և տվյալները, ինչպես նաև ձեր սարքի տեղադրության տվյալները:"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Իմանալ ավելին"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Դուք կապակցված եք <xliff:g id="VPN_APP">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցային գործողությունը, այդ թվում նաև էլփոստը, հավելվածները և կայքերը:"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Բացել VPN-ի կարգավորումները"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Ձեր ադմինիստրատորը միացրել է ցանցային իրադարձությունների գրանցումը, որը վերահսկում է ձեր սարքի թրաֆիկը։\n\nԼրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր ադմինիստրատորին։"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Ինչ-որ հավելվածի թույլ եք տվել հաստատել VPN կապակցում:\n\nԱյդ հավելվածը կարող է վերահսկել ձեր սարքի և ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Ձեր աշխատանքային պրոֆիլի կառավարիչն է <xliff:g id="ORGANIZATION">%1$s</xliff:g> կազմակերպությունը։\n\nԱդմինիստրատորը կարող է վերահսկել ձեր ցանցային գործունեությունը, այդ թվում նաև էլփոստը, հավելվածները և կայքերը։\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին։\n\nԴուք կապակցված են նաև VPN ցանցին, որը կարող է վերահսկել ձեր ցանցային գործունեությունը։"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Ձեր աշխատանքային պրոֆիլի կառավարիչն է <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="4946600443852045903">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <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_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Ավելի արագ ստացեք ծանուցումները"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Ձայն հանել և ցուցադրել էկրանին"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
<string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարներ"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ծանուցման կառավարներ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ծանուցման հետաձգման ընտրանքներ"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 րոպե"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 րոպե"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ժամ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Չհետաձգել"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ՀԵՏԱՐԿԵԼ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Հետաձգվել է <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ով"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Մարտկոցի օգտագործում"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Մարտկոցի տնտեսումը լիցքավորման ժամանակ հասանելի չէ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Մարտկոցի տնտեսում"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Միացնել"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Անջատել"</string>
<string name="nav_bar" msgid="1993221402773877607">"Նավարկման գոտի"</string>
- <string name="start" msgid="6873794757232879664">"Սկսել"</string>
- <string name="center" msgid="4327473927066010960">"Կենտրոն"</string>
- <string name="end" msgid="125797972524818282">"Վերջ"</string>
- <string name="space" msgid="804232271282109749">"Բաժանիչ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Դասավորություն"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Ձախ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Աջ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Կոճակի տեսակը"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(կանխադրված)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Սեղմատախտակ"</item>
+ <item msgid="5742013440802239414">"Ստեղնային կոդ"</item>
+ <item msgid="8748101184830239843">"Ընտրացանկ/Ստեղնաշարի փոխարկիչ"</item>
+ <item msgid="8175437057325747277">"Չկան"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Բաժանված (կանխադրված)"</item>
+ <item msgid="6210279084134579668">"Կենտրոնում"</item>
+ <item msgid="89143234390889289">"Հավասարեցված ձախ"</item>
+ <item msgid="7715533883382410603">"Հավասարեցված աջ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Ընտրացանկ/Ստեղնաշարի փոխարկիչ"</string>
- <string name="select_button" msgid="1597989540662710653">"Ավելացնելու համար ընտրեք կոճակ"</string>
- <string name="add_button" msgid="4134946063432258161">"Ավելացնել կոճակ"</string>
<string name="save" msgid="2311877285724540644">"Պահել"</string>
<string name="reset" msgid="2448168080964209908">"Վերակայել"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Գլխավոր էջի կոճակ չի գտնվել"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Այս սարքը նավարկելու համար պահանջվում է գլխավոր էջ վերադառնալու կոճակ: Պահելուց առաջ ավելացրեք գլխավոր էջ վերադառնալու կոճակ:"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Կարգավորել կոճակի լայնությունը"</string>
<string name="clipboard" msgid="1313879395099896312">"Սեղմատախտակ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Սեղմատախտակ կոճակը թույլ է տալիս տարրերը քաշել անմիջապես դեպի սեղմատախտակ: Առկայության դեպքում տարրերը հնարավոր է նաև սեղմատախտակից դուրս քաշել:"</string>
<string name="accessibility_key" msgid="5701989859305675896">"Հատուկ նավարկման կոճակ"</string>
<string name="keycode" msgid="7335281375728356499">"Ստեղնային կոդ"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Ստեղնային կոդի կոճակները թույլ են տալիս Նավարկման գոտում ավելացնել ստեղնաշարի ստեղները: Սեղմելու դեպքում դրանք էմուլացնում են ստեղնաշարի ընտրված ստեղնը: Կոճակի համար նախ անհրաժեշտ է ընտրել ստեղնը, այնուհետև՝ կոճակի վրա ցուցադրվող պատկերը:"</string>
- <string name="select_keycode" msgid="7413765103381924584">"Ընտրեք ստեղնաշարի կոճակը"</string>
- <string name="preview" msgid="9077832302472282938">"Նախադիտում"</string>
+ <string name="icon" msgid="8732339849035837289">"Պատկերակ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Քաշեք՝ սալիկներ ավելացնելու համար"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
<string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Ծալել"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Փակել"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Հեռախոսը տաքանում է"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Ձախ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Աջ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Հարմարեցնել դյուրանցումը"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Դյուրանցում"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Պահանջել գաղտնաբառ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Էկրանի պատկերներ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Ընդհանուր հաղորդագրություններ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Հիշողություն"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index d2b7a81ced44..a2d38e9faa60 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode kerja"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC dinonaktifkan"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC diaktifkan"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Tidak ada item baru-baru ini"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda sudah menghapus semua"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Pisahkan layar ke atas"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Pisahkan layar ke kiri"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Pisahkan layar ke kanan"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Putuskan sambungan VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Perangkat dikelola oleh <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengelola perangkat Anda."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Admin dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Pelajari lebih lanjut"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buka Setelan VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Anda memberikan izin kepada aplikasi untuk menyiapkan sambungan VPN.\n\nAplikasi ini ini dapat memantau aktivitas perangkat dan jaringan, termasuk email, aplikasi, dan situs web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga tersambung ke VPN, yang dapat memantau aktivitas jaringan."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini terhubung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Buat suara dan munculkan di layar"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrol notifikasi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrol notifikasi"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opsi tunda notifikasi"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 menit"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 menit"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 jam"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Jangan tunda"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"URUNG"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Ditunda selama <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Pemakaian baterai"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penghemat Baterai tidak tersedia selama pengisian daya"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Penghemat Baterai"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aktif"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Nonaktif"</string>
<string name="nav_bar" msgid="1993221402773877607">"Bilah navigasi"</string>
- <string name="start" msgid="6873794757232879664">"Awal"</string>
- <string name="center" msgid="4327473927066010960">"Tengah"</string>
- <string name="end" msgid="125797972524818282">"Akhir"</string>
- <string name="space" msgid="804232271282109749">"Pengatur spasi"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Tata Letak"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kiri"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Kanan"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Jenis tombol"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(default)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Papan klip"</item>
+ <item msgid="5742013440802239414">"Kode tombol"</item>
+ <item msgid="8748101184830239843">"Pengalih Menu / Keyboard"</item>
+ <item msgid="8175437057325747277">"Tidak Ada"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Terbagi (default)"</item>
+ <item msgid="6210279084134579668">"Tengah"</item>
+ <item msgid="89143234390889289">"Rata-kiri"</item>
+ <item msgid="7715533883382410603">"Rata-kanan"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Pengalih Menu / Keyboard"</string>
- <string name="select_button" msgid="1597989540662710653">"Pilih tombol untuk ditambahkan"</string>
- <string name="add_button" msgid="4134946063432258161">"Tambahkan tombol"</string>
<string name="save" msgid="2311877285724540644">"Simpan"</string>
<string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Tidak ada tombol layar utama"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Tombol layar utama diperlukan agar dapat menavigasi perangkat ini. Tambahkan tombol layar uama sebelum menyimpan."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Sesuaikan lebar tombol"</string>
<string name="clipboard" msgid="1313879395099896312">"Papan klip"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Papan klip memungkinkan item diseret langsung ke papan klip. Item juga dapat diseret langsung dari papan klik jika ada."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Tombol navigasi khusus"</string>
<string name="keycode" msgid="7335281375728356499">"Kode tombol"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tombol untuk kode tombol memungkinkan keyboard ditambahkan ke Bilah Navigasi. Jika ditekan, tombol ini mengemulasi tombol keyboard yang dipilih. Terlebih dahulu tombol harus dipilih, diikuti dengan gambar yang akan ditampilkan."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Pilih Tombol Keyboard"</string>
- <string name="preview" msgid="9077832302472282938">"Pratinjau"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan ubin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Seret ke sini untuk menghapus"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalkan"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Tutup"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Ponsel menjadi hangat"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Beberapa fitur dibatasi saat ponsel mendingin"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kiri"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Kanan"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Sesuaikan pintasan"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Pintasan"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Minta sandi"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikasi"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Pesan Umum"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Penyimpanan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 28ccdf55c2d1..b0dacfc4162b 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Vinnustilling"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Næturljós"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Slökkt á NFC"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Kveikt á NFC"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Engin nýleg atriði"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Þú hefur hreinsað allt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Skipta skjá að ofanverðu"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Skipta skjá til vinstri"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Skipta skjá til hægri"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Aftengja VPN-net"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Þessu tæki er stýrt af <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> notar <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til að stýra tækinu þínu."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Kerfisstjóri getur fylgst með og stjórnað stillingum, fyrirtækjaaðgangi, forritum, gögnum tengdum tækinu og staðsetningu tækisins."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Frekari upplýsingar"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Þú ert með tengingu við <xliff:g id="VPN_APP">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Opna VPN-stillingar"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Kerfisstjóri hefur kveikt á eftirliti netkerfa, sem fylgist með netumferð á tækinu þínu.\n\nHafðu samband við kerfisstjóra til að fá frekari upplýsingar."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Þú veittir forriti heimild til að koma á VPN-tengingu.\n\nÞetta forrit getur fylgst með virkni þinni í tækinu og á netinu, þar á meðal tölvupósti, forritum og vefsvæðum."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> stýrir vinnusniðinu þínu.\n\nKerfisstjórinn getur fylgst með virkni þinni á netinu, þ.m.t. tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar.\n\nÞú ert einnig með VPN-tengingu, sem getur fylgst með virkni þinni á netinu."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> stýrir vinnusniðinu þínu. Það er tengt við <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með netvirkni þinni í vinnunni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjóra til að fá frekari upplýsingar."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Tækið verður læst þar til þú opnar það handvirkt"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Fáðu tilkynningar hraðar"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Spila hljóð og birta sprettitilkynningu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
<string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"tilkynningastýringar"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"þöggunarstillingar tilkynninga"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 mínútur"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 mínútur"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 klukkustund"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ekki blunda"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"AFTURKALLA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Þaggað í <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Rafhlöðunotkun"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ekki er hægt að nota rafhlöðusparnað meðan á hleðslu stendur"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Rafhlöðusparnaður"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Kveikt"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Slökkt"</string>
<string name="nav_bar" msgid="1993221402773877607">"Yfirlitsstika"</string>
- <string name="start" msgid="6873794757232879664">"Byrja"</string>
- <string name="center" msgid="4327473927066010960">"Miðja"</string>
- <string name="end" msgid="125797972524818282">"Ljúka"</string>
- <string name="space" msgid="804232271282109749">"Bil"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Útlit"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Vinstri"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Hægri"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Gerð hnapps"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(sjálfgefið)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Klippiborð"</item>
+ <item msgid="5742013440802239414">"Lykilkóði"</item>
+ <item msgid="8748101184830239843">"Valmynd / lyklaborðsval"</item>
+ <item msgid="8175437057325747277">"Ekkert"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Skipt (sjálfgefið)"</item>
+ <item msgid="6210279084134579668">"Miðjað"</item>
+ <item msgid="89143234390889289">"Vinstrijafnað"</item>
+ <item msgid="7715533883382410603">"Hægrijafnað"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Valmynd / lyklaborðsval"</string>
- <string name="select_button" msgid="1597989540662710653">"Veldu hnapp til að bæta við"</string>
- <string name="add_button" msgid="4134946063432258161">"Bæta við hnappi"</string>
<string name="save" msgid="2311877285724540644">"Vista"</string>
<string name="reset" msgid="2448168080964209908">"Endurstilla"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Enginn heimahnappur fannst"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Þörf er á heimahnappi til að hægt sé að fletta á þessu tæki. Bættu við heimahnappi áður en þú vistar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Breyta breidd hnapps"</string>
<string name="clipboard" msgid="1313879395099896312">"Klippiborð"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Hægt er að draga atriði beint yfir á klippiborðið. Eins má draga þau atriði sem eru þar fyrir beint út af klippiborðinu."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Sérsniðinn flettingahnappur"</string>
<string name="keycode" msgid="7335281375728356499">"Lykilkóði"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Með lykilkóðahnöppum má bæta lyklaborðshnöppum við yfirlitsstikuna. Þegar ýtt er á slíka hnappa líkja þeir eftir fyrirfram völdum lyklaborðshnöppum. Fyrst þarf að velja tiltekinn hnapp fyrir hvern þeirra og síðan þá mynd sem á að birtast á hnappnum."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Veldu lyklaborðshnapp"</string>
- <string name="preview" msgid="9077832302472282938">"Forskoðun"</string>
+ <string name="icon" msgid="8732339849035837289">"Tákn"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dragðu til að bæta við reitum"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dragðu hingað til að fjarlægja"</string>
<string name="qs_edit" msgid="2232596095725105230">"Breyta"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minnka"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Hunsa"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Síminn er að hitna"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Sumir eiginleikar eru takmarkaðir þegar síminn kælir sig"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vinstri"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Hægri"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Sérstilla flýtilykil"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Flýtilykill"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Beiðni um aðgangsorð"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Tilkynningar"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjámyndir"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Almenn skilaboð"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Geymslurými"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 515f77fa4d69..8dacab213eab 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modalità Lavoro"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luminosità notturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC non attiva"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC attiva"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nessun elemento recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hai cancellato tutto"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Schermo diviso in alto"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Schermo diviso a sinistra"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Schermo diviso a destra"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Scollega VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Il dispositivo è gestito dall\'app <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilizza l\'app <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> per gestire il dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"L\'amministratore può monitorare e gestire impostazioni, accesso aziendale, app, dati associati al dispositivo e informazioni sulla posizione del dispositivo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ulteriori informazioni"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Sei connesso a <xliff:g id="VPN_APP">%1$s</xliff:g>, che consente di monitorare le attività di rete, inclusi siti web, email e app."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Apri impostazioni VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"L\'amministratore ha attivato i log di rete, che consentono di monitorare il traffico sul dispositivo.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Hai autorizzato l\'app a configurare una connessione VPN.\n\nQuesta app può monitorare il tuo dispositivo e l\'attività di rete, inclusi email, app e siti web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare la tua attività di rete, inclusi siti web, email e app.\n\nPer ulteriori informazioni, contatta l\'amministratore.\n\nSei inoltre connesso a una VPN, da cui è possibile monitorare la tua attività di rete."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, che consente di monitorare la tua attività di rete personale, inclusi siti web, email e app."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi siti web, email e app.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nSei connesso anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Il dispositivo resterà bloccato fino allo sblocco manuale"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Ricevi notifiche più velocemente"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Con suoneria e visualizzazione sullo schermo"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
<string name="notification_done" msgid="5279426047273930175">"Fine"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlli di notifica per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"gestione delle notifiche"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opzioni di posticipazione notifiche"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuti"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuti"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Non posticipare"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANNULLA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilizzo batteria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Risparmio energetico non disponibile durante la ricarica"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Risparmio energetico"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Attiva"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra di navigazione"</string>
- <string name="start" msgid="6873794757232879664">"All\'inizio"</string>
- <string name="center" msgid="4327473927066010960">"Al centro"</string>
- <string name="end" msgid="125797972524818282">"Alla fine"</string>
- <string name="space" msgid="804232271282109749">"Spaziatore"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Sinistra"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Destra"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo di pulsante"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predefinito)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Appunti"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Selettore menu/tastiera"</item>
+ <item msgid="8175437057325747277">"Nessuno"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Diviso (predefinito)"</item>
+ <item msgid="6210279084134579668">"Centrato"</item>
+ <item msgid="89143234390889289">"Allineato a sinistra"</item>
+ <item msgid="7715533883382410603">"Allineato a destra"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Selettore menu/tastiera"</string>
- <string name="select_button" msgid="1597989540662710653">"Selez. pulsante da aggiungere"</string>
- <string name="add_button" msgid="4134946063432258161">"Aggiungi pulsante"</string>
<string name="save" msgid="2311877285724540644">"Salva"</string>
<string name="reset" msgid="2448168080964209908">"Reimposta"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nessun pulsante Home trovato"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Per potersi spostare tra le funzioni del dispositivo, è necessario un pulsante Home. Aggiungine uno prima di salvare."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Modifica la larghezza del pulsante"</string>
<string name="clipboard" msgid="1313879395099896312">"Appunti"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"La funzione Appunti consente di trascinare gli elementi direttamente negli appunti e fuori dagli appunti."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Pulsante di navigazione personalizzato"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"I pulsanti keycode consentono di aggiungere tasti della tastiera alla barra di navigazione. Quando vengono premuti, emulano il tasto selezionato. Innanzitutto è necessario selezionare il tasto da associare al pulsante, poi un\'immagine da mostrare sul pulsante."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Seleziona il tasto della tastiera"</string>
- <string name="preview" msgid="9077832302472282938">"Anteprima"</string>
+ <string name="icon" msgid="8732339849035837289">"Icona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Trascina per aggiungere le funzioni"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trascina qui per rimuovere"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifica"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Riduci a icona"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignora"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Il telefono si sta scaldando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Alcune funzioni limitate durante il raffreddamento del telefono"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Sinistra"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Destra"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizza scorciatoia"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Scorciatoia"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Richiedi password"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Avvisi"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Messaggi generali"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Spazio di archiviazione"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a32fbf6654c0..d39a07aec821 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -325,12 +325,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"אזהרה - <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"מצב עבודה"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"תאורת לילה"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"‏NFC מושבת"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"‏NFC מופעל"</string>
<string name="recents_empty_message" msgid="808480104164008572">"אין פריטים אחרונים"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"מחקת הכול"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
@@ -344,16 +341,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"פיצול מסך למעלה"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"פיצול מסך לשמאל"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"פיצול מסך לימין"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
@@ -434,24 +424,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"‏נתק את ה-VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"המכשיר שלך מנוהל על ידי <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> משתמש באפליקציה <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> כדי לנהל את מכשירך."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"מנהל המערכת יכול לנטר ולנהל הגדרות, גישה ארגונית, אפליקציות, נתונים המשויכים למכשיר ומידע על מיקום המכשיר."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"למידע נוסף"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"אתה מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏פתח את הגדרות ה-VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"מנהל המערכת הפעיל את תכונת רישום התנועה ברשת, שמנטרת את תנועת הנתונים במכשיר.\n\nלמידע נוסף, צור קשר עם מנהל המערכת."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"‏נתת לאפליקציה כלשהי הרשאה להגדיר חיבור ‏VPN‏.\n\nהאפליקציה הזו יכולה לעקוב אחר הפעילות שלך ברשת ובמכשיר, כולל הודעות אימייל, אפליקציות ואתרים."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"‏פרופיל העבודה שלך מנוהל על-ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\n מנהל המערכת שלך יכול לעקוב אחרי הפעילות שלך ברשת, כולל פעילות באימייל, באפליקציות ובאתרים.\n\n למידע נוסף, צור קשר עם מנהל המערכת.\n\nבנוסף, אתה מחובר ל-VPN, שגם באמצעותו ניתן לעקוב אחרי הפעילות שלך ברשת."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"פרופיל העבודה שלך מנוהל על-ידי <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="4946600443852045903">"פרופיל העבודה שלך מנוהל על ידי <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_disabled" msgid="7412534203633528135">"המכשיר יישאר נעול עד שתבטל את נעילתו באופן ידני"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"קבל התראות מהר יותר"</string>
@@ -544,7 +530,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"השמע צליל והצג במסך"</string>
<string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
<string name="notification_done" msgid="5279426047273930175">"סיום"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> פקדי הודעות"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"בקרת הודעות"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"אפשרויות של דחיית הודעות לטיפול בהמשך"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 דקות"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 דקות"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"שעה אחת"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"אל תדחה לטיפול בהמשך"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"בטל"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"נדחה לטיפול בעוד <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"שימוש בסוללה"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"תכונת החיסכון בסוללה אינה זמינה בעת טעינת המכשיר"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"חיסכון בסוללה"</string>
@@ -606,25 +600,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"פועל"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"כבוי"</string>
<string name="nav_bar" msgid="1993221402773877607">"סרגל ניווט"</string>
- <string name="start" msgid="6873794757232879664">"התחלה"</string>
- <string name="center" msgid="4327473927066010960">"מרכז"</string>
- <string name="end" msgid="125797972524818282">"סיום"</string>
- <string name="space" msgid="804232271282109749">"רווח"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"פריסה"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"צד שמאל"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"צד ימין"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"סוג לחצן"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ברירת מחדל)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"לוח"</item>
+ <item msgid="5742013440802239414">"קוד מפתח"</item>
+ <item msgid="8748101184830239843">"מחליף תפריט / מקלדת"</item>
+ <item msgid="8175437057325747277">"ללא"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"מחולק (ברירת מחדל)"</item>
+ <item msgid="6210279084134579668">"ממורכז"</item>
+ <item msgid="89143234390889289">"מיושר לשמאל"</item>
+ <item msgid="7715533883382410603">"מיושר לימין"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"מחליף תפריט / מקלדת"</string>
- <string name="select_button" msgid="1597989540662710653">"בחירת לחצן להוספה"</string>
- <string name="add_button" msgid="4134946063432258161">"הוסף לחצן"</string>
<string name="save" msgid="2311877285724540644">"שמור"</string>
<string name="reset" msgid="2448168080964209908">"איפוס"</string>
- <string name="no_home_title" msgid="1563808595146071549">"לחצן הבית לא נמצא"</string>
- <string name="no_home_message" msgid="5408485011659260911">"לחצן הבית נדרש כדי לנווט במכשיר הזה. הוסף לחצן בית לפני השמירה."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"שינוי של רוחב לחצן"</string>
<string name="clipboard" msgid="1313879395099896312">"לוח"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"בעזרת האפשרות \'לוח\', ניתן לגרור פריטים ישירות ללוח. ניתן גם לגרור פריטים ישירות מהלוח, כשהוא זמין."</string>
<string name="accessibility_key" msgid="5701989859305675896">"לחצן לניווט מותאם אישית"</string>
<string name="keycode" msgid="7335281375728356499">"קוד מפתח"</string>
- <string name="keycode_description" msgid="1403795192716828949">"לחצנים של קוד מפתח מאפשרים להוסיף מקשי מקלדת לסרגל הניווט. בעת הלחיצה הם מדמים את מקש המקלדת שנבחר. תחילה יש לבחור את המקש ללחצן, ולאחר מכן יש לבחור תמונה שתוצג בלחצן."</string>
- <string name="select_keycode" msgid="7413765103381924584">"בחירת לחצן מקלדת"</string>
- <string name="preview" msgid="9077832302472282938">"תצוגה מקדימה"</string>
+ <string name="icon" msgid="8732339849035837289">"סמל"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"גרור כדי להוסיף משבצות"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"גרור לכאן כדי להסיר"</string>
<string name="qs_edit" msgid="2232596095725105230">"ערוך"</string>
@@ -675,8 +675,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"מזער"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"סגור"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"הטלפון מתחמם"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"קירור הטלפון ייעשה באופן אוטומטי. תוכל עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"צד שמאל"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"צד ימין"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"התאם אישית את קיצור הדרך"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"קיצור דרך"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"בקש סיסמה"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"התראות"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"צילומי מסך"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"הודעות כלליות"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"אחסון"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4ac5e07a1616..9ea02b97a22d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"読書灯"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC は無効です"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC は有効です"</string>
<string name="recents_empty_message" msgid="808480104164008572">"最近のタスクはありません"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"すべてのタスクを消去しました"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"画面を上に分割"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"画面を左に分割"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"画面を右に分割"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPNを切断"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"この端末は <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>で管理されています。"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> は <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>を使用してこの端末を管理しています。"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"管理者は、この端末に関連付けられた設定、コーポレート アクセス、アプリ、データのほか、端末の位置情報を監視、管理できます。"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"詳細"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"「<xliff:g id="VPN_APP">%1$s</xliff:g>」に接続しています。このアプリはあなたのネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN 設定を開く"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"管理者がネットワーク ログを有効にしているため、この端末のトラフィックは監視されています。\n\n詳しくは管理者にお問い合わせください。"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"アプリにVPN接続の設定を許可しました。\n\nこのアプリはあなたの端末やネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"この仕事用プロファイルは、<xliff:g id="ORGANIZATION">%1$s</xliff:g> により管理されています。\n\n管理者は、このプロファイルでのネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。\n\nまた、VPN に接続しているため、このネットワークでのあなたのネットワーク アクティビティも監視されます。"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」に接続しています。このアプリはあなたの個人のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"この仕事用プロファイルは、<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="4946600443852045903">"この仕事用プロファイルは<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_disabled" msgid="7412534203633528135">"手動でロックを解除するまでロックされたままとなります"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"通知をすばやく確認できます"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"音声とポップアップで知らせる"</string>
<string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完了"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」の通知の管理"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"通知管理"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知スヌーズ設定"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15分"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30分"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1時間"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"スヌーズなし"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"元に戻す"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"スヌーズ: <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"電池の使用状況"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電中はバッテリー セーバーは利用できません"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"バッテリー セーバー"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ON"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"OFF"</string>
<string name="nav_bar" msgid="1993221402773877607">"ナビゲーション バー"</string>
- <string name="start" msgid="6873794757232879664">"最初"</string>
- <string name="center" msgid="4327473927066010960">"中央"</string>
- <string name="end" msgid="125797972524818282">"最後"</string>
- <string name="space" msgid="804232271282109749">"スペース"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"レイアウト"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"左"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"右"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ボタンタイプ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(デフォルト)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"クリップボード"</item>
+ <item msgid="5742013440802239414">"キーコード"</item>
+ <item msgid="8748101184830239843">"メニューとキーボードの切り替え"</item>
+ <item msgid="8175437057325747277">"なし"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"分割(デフォルト)"</item>
+ <item msgid="6210279084134579668">"中央揃え"</item>
+ <item msgid="89143234390889289">"左揃え"</item>
+ <item msgid="7715533883382410603">"右揃え"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"メニューとキーボードの切り替え"</string>
- <string name="select_button" msgid="1597989540662710653">"追加するボタンの選択"</string>
- <string name="add_button" msgid="4134946063432258161">"ボタンを追加"</string>
<string name="save" msgid="2311877285724540644">"保存"</string>
<string name="reset" msgid="2448168080964209908">"リセット"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ホームボタンが見つかりません"</string>
- <string name="no_home_message" msgid="5408485011659260911">"この端末を操作できるようにするにはホームボタンが必要です。保存する前にホームボタンを追加してください。"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ボタンの幅の調整"</string>
<string name="clipboard" msgid="1313879395099896312">"クリップボード"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"クリップボード機能ではクリップボードにアイテムを直接ドラッグできます。クリップボードにアイテムがある場合、直接そのアイテムをドラッグして取り出すこともできます。"</string>
<string name="accessibility_key" msgid="5701989859305675896">"カスタム ナビゲーション ボタン"</string>
<string name="keycode" msgid="7335281375728356499">"キーコード"</string>
- <string name="keycode_description" msgid="1403795192716828949">"キーコード ボタンを利用すると、ナビゲーション バーにキーボードのキー機能を追加できるようになります。ボタンを押すと選択済みのキーボードのキーがエミュレートされます。まずボタン用にキーを選択し、次にボタン上の画像を選択する必要があります。"</string>
- <string name="select_keycode" msgid="7413765103381924584">"キーボードのボタンの選択"</string>
- <string name="preview" msgid="9077832302472282938">"プレビュー"</string>
+ <string name="icon" msgid="8732339849035837289">"アイコン"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"タイルを追加するにはドラッグしてください"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"削除するにはここにドラッグ"</string>
<string name="qs_edit" msgid="2232596095725105230">"編集"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"閉じる"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"スマートフォンの温度が上昇中"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"スマートフォンのクールダウン中は一部の機能が制限されます"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"左"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"右"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ショートカットのカスタマイズ"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ショートカット"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"パスワードの入力"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"スクリーンショット"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"一般メッセージ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ストレージ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index c0b6b79d927e..30b503e48701 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"სამსახურის რეჟიმი"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ღამის განათება"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC გათიშულია"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ჩართულია"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ყველაფერი გასუფთავდა"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ეკრანის გაყოფა ზემოთ"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ეკრანის გაყოფა მარცხნივ"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ეკრანის გაყოფა მარჯვნივ"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN-ის გათიშვა"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"თქვენს მოწყობილობას მართავს <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> იყენებს <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>-ს თქვენი მოწყობილობის სამართავად."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"თქვენს ადმინისტრატორს შეუძლია მოწყობილობასთან დაკავშირებული პარამეტრების, კორპორაციული წვდომის, აპებისა და მონაცემების (მათ შორის, თქვენი მოწყობილობის მდებარეობის ინფორმაციის) მონიტორინგი და მართვა."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"შეიტყვეთ მეტი"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"თქვენ დაუკავშირდით <xliff:g id="VPN_APP">%1$s</xliff:g>-ს, რომელსაც თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების, მონიტორინგი შეუძლია."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-ის პარამეტრების გახსნა"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"თქვენმა ადმინისტრატორმა ქსელის ჟურნალირება ჩართო, რომელიც თქვენი მოწყობილობის ტრაფიკის მონიტორინგს ახორციელებს.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"თქვენ მიეცით ნებართვა აპს, დააყენოს VPN კავშირი.\n\nამ აპს შეუძლია თქვენი მოწყობილობის და ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"თქვენს სამსახურის პროფილს მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nთქვენს ადმინისტრატორს შეუძლია თქვენი ქსელის აქტივობის (მათ შორის, ელფოსტის, აპებისა და ვებსაიტების) მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს.\n\nგარდა ამისა, თქვენ დაკავშირებული ხართ VPN-თან, რომელსაც ასევე შეუძლია თქვენი ქსელის აქტივობის მონიტორინგი."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც თქვენი პირადი ქსელის აქტივობის მონიტორინგი შეუძლია, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"თქვენს სამსახურის პროფილს მართავს <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="4946600443852045903">"თქვენი სამუშაო პროფილი <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_disabled" msgid="7412534203633528135">"მოწყობილობის დარჩება ჩაკეტილი, სანამ ხელით არ გახსნით"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"შეტყობინებების უფრო სწრაფად მიღება"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ხმის გამოცემა და ეკრანზე გამოჩენა"</string>
<string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
<string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეტყობინებების მართვის საშუალებები"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"შეტყობინებების მართვის საშუალებები"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"შეტყობინებების ჩაჩუმების ვარიანტები"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 წუთი"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 წუთი"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 საათი"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"არ ჩაჩუმდეს"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"მოქმედების გაუქმება"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"ჩაჩუმებული იქნება <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ბატარეის მოხმარება"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ბატარეის დამზოგი დატენვისას მიწვდომელია"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ბატარეის დამზოგი"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ჩართული"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"გამორთვა"</string>
<string name="nav_bar" msgid="1993221402773877607">"ნავიგაციის ზოლი"</string>
- <string name="start" msgid="6873794757232879664">"თავში"</string>
- <string name="center" msgid="4327473927066010960">"ცენტრში"</string>
- <string name="end" msgid="125797972524818282">"ბოლოში"</string>
- <string name="space" msgid="804232271282109749">"ინტერვალი"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"განლაგება"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"მარცხნივ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"მარჯვნივ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ღილაკის ტიპი"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ნაგულისხმევი)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"გაცვლის ბუფერი"</item>
+ <item msgid="5742013440802239414">"კლავიშის კოდი"</item>
+ <item msgid="8748101184830239843">"მენიუს/კლავიატურის გადამრთველი"</item>
+ <item msgid="8175437057325747277">"არცერთი"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"გაყოფილი (ნაგულისხმევი)"</item>
+ <item msgid="6210279084134579668">"ცენტრში"</item>
+ <item msgid="89143234390889289">"მარცხენა სწორებით"</item>
+ <item msgid="7715533883382410603">"მარჯვენა სწორებით"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"მენიუს/კლავიატურის გადამრთველი"</string>
- <string name="select_button" msgid="1597989540662710653">"აირჩიეთ დასამატებელი ღილაკი"</string>
- <string name="add_button" msgid="4134946063432258161">"ღილაკის დამატება"</string>
<string name="save" msgid="2311877285724540644">"შენახვა"</string>
<string name="reset" msgid="2448168080964209908">"საწყისზე დაბრუნება"</string>
- <string name="no_home_title" msgid="1563808595146071549">"მთავარი ღილაკი ვერ მოიძებნა"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ამ მოწყობილობაში ნავიგაციისთვის საჭიროა მთავარი ღილაკი. გთხოვთ, შენახვამდე დაამატოთ მთავარი ღილაკი."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ღილაკის სიგანის კორექტირება"</string>
<string name="clipboard" msgid="1313879395099896312">"გაცვლის ბუფერი"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"გაცვლის ბუფერის მეშვეობით შესაძლებელია ერთეულების ჩავლებით პირდაპირ მასში გადატანა და ჩავლებითვე გამოტანა, როცა ის ხელმისაწვდომია."</string>
<string name="accessibility_key" msgid="5701989859305675896">"ნავიგაციის მორგებული ღილაკი"</string>
<string name="keycode" msgid="7335281375728356499">"კლავიშის კოდი"</string>
- <string name="keycode_description" msgid="1403795192716828949">"კლავიშის კოდის ტიპის ღილაკების მეშვეობით ნავიგაციის ზოლში კლავიატურის კლავიშების დამატება არის შესაძლებელი. მათზე დაჭერისას არჩეული კლავიატურის კლავიშის ემულაცია ხდება. პირველ რიგში, ღილაკისთვის უნდა აირჩეს კლავიში, ხოლო შემდეგ სურათი, რომელიც ღილაკზე უნდა იყოს ნაჩვენები."</string>
- <string name="select_keycode" msgid="7413765103381924584">"აირჩიეთ კლავიატურის ღილაკი"</string>
- <string name="preview" msgid="9077832302472282938">"გადახედვა"</string>
+ <string name="icon" msgid="8732339849035837289">"ხატულა"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ფილების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
<string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ჩაკეცვა"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"დახურვა"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ტელეფონი ცხელდება"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"მარცხნივ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"მარჯვნივ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"მალსახმობის მორგება"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"მალსახმობი"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"პაროლის მოთხოვნა"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"გაფრთხილებები"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ეკრანის ანაბეჭდები"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ზოგადი შეტყობინებები"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"მეხსიერება"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 69cd8bf07704..cfcd2ec102fc 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Жұмыс режимі"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнгі жарық"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC өшірулі"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC қосулы"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Жақындағы элементтер жоқ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Сіз барлығын өшірдіңіз"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Экранды жоғарыға қарай бөлу"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Экранды солға қарай бөлу"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Экранды оңға қарай бөлу"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зарядталды"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN желісін ажырату"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Құрылғыңызды <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> басқарады."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> құрылғыны <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> қолданбасымен басқарады."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Әкімші параметрлерді, корпоративтік кіру рұқсаттарын, қолданбаларды, құрылғыға қатысты деректерді, құрылғының орналасқан жер ақпаратын бақылай және басқара алады."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Толығырақ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Желідегі әрекеттерді, соның ішінде электрондық хабарларды, қолданбаларды және вебсайттарды бақылайтын <xliff:g id="VPN_APP">%1$s</xliff:g> қолданбасына қосылдыңыз."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN параметрлерін ашу"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Әкімші құрылғыдағы трафикті қадағалау үшін желі журналын жүргізуді қосып қойған.\n\nТолығырақ ақпарат алу үшін әкімшімен хабарласыңыз."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Қолданбаға VPN байланысын орнату рұқсатын бердіңіз.\n\nБұл қолданба құрылғыңызды және желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алады."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және вебсайттарды бақылай алады.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз.\n\nСондай-ақ сіз желідегі белсенділігіңізді бақылай алатын VPN желісіне қосылғансыз."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Жеке желідегі әрекеттеріңізді, соның ішінде электрондық пошта хабарларын, қолданбаларды және вебсайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Жұмыс профиліңізді <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="4946600443852045903">"Жұмыс профиліңізді <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_disabled" msgid="7412534203633528135">"Қолмен бекітпесін ашқанша құрылғы бекітілген күйде қалады"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Хабарландыруларды тезірек алу"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Дыбыстық сигнал беру және экранға шығару"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
<string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларды басқару элементтері"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"хабарландыруларды басқару элементтері"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"хабарландыруды кідірту опциялары"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минут"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минут"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 сағат"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Кідіртілмесін"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"КЕРІ ҚАЙТАРУ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> кідіртілді"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Батареяны пайдалану"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Зарядтау кезінде Батарея үнемдегіш қол жетімді емес"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Батарея үнемдегіш"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Қосулы"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Өшірулі"</string>
<string name="nav_bar" msgid="1993221402773877607">"Шарлау тақтасы"</string>
- <string name="start" msgid="6873794757232879664">"Бастау"</string>
- <string name="center" msgid="4327473927066010960">"Орталық"</string>
- <string name="end" msgid="125797972524818282">"Аяқтау"</string>
- <string name="space" msgid="804232271282109749">"Аралық"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Формат"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Сол жақ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Оң жақ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Түйме түрі"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(әдепкі)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Буфер"</item>
+ <item msgid="5742013440802239414">"Перне коды"</item>
+ <item msgid="8748101184830239843">"Мәзір/пернетақта ауыстырғышы"</item>
+ <item msgid="8175437057325747277">"Ешқандай"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Бөлінген (әдепкі)"</item>
+ <item msgid="6210279084134579668">"Ортасына тураланған"</item>
+ <item msgid="89143234390889289">"Сол жағына тураланған"</item>
+ <item msgid="7715533883382410603">"Оң жағына тураланған"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Мәзір/пернетақта ауыстырғышы"</string>
- <string name="select_button" msgid="1597989540662710653">"Қосу үшін түймені таңдаңыз"</string>
- <string name="add_button" msgid="4134946063432258161">"Қосу түймесі"</string>
<string name="save" msgid="2311877285724540644">"Сақтау"</string>
<string name="reset" msgid="2448168080964209908">"Қайта реттеу"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Негізгі бет түймесі табылмады"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Негізгі бет түймесі осы құрылғыны шарлау үшін қажет. Сақтау алдында негізгі бет түймесін қосыңыз."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Түйме енін реттеу"</string>
<string name="clipboard" msgid="1313879395099896312">"Буфер"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"\"Буфер\" элементтерді тікелей буферге сүйреуге мүмкіндік береді. Сондай-ақ, бар болса, элементтерді тікелей буферден сүйреп шығаруға болады."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Арнаулы шарлау түймесі"</string>
<string name="keycode" msgid="7335281375728356499">"Кілт коды"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Кілт коды түймелері пернетақта пернелерін шарлау тақтасына қосуға мүмкіндік береді. Басқан кезде олар таңдалған пернетақта пернесін эмуляциялайды. Алдымен түйме үшін пернені, содан кейін түймеде көрсетілетін кескінді таңдау керек."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Пернетақта түймесін таңдау"</string>
- <string name="preview" msgid="9077832302472282938">"Алдын ала қарау"</string>
+ <string name="icon" msgid="8732339849035837289">"Белгіше"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Қажеттерін сүйреп қойыңыз"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Керексіздерін осы жерге сүйреңіз"</string>
<string name="qs_edit" msgid="2232596095725105230">"Өңдеу"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Кішірейту"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Қабылдамау"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефон қызуда"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Сол жақ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Оң жақ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Таңбашаны реттеу"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Таңбаша"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Құпия сөзді сұрау"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Дабылдар"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттар"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Жалпы хабарлар"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Жад"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 3b04eca2ba4c..a958258e1d5e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការ​ព្រមាន"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"របៀបការងារ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ពន្លឺពេលយប់"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"បាន​បិទ NFC"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"បាន​បើក NFC"</string>
<string name="recents_empty_message" msgid="808480104164008572">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"អ្នកបានជម្រះអ្វីៗទាំងអស់"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"បំបែក​អេក្រង់​ទៅ​ខាងលើ"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"បំបែក​អេក្រង់​ទៅ​ខាងឆ្វេង"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"បំបែក​អេក្រង់​ទៅ​ខាងស្តាំ"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"បាន​បញ្ចូល​ថ្ម​​"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"ផ្ដាច់ VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ឧបករណ៍របស់អ្នកគ្រប់គ្រងដោយ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ។"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ប្រើប្រាស់ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ដើម្បីគ្រប់គ្រងឧបករណ៍របស់អ្នក។"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"អ្នក​គ្រប់គ្រង​របស់អ្នក​អាចតាមដាន និង​គ្រប់គ្រង​ការកំណត់ ការ​ចូល​ប្រើ​លក្ខណៈ​ក្រុមហ៊ុន កម្មវិធី ទិន្នន័យ​ពាក់ព័ន្ធ​នឹង​ឧបករណ៍​របស់អ្នក និង​ព័ត៌មាន​ទីតាំង​ឧបករណ៍​របស់អ្នក។"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ស្វែងយល់បន្ថែម"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"អ្នកបានភ្ជាប់ទៅ <xliff:g id="VPN_APP">%1$s</xliff:g> ដែលអាចតាមដានសកម្មភាពក្នុងបណ្តាញរបស់អ្នក រួមទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រផងដែរ។"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"បើក​ការ​កំណត់​ VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"អ្នក​គ្រប់គ្រង​របស់អ្នក​បាន​បើក​ការ​ធ្វើ​កំណត់ហេតុ​បណ្តាញ​ ដែល​នឹង​តាមដាន​ចរាចរណ៍​នៅលើ​ឧបករណ៍​របស់អ្នក។\n\nសម្រាប់​ព័ត៌មាន​បន្ថែម​ សូម​ទាក់ទង​អ្នក​គ្រប់គ្រង​របស់អ្នក។"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"អ្នកបានអនុញ្ញាតឲ្យកម្មវិធីដំឡើងការតភ្ជាប់ VPN។\n\nកម្មវិធីនេះអាចឃ្លាំមើលឧបករណ៍ និងសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"កម្រង​ព័ត៌មាន​ការងារ​របស់អ្នក​ស្ថិត​ក្រោម​ការ​គ្រប់គ្រង​របស់ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ។\n\nអ្នក​គ្រប់គ្រង​របស់អ្នក​មាន​លទ្ធភាព​តាមដាន​សកម្មភាព​នៅលើ​បណ្តាញ​របស់អ្នក រួមទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។\n\nសម្រាប់​ព័ត៌មាន​បន្ថែម​ សូម​ទាក់ទង​អ្នក​គ្រប់គ្រង​របស់អ្នក។\n\nអ្នក​ក៏​ត្រូវ​បាន​ភ្ជាប់​ទៅ VPN ដែល​អាច​តាមដាន​សកម្មភាព​នៅលើ​បណ្តាញ​របស់អ្នក​ផងដែរ។"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"អ្នកត្រូវបានភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"កម្រង​ព័ត៌មាន​ការងារ​របស់អ្នក​ស្ថិត​ក្រោម​ការ​គ្រប់គ្រង​របស់ <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="4946600443852045903">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <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_disabled" msgid="7412534203633528135">"ឧបករណ៍​នឹង​ចាក់​សោ​រហូត​ដល់​អ្នក​ដោះ​សោ​ដោយ​ដៃ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ទទួល​បាន​ការ​ជូន​ដំណឹង​កាន់តែ​លឿន"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"បន្លឺ​សំឡេង និង​លេច​ឡើង​នៅ​លើ​អេក្រង់"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
<string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"អង្គគ្រប់គ្រងការជូនដំណឹង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ការគ្រប់គ្រង​ការជូន​ដំណឹង"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ជម្រើស​ផ្អាកការ​ជូនដំណឹង"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 នាទី"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 នាទី"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ម៉ោង"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"កុំ​ផ្អាក"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"មិន​ធ្វើវិញ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"បាន​ផ្អាក​រយៈពេល <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ការប្រើប្រាស់ថ្ម"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"កម្មវិធីសន្សំថ្ម"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"បើក"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"បិទ"</string>
<string name="nav_bar" msgid="1993221402773877607">"របាររុករក"</string>
- <string name="start" msgid="6873794757232879664">"ចាប់ផ្ដើម"</string>
- <string name="center" msgid="4327473927066010960">"កណ្តាល"</string>
- <string name="end" msgid="125797972524818282">"បញ្ចប់"</string>
- <string name="space" msgid="804232271282109749">"ចន្លោះ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ប្លង់"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ឆ្វេង"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ស្ដាំ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ប្រភេទ​ប៊ូតុង"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(លំនាំដើម)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"អង្គចងចាំ"</item>
+ <item msgid="5742013440802239414">"លេខកូដ​គ្រាប់ចុច"</item>
+ <item msgid="8748101184830239843">"ម៉ឺនុយ / កម្មវិធី​ប្តូរក្តារ​ចុច"</item>
+ <item msgid="8175437057325747277">"គ្មាន"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"បំបែក (លំនាំដើម)"</item>
+ <item msgid="6210279084134579668">"ដាក់​នៅ​កណ្តាល"</item>
+ <item msgid="89143234390889289">"តម្រឹម​ឆ្វេង"</item>
+ <item msgid="7715533883382410603">"តម្រឹមស្ដាំ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"កម្មវិធីប្តូរក្តារចុច / ម៉ឺនុយ"</string>
- <string name="select_button" msgid="1597989540662710653">"ជ្រើសប៊ូតុងដែលត្រូវថែម"</string>
- <string name="add_button" msgid="4134946063432258161">"បន្ថែមប៊ូតុង"</string>
<string name="save" msgid="2311877285724540644">"រក្សាទុក"</string>
<string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
- <string name="no_home_title" msgid="1563808595146071549">"រកមិនឃើញប៊ូតុងដើមទេ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"តម្រូវឲ្យមានប៊ូតុងដើមដើម្បីអាចរុករកឧបករណ៍នេះបាន។ សូមបន្ថែមប៊ូតុងដើមមុនពេលរក្សាទុក។"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"កែសម្រួលទទឹងប៊ូតុង"</string>
<string name="clipboard" msgid="1313879395099896312">"ក្ដារ​តម្បៀត​ខ្ទាស់"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ក្តារតម្បៀតខ្ទាស់អនុញ្ញាតឲ្យមានការអូសធាតុដោយផ្ទាល់ទៅកាន់ក្តារតម្បៀតខ្ទាស់នោះ។ នៅពេលដែលមានធាតុស្រាប់ក្នុងក្តារតម្បៀតខ្ទាស់ ធាតុទាំងនោះក៏អាចអូសដោយផ្ទាល់ចេញពីក្តារតម្បៀតខ្ទាស់បានដែរ។"</string>
<string name="accessibility_key" msgid="5701989859305675896">"ប៊ូតុងរុករកផ្ទាល់ខ្លួន"</string>
<string name="keycode" msgid="7335281375728356499">"លេខកូដគ្រាប់ចុច"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ប៊ូតុងលេខកូដគ្រាប់ចុចអនុញ្ញាតឲ្យមានការបន្ថែមគ្រាប់ចុចនៃក្តារចុចទៅក្នុងរបាររុករក។ នៅពេលចុចប៊ូតុងទាំងនោះ ពួកវាបង្កើតមុខងារឲ្យគ្រាប់ចុចនៃក្តារចុចដែលបានជ្រើស។ សូមជ្រើសរើសគ្រាប់ចុចសម្រាប់ប៊ូតុងជាមុនសិន មុនពេលដែលរូបភាពត្រូវបានបង្ហាញនៅលើប៊ូតុង។"</string>
- <string name="select_keycode" msgid="7413765103381924584">"ជ្រើសប៊ូតុងក្តារចុច"</string>
- <string name="preview" msgid="9077832302472282938">"មើលជាមុន"</string>
+ <string name="icon" msgid="8732339849035837289">"រូប​តំណាង"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"អូសដើម្បីបន្ថែមប្រអប់"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"អូសទីនេះដើម្បីយកចេញ"</string>
<string name="qs_edit" msgid="2232596095725105230">"កែសម្រួល"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"បង្រួម"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"បដិសេធ"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ទូរសព្ទ​នេះ​កំពុង​កើន​កម្តៅ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"មុខងារ​មួយ​ចំនួន​នឹង​មិន​អាច​ប្រើ​បាន​ពេញលេញ​នោះ​ទេ ខណៈពេល​ដែល​ទូរសព្ទ​កំពុង​បញ្ចុះ​កម្តៅ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"ទូរសព្ទ​របស់អ្នក​នឹង​ព្យាយាម​បញ្ចុះ​កម្តៅ​ដោយ​ស្វ័យប្រវត្តិ។ អ្នក​នៅតែ​អាច​ប្រើ​ទូរសព្ទ​របស់អ្នក​បាន​ដដែល​ ប៉ុន្តែ​វា​នឹង​ដំណើរ​ការ​យឺត​ជាង​មុន។\n\nបន្ទាប់​ពី​ទូរសព្ទ​របស់អ្នក​ត្រជាក់​ជាង​មុន​ហើយ វា​នឹង​ដំណើរការ​ដូច​ធម្មតា។"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ឆ្វេង"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ស្ដាំ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ប្ដូរ​ផ្លូវកាត់​តាម​បំណង"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ផ្លូវកាត់"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"ជំរុញ​ឲ្យ​បញ្ចូល​ពាក្យ​សម្ងាត់"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ការ​ជូនដំណឹង"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"រូបថត​អេក្រង់"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"សារ​ទូទៅ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ទំហំផ្ទុក"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e26ac8787e2d..ba681db62f6c 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ಕೆಲಸದ ಮೋಡ್"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ನೈಟ್ ಲೈಟ್"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ನೀವು ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿರುವಿರಿ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ಮೇಲ್ಭಾಗಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ಎಡಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ಬಲಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ಸಂಪರ್ಕಕಡಿತಗೊಳಿಸಿ"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ನಿಮ್ಮ ಸಾಧನವನ್ನು <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ನಿಂದ ನಿರ್ವಹಿಸಲಾಗಿದೆ."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲು <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ಅನ್ನು ಬಳಸುತ್ತದೆ."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ನಿರ್ವಾಹಕರು ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ನಿಮ್ಮ ಸಾಧನದ ಡೇಟಾ ಮತ್ತು ಸ್ಥಳ ಮಾಹಿತಿಯ ನಿಗಾವಣೆ ಮತ್ತು ನಿರ್ವಹಣೆ ಮಾಡಬಹುದು."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ, <xliff:g id="VPN_APP">%1$s</xliff:g> ಗೆ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ನೆಟ್‌ವರ್ಕ್ ಲಾಗಿಂಗ್ ಆನ್ ಮಾಡಿದ್ದಾರೆ. ಇದು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ನಿಗಾ ಇರಿಸುತ್ತದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"ನೀವು VPN ಸಂಪರ್ಕ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡಿರುವಿರಿ.\n\nಈ ಅಪ್ಲಿಕೇಶನ್ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ನಿರ್ವಹಿಸುತ್ತಿದೆ.\n\nಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳೂ ಸೇರಿದಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ ಚಟುವಟಿಕೆಯ ಮೇಲೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಗಾ ಇರಿಸಬಲ್ಲರು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.\n\nಅಲ್ಲದೇ, ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ ಚಟುವಟಿಕೆಯ ನಿಗಾ ವಹಿಸುವ VPN ಗೂ ಸಹ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು <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="4946600443852045903">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <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_disabled" msgid="7412534203633528135">"ನೀವಾಗಿಯೇ ಅನ್‌ಲಾಕ್‌ ಮಾಡುವವರೆಗೆ ಸಾಧನವು ಲಾಕ್‌ ಆಗಿಯೇ ಇರುತ್ತದೆ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ವೇಗವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ಪರದೆಯ ಮೇಲೆ ಧ್ವನಿಮಾಡಿ ಮತ್ತು ಪಾಪ್ ಮಾಡಿ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ಅಧಿಸೂಚನೆ ಸ್ನೂಜ್ ಆಯ್ಕೆಗಳು"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 ನಿಮಿಷಗಳು"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 ನಿಮಿಷಗಳು"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ಗಂಟೆ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ಸ್ನೂಜ್‌ ಮಾಡಬೇಡಿ"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ಗೆ ಸ್ನೂಜ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ಬ್ಯಾಟರಿ ಬಳಕೆ"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್‌‌ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ಬ್ಯಾಟರಿ ಸೇವರ್‌‌"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ಆನ್"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ಆಫ್"</string>
<string name="nav_bar" msgid="1993221402773877607">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
- <string name="start" msgid="6873794757232879664">"ಪ್ರಾರಂಭ"</string>
- <string name="center" msgid="4327473927066010960">"ಮಧ್ಯ"</string>
- <string name="end" msgid="125797972524818282">"ಮುಕ್ತಾಯ"</string>
- <string name="space" msgid="804232271282109749">"ಸ್ಪೇಸರ್"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ಲೇಔಟ್"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ಎಡ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ಬಲ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ಬಟನ್ ವಿಧ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ಡಿಫಾಲ್ಟ್‌)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</item>
+ <item msgid="5742013440802239414">"ಕೀಕೋಡ್"</item>
+ <item msgid="8748101184830239843">"ಮೆನು / ಕೀಬೋರ್ಡ್ ಬದಲಾಯಿಸುವಿಕೆ"</item>
+ <item msgid="8175437057325747277">"ಯಾವುದೂ ಅಲ್ಲ"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"ವಿಭಜಿಸಲಾಗಿದೆ (ಡಿಫಾಲ್ಟ್‌)"</item>
+ <item msgid="6210279084134579668">"ಕೇಂದ್ರೀಕೃತ"</item>
+ <item msgid="89143234390889289">"ಎಡಕ್ಕೆ ಹೊಂದಿಸಿರುವುದು"</item>
+ <item msgid="7715533883382410603">"ಬಲಕ್ಕೆ ಹೊಂದಿಸಿರುವುದು"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"ಮೆನು / ಕೀಬೋರ್ಡ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
- <string name="select_button" msgid="1597989540662710653">"ಸೇರಿಸಲು ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="add_button" msgid="4134946063432258161">"ಬಟನ್ ಸೇರಿಸು"</string>
<string name="save" msgid="2311877285724540644">"ಉಳಿಸು"</string>
<string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಮುಖಪುಟ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಮುಖಪುಟ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಮುಖಪುಟ ಬಟನ್ ಸೇರಿಸಿ."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ಬಟನ್ ಅಳತೆ ಹೊಂದಿಸು"</string>
<string name="clipboard" msgid="1313879395099896312">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ಐಟಂಗಳನ್ನು ನೇರವಾಗಿ ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಅನುಮತಿಸುತ್ತದೆ. ಐಟಂಗಳು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವಾಗ ಅವುಗಳನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ನೇರವಾಗಿ ಹೊರಗೆ ಹಾಕಬಹುದಾಗಿರುತ್ತದೆ."</string>
<string name="accessibility_key" msgid="5701989859305675896">"ಕಸ್ಟಮ್ ನ್ಯಾವಿಗೇಷನ್ ಬಟನ್"</string>
<string name="keycode" msgid="7335281375728356499">"ಕೀಕೋಡ್"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ಕೀಕೋಡ್ ಬಟನ್‌ಗಳು ಕೀಬೋರ್ಡ್ ಕೀಗಳನ್ನು ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್‌ಗೆ ಸೇರಿಸಲು ಆನುಮತಿಸುತ್ತದೆ. ಒತ್ತಿದಾಗ ಆಯ್ಕೆಮಾಡಲಾದ ಕೀಬೋರ್ಡ್ ಕೀಯನ್ನು ಅವುಗಳು ಅನುಕರಿಸುತ್ತವೆ. ಮೊದಲು ಬಟನ್‌ಗೆ ಕೀಯನ್ನು ಆಯ್ಕೆಮಾಡಬೇಕು ನಂತರ ಬಟನ್‌ನಲ್ಲಿ ತೋರಿಸಬೇಕಾದ ಚಿತ್ರವನ್ನು ಅನುಸರಿಸಬೇಕು."</string>
- <string name="select_keycode" msgid="7413765103381924584">"ಕೀಬೋರ್ಡ್ ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="preview" msgid="9077832302472282938">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
+ <string name="icon" msgid="8732339849035837289">"ಐಕಾನ್‌"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ಎಡಿಟ್"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ಕುಗ್ಗಿಸಿ"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"ವಜಾಗೊಳಿಸಿ"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ಫೋನ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸುತ್ತದೆ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ಎಡ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ಬಲ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ಶಾರ್ಟ್‌ಕಟ್ ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ಶಾರ್ಟ್‌ಕಟ್"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"ಪಾಸ್‌ವರ್ಡ್‌ ಕೇಳಿ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ಎಚ್ಚರಿಕೆಗಳು"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳು"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ಸಂಗ್ರಹಣೆ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 62b5d47fcdb5..c5faa18ed85c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"작업 모드"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"야간 조명"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC 사용 중지됨"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC 사용 설정됨"</string>
<string name="recents_empty_message" msgid="808480104164008572">"최근 항목이 없습니다."</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"모든 항목을 삭제했습니다."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"위쪽으로 화면 분할"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"왼쪽으로 화면 분할"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"오른쪽으로 화면 분할"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN 연결 해제"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>에서 관리하는 기기입니다."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>이(가) <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>을(를) 사용하여 내 기기를 관리합니다."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"관리자는 설정, 기업 액세스, 앱, 기기에 연결된 데이터 및 기기의 위치 정보를 모니터링하고 관리할 수 있습니다."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"자세히 알아보기"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"공개 VPN 설정"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"관리자가 기기에서 발생하는 트래픽을 모니터링하는 네트워크 로깅을 사용 설정했습니다.\n\n자세한 정보는 관리자에게 문의하세요."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN 연결을 설정할 수 있는 권한을 앱에 부여했습니다.\n\n이 앱에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동 및 기기를 모니터링할 수 있습니다."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 직장 프로필을 관리합니다.\n\n관리자가 이메일, 앱, 웹사이트를 비롯한 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 정보는 관리자에게 문의하세요.\n\n또한 VPN에 연결되어 있으며, VPN에서 네트워크 활동을 모니터링할 수 있습니다."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<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="4946600443852045903">"직장 프로필은 <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_disabled" msgid="7412534203633528135">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"알림을 더욱 빠르게 받기"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"소리 및 화면 표시로 알림"</string>
<string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
<string name="notification_done" msgid="5279426047273930175">"완료"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 관리"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"알림 관리"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"알림 일시 중지 옵션"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15분"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30분"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1시간"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"일시 중지 사용 안함"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"실행취소"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> 동안 일시 중지됨"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"배터리 사용량"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"충전하는 동안 배터리 세이버는 사용할 수 없습니다."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"배터리 세이버"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"사용"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"사용 안함"</string>
<string name="nav_bar" msgid="1993221402773877607">"탐색 메뉴"</string>
- <string name="start" msgid="6873794757232879664">"시작"</string>
- <string name="center" msgid="4327473927066010960">"중앙"</string>
- <string name="end" msgid="125797972524818282">"끝"</string>
- <string name="space" msgid="804232271282109749">"공백"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"레이아웃"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"왼쪽"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"오른쪽"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"버튼 유형"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(기본)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"클립보드"</item>
+ <item msgid="5742013440802239414">"키 코드"</item>
+ <item msgid="8748101184830239843">"메뉴/키보드 전환 도구"</item>
+ <item msgid="8175437057325747277">"없음"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"분할(기본)"</item>
+ <item msgid="6210279084134579668">"가운데 맞춤"</item>
+ <item msgid="89143234390889289">"왼쪽 정렬됨"</item>
+ <item msgid="7715533883382410603">"오른쪽 정렬됨"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"메뉴/키보드 전환 도구"</string>
- <string name="select_button" msgid="1597989540662710653">"추가할 버튼 선택"</string>
- <string name="add_button" msgid="4134946063432258161">"버튼 추가"</string>
<string name="save" msgid="2311877285724540644">"저장"</string>
<string name="reset" msgid="2448168080964209908">"초기화"</string>
- <string name="no_home_title" msgid="1563808595146071549">"홈 버튼을 찾지 못함"</string>
- <string name="no_home_message" msgid="5408485011659260911">"이 기기를 탐색하려면 홈 버튼을 사용해야 합니다. 홈 버튼을 추가한 다음 저장하세요."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"버튼 너비 조정"</string>
<string name="clipboard" msgid="1313879395099896312">"클립보드"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"클립보드를 사용하면 항목을 클립보드로 바로 드래그할 수 있습니다. 또한 발표 시 항목을 클립보드 밖으로 바로 드래그할 수도 있습니다."</string>
<string name="accessibility_key" msgid="5701989859305675896">"맞춤 탐색 버튼"</string>
<string name="keycode" msgid="7335281375728356499">"키 코드"</string>
- <string name="keycode_description" msgid="1403795192716828949">"키 코드 버튼을 사용하면 키보드 키를 탐색 메뉴에 추가할 수 있습니다. 키 코드 버튼을 누르면 선택된 키보드 키가 에뮬레이션됩니다. 먼저 버튼에 대해 키를 선택하고 그다음 버튼에 표시될 이미지를 선택해야 합니다."</string>
- <string name="select_keycode" msgid="7413765103381924584">"키보드 버튼 선택"</string>
- <string name="preview" msgid="9077832302472282938">"미리보기"</string>
+ <string name="icon" msgid="8732339849035837289">"아이콘"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"드래그하여 타일 추가"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"삭제하려면 여기를 드래그"</string>
<string name="qs_edit" msgid="2232596095725105230">"수정"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"최소화"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"닫기"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"휴대전화 온도가 높음"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다."</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"왼쪽"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"오른쪽"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"바로가기 맞춤설정"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"바로가기"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"비밀번호 요청"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"알림"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"스크린샷"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"일반 메시지"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"저장소"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2dc5c1d223da..6f57a7355421 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Иштөө режими"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнкү жарык"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC өчүрүлгөн"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC иштетилген"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Акыркы колдонмолор жок"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Баарын тазаладыңыз"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Экранды өйдө жакка бөлүү"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Экранды сол жакка бөлүү"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Экранды оң жакка бөлүү"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Кубатталды"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN\'ди ажыратуу"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Түзмөгүңүз <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> тарабынан башкарылат."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Түзмөгүңүздү башкаруу үчүн <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюму <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> колдонмосун колдонот."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Администраторуңуз жөндөөлөрдү, корпоративдик кирүү мүмкүнчүлүгүн, колдонмолорду, уруксаттарды жана ушул түзмөкө байланыштуу дайындарды, ошондой эле түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Кеңири маалымат"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тескей турган <xliff:g id="VPN_APP">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN жөндөөлөрүн ачуу"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Администраторуңуз тармактын таржымалын алууну иштетти, андыктан түзмөгүңүздөгү трафик көзөмөлгө алынды.\n\nКеңири маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Колдонмого VPN туташуусун орнотууга уруксат бердиңиз.\n\nБул колдонмо түзмөгүңүздү жана электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди көзөмөлдөй алат."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\n\nАдминистраторуңуздун тармактагы аракетиңизди, анын ичинде электрондук почталар, колдонмолор жана вебсайттарды көзөмөлдөө мүмкүнчүлүгү бар.\n\nКөбүрөөк маалымат үчүн, администраторуңузга кайрылыңыз.\n\nСиз тармактагы жеке аракетиңизди көзөмөлдөй турган VPN\'ге да туташкансыз."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди тескей турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Жумуш профилиңизди <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="4946600443852045903">"Жумуш профилиңизди <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_disabled" msgid="7412534203633528135">"Түзмөктүн кулпусу кол менен ачылмайынча кулпуланган бойдон алат"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Эскертмелерди тезирээк алуу"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Добуш менен экранга калкып чыксын"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
<string name="notification_done" msgid="5279426047273930175">"Бүттү"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"эскертмелерди башкаруу каражаттары"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"эскертмени тындыруу опциялары"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 мүнөт"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 мүнөт"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 саат"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Тындырылбасын"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"КАЙТАРУУ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> тындырылды"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Батарея колдонулушу"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Батареяны үнөмдөгүч"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Күйүк"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Өчүк"</string>
<string name="nav_bar" msgid="1993221402773877607">"Чабыттоо тилкеси"</string>
- <string name="start" msgid="6873794757232879664">"Баштоо"</string>
- <string name="center" msgid="4327473927066010960">"Экрандын ортосунда"</string>
- <string name="end" msgid="125797972524818282">"Бүтүрүү"</string>
- <string name="space" msgid="804232271282109749">"Боштук калтыргыч"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Калып"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Сол жакта"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Оң жакта"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Баскычтын түрү"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(демейки)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Алмашуу буфери"</item>
+ <item msgid="5742013440802239414">"Баскыч коду"</item>
+ <item msgid="8748101184830239843">"Меню / Баскычтоп которуштургуч"</item>
+ <item msgid="8175437057325747277">"Эч бири"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Бөлүнгөн (демейки)"</item>
+ <item msgid="6210279084134579668">"Так ортодо"</item>
+ <item msgid="89143234390889289">"Солго тегизделген"</item>
+ <item msgid="7715533883382410603">"Оңго тегизделген"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Меню / Баскычтоп которуштургуч"</string>
- <string name="select_button" msgid="1597989540662710653">"Кошула турган баскычты тандоо"</string>
- <string name="add_button" msgid="4134946063432258161">"Баскыч кошуу"</string>
<string name="save" msgid="2311877285724540644">"Сактоо"</string>
<string name="reset" msgid="2448168080964209908">"Баштапкы абалга келтирүү"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Башкы бет баскычы табылган жок"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Бул түзмөктө чабыттоо үчүн башкы бет баскычы керек. Сактаардан мурун, башкы бет баскычын кошуңуз."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Баскычтын жазылыгын тууралоо"</string>
<string name="clipboard" msgid="1313879395099896312">"Алмашуу буфери"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Бул баскычтын жардамы менен файлдарды алмашуу буферине көчүрүп, анын ичинен сүйрөп чыгууга болот."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Ыңгайлаштырылган чабыттоо баскычы"</string>
<string name="keycode" msgid="7335281375728356499">"Баскыч коду"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Бул баскычтын жардамы менен баскычтоптогу баскычтарды чабыттоо тилкесине кошууга болот. Ал үчүн баскычты жана тийиштүү баскычтын көрүнүшүн тандаңыз."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
- <string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
+ <string name="icon" msgid="8732339849035837289">"Сүрөтчө"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
<string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Кичирейтүү"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Этибарга албоо"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефонуңуз ысып баратат"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Телефон сууганча айрым элементтердин иши чектелген"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Сол жакта"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Оң жакта"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Кыска жолду тууралоо"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Кыска жол"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Сырсөздү суроо"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Эскертүүлөр"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттор"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Жалпы билдирүүлөр"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Сактагыч"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7fb5c1e03ea4..c7475bc61264 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ໂໝດການເຮັດວຽກ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ແສງກາງຄືນ"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is disabled"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is enabled"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ທ່ານລຶບລ້າງທຸກຢ່າງແລ້ວ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Split screen to the top"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Split screen to the left"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Split screen to the right"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"ຕັດ​ການ​ເຊື່ອມ​ຕໍ່ VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ອຸປະກອນຂອງທ່ານແມ່ນຈັດການໂດຍ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ໃຊ້ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ເພື່ອຈັດການອຸປະກອນຂອງທ່ານ."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານສາມາດຕິດຕາມ ແລະ ຈັດການການຕັ້ງຄ່າ, ການເຂົ້າເຖິງອົງກອນ, ແອັບ, ຂໍ້ມູນທີ່ເຊື່ອມໂຍງກັບອຸປະກອນຂອງທ່ານແລະ ຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນທ່ານໄດ້."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ສຶກສາເພີ່ມເຕີມ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="VPN_APP">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍ, ຮວມທັງອີເມວ, ແອັບ ແລະ ເວັບໄຊຕ່າງໆໄດ້."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"ເປີດການຕັ້ງຄ່າ VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"ທ່ານໄດ້ອະນຸຍາດໃຫ້ແອັບຕັ້ງການເຊື່ອມຕໍ່ VPN.\n\nແອັບນີ້ສາມາດຕິດຕາມການເຄື່ອນໄຫວຂອງອຸປະກອນ ແລະເຄືອຂ່າຍຂອງທ່ານ ເຊິ່ງລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ຮວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊໄດ້."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຈັດການໂດຍ <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_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ຮັບເອົາການ​ແຈ້ງເຕືອນ​ໄວຂຶ້ນ"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ເຮັດສຽງດັງ ແລະ ສະແດງຂຶ້ນໃນໜ້າຈໍ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
<string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"ການຄວບຄຸມການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ການຄວບຄຸມການແຈ້ງເຕືອນ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ຕົວເລືອກການເລື່ອນການແຈ້ງເຕືອນ"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 ນາທີ"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 ນາທີ"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ຊົ່ວໂມງ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ບໍ່ເລື່ອນ"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ຍົກເລີກ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"ເລື່ອນໄປ <xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ນາທີແລ້ວ"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ການໃຊ້ແບັດເຕີຣີ"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ຕົວປະຢັດແບັດເຕີຣີບໍ່ມີໃຫ້ນຳໃຊ້ໃນລະຫວ່າງການສາກ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ຕົວປະຢັດ​ແບັດເຕີຣີ"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ເປີດ"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ປິດ"</string>
<string name="nav_bar" msgid="1993221402773877607">"ແຖບນຳທາງ"</string>
- <string name="start" msgid="6873794757232879664">"ເລີ່ມຕົ້ນ"</string>
- <string name="center" msgid="4327473927066010960">"ເຄິ່ງກາງ"</string>
- <string name="end" msgid="125797972524818282">"ທ້າຍ"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ຮູບແບບ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ຊ້າຍ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ຂວາ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ປະເພດປຸ່ມ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ຄ່າເລີ່ມຕົ້ນ)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ຄລິບບອດ"</item>
+ <item msgid="5742013440802239414">"ລະຫັດກະແຈ"</item>
+ <item msgid="8748101184830239843">"ຕົວປ່ຽນເມນູ / ແປ້ນພິມ"</item>
+ <item msgid="8175437057325747277">"ບໍ່ໃຊ້"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"ແຍກກັນ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+ <item msgid="6210279084134579668">"ທາງກາງ"</item>
+ <item msgid="89143234390889289">"ຮຽງຊ້າຍ"</item>
+ <item msgid="7715533883382410603">"ຮຽງຂວາ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"ຕົວປ່ຽນເມນູ / ແປ້ນພິມ"</string>
- <string name="select_button" msgid="1597989540662710653">"ເລືອກປຸ່ມເພື່ອເພີ່ມ"</string>
- <string name="add_button" msgid="4134946063432258161">"ເພີ່ມປຸ່ມ"</string>
<string name="save" msgid="2311877285724540644">"ບັນທຶກ"</string>
<string name="reset" msgid="2448168080964209908">"ຣີເຊັດ"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ບໍ່ພົບປຸ່ມໜ້າຫຼັກ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ຈຳເປັນຕ້ອງມີປຸ່ມໜ້າຫຼັກເພື່ອໃຫ້ສາມາດນຳທາງອຸປະກອນນີ້. ກະລຸນາເພີ່ມປຸ່ມໜ້າຫຼັກກ່ອນທີ່ຈະບັນທຶກ."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ປັບຄວາມກວ້າງຂອງປຸ່ມ"</string>
<string name="clipboard" msgid="1313879395099896312">"​ຄລິບບອດ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ຄລິບບອດອະນຸຍາດໃຫ້ລາກລາຍການຕ່າງໆໂດຍກົງຫາຄລິບບອດ. ນອກນັ້ນ ຍັງສາມາດລາກລາຍການໂດຍກົງອອກຈາກຄລິບບອດໄດ້ ເມື່ອມີຢູ່."</string>
<string name="accessibility_key" msgid="5701989859305675896">"ປຸ່ມນຳທາງແບບກຳນົດເອງ"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ປຸ່ມ Keycode ອະນຸຍາດໃຫ້ເພີ່ມປຸ່ມແປ້ນພິມໃສ່ແຖບການນຳທາງ. ເມື່ອກົດແລ້ວພວກມັນຈະຮຽນແບບປຸ່ມແປ້ນພິມທີ່ເລືອກ. ທຳອິດຕ້ອງເລືອກປຸ່ມແປ້ນພິມສຳລັບປຸ່ມນັ້ນ, ຕາມດ້ວຍຮູບທີ່ຈະປາກົດຂຶ້ນເທິງປຸ່ມນັ້ນ."</string>
- <string name="select_keycode" msgid="7413765103381924584">"ເລືອກປຸ່ມແປ້ນພິມ"</string>
- <string name="preview" msgid="9077832302472282938">"ສະແດງຕົວຢ່າງ"</string>
+ <string name="icon" msgid="8732339849035837289">"ໄອຄອນ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ລາກເພື່ອເພີ່ມໄອຄອນ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ລາກມາບ່ອນນີ້ເພື່ອລຶບອອກ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ແກ້ໄຂ"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ຫຍໍ້"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"ປິດໄວ້"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ໂທລະສັບກຳລັງຮ້ອນຂຶ້ນ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ເນື່ອງໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ຊ້າຍ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ຂວາ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ປັບແຕ່ງທາງລັດ"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ທາງລັດ"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"ຖາມຫາລະຫັດຜ່ານ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ການເຕືອນ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ຮູບຖ່າຍໜ້າຈໍ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ຂໍ້ຄວາມທົ່ວໄປ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ບ່ອນເກັບຂໍ້ມູນ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 60368425d0c9..e6713f2ba207 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -325,12 +325,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darbo režimas"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakties šviesa"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"ALR"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"ALR išjungtas"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"ALR įjungtas"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nėra jokių naujausių elementų"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Viską išvalėte"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
@@ -344,16 +341,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Skaidyti ekraną į viršų"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Skaidyti ekraną į kairę"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Skaidyti ekraną į dešinę"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
@@ -434,24 +424,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Atjungti VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Įrenginį tvarko „<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>“."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"„<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>“ naudoja „<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>“ įrenginiui tvarkyti."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrat. gali stebėti ir tvark. nustat., įmonės prieigos par., progr., su įreng. susietus duomenis ir įreng. vietovės inform."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Sužinoti daugiau"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Esate prisijungę prie programos „<xliff:g id="VPN_APP">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Atidaryti VPN nustatymus"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratorius įjungė tinklo duomenų įrašymą į žurnalą. Įjungus šią funkciją stebimas srautas jūsų įrenginyje.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Suteikėte programai leidimą nustatyti VPN ryšį.\n\nŠi programa gali stebėti įrenginio ir tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nJūsų administratorius gali stebėti jūsų tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi.\n\nTaip pat esate prisijungę prie VPN, kuris gali stebėti jūsų tinklo veiklą."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri negali stebėti jūsų tinklo veiklos, įskaitant el. laiškus, programas ir svetaines.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Įrenginys liks užrakintas, kol neatrakinsite jo neautomatiniu būdu"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Greičiau gaukite pranešimus"</string>
@@ -544,7 +530,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Skambėti ir iššokti ekrane"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
<string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų valdikliai"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"pranešimų valdikliai"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"pranešimų snaudimo parinktys"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 min."</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 min."</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 val."</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Nesnausti"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANULIUOTI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Nustatyta snausti <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akum. energ. vartoj."</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumuliatoriaus tausojimo priemonė nepasiekiama įkraunant"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumuliatoriaus tausojimo priemonė"</string>
@@ -606,25 +600,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Įjungta"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Išjungta"</string>
<string name="nav_bar" msgid="1993221402773877607">"Naršymo juosta"</string>
- <string name="start" msgid="6873794757232879664">"Pradėti"</string>
- <string name="center" msgid="4327473927066010960">"Centre"</string>
- <string name="end" msgid="125797972524818282">"Baigti"</string>
- <string name="space" msgid="804232271282109749">"Skirtukas"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Išdėstymas"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kairėn"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Dešinėn"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Mygtuko tipas"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(numatytoji)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Iškarpinė"</item>
+ <item msgid="5742013440802239414">"Klavišo kodas"</item>
+ <item msgid="8748101184830239843">"Meniu / klaviatūros perjungiklis"</item>
+ <item msgid="8175437057325747277">"Nėra"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Padalyta (numatytoji)"</item>
+ <item msgid="6210279084134579668">"Centruota"</item>
+ <item msgid="89143234390889289">"Sulygiuota kairėje"</item>
+ <item msgid="7715533883382410603">"Sulygiuota dešinėje"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Meniu / klaviatūros perjung."</string>
- <string name="select_button" msgid="1597989540662710653">"Norimo pridėti mygt. pasirink."</string>
- <string name="add_button" msgid="4134946063432258161">"Pridėti mygtuką"</string>
<string name="save" msgid="2311877285724540644">"Išsaugoti"</string>
<string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Pagr. pusl. mygtukas nerastas"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Kad būtų galima naršyti šį įrenginį, reikalingas pagrindinio puslapio mygtukas. Prieš išsaugodami pridėkite pagrindinio puslapio mygtuką."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Mygtuko pločio koregavimas"</string>
<string name="clipboard" msgid="1313879395099896312">"Iškarpinė"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Naudojant Iškarpinę galima vilkti elementus tiesiai į iškarpinę. Be to, rodomus elementus galima vilkti tiesiai iš iškarpinės."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Tinkintas naršymo mygtukas"</string>
<string name="keycode" msgid="7335281375728356499">"Klavišo kodas"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Klavišų kodų mygtukais galima pridėti klaviatūros klavišus prie naršymo juostos. Paspaudus jie imituoja pasirinktą klaviatūros klavišą. Pirmiausia reikia pasirinkti mygtuko klavišą su vaizdu, kuris turėtų būti rodomas ant mygtuko."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Klaviatūros mygtuko pasirinkimas"</string>
- <string name="preview" msgid="9077832302472282938">"Peržiūrėti"</string>
+ <string name="icon" msgid="8732339849035837289">"Piktograma"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Nuvilkite, kad pridėtumėte išklotinės elementų"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Vilkite čia, jei norite pašalinti"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redaguoti"</string>
@@ -675,8 +675,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Sumažinti"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Atsisakyti"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefonas kaista"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kairioji pusė"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Dešinioji pusė"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Tinkinti spartųjį klavišą"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Spartusis klavišas"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Paraginti įvesti slaptažodį"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Įspėjimai"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrano kopijos"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Bendrieji pranešimai"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Saugykla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 9911109a597d..ba6ce3c040f0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darba režīms"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakts režīms"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ir atspējoti"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ir iespējoti"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nav nesenu vienumu"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Visi uzdevumi ir notīrīti"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Sadalīt ekrānu augšdaļā"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Sadalīt ekrānu kreisajā pusē"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Sadalīt ekrānu labajā pusē"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Atvienot VPN tīklu"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Jūsu ierīci pārvalda <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> izmanto lietotni <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> jūsu ierīces pārvaldībai."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes, ierīces datus, informāciju par atrašanās vietu."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Uzzināt vairāk"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ir izveidots savienojums ar lietotni <xliff:g id="VPN_APP">%1$s</xliff:g>, kas var pārraudzīt jūsu darbības tīklā, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Atvērt VPN iestatījumus"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administrators ir ieslēdzis tīkla reģistrēšanu, kuru izmanto, lai pārraudzītu datplūsmu jūsu ierīcē.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Jūs piešķīrāt lietotnei atļauju izveidot savienojumu ar VPN tīklu.\n\nŠī lietotne var pārraudzīt jūsu ierīcē un tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrators var pārraudzīt jūsu darbības darba tīklā, tostarp e-pastu, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru.\n\nIr izveidots savienojums arī ar VPN, kurā var pārraudzīt jūsu darbības tīklā."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION">%2$s</xliff:g>, kurā var pārraudzīt jūsu darbības darba tīklā, tostarp e-pastu, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nIr piesaistīta arī lietojumprogramma <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Ierīce būs bloķēta, līdz to manuāli atbloķēsiet."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Saņemiet paziņojumus ātrāk"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Atskaņot skaņas signālu un īslaicīgi parādīt ekrānā"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"paziņojumu vadīklas"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"paziņojumu atlikšanas opcijas"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minūtes"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minūtes"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 stunda"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Neatlikt"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ATSAUKT"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Atlikts: <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Akumulatora lietojums"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumulatora jaudas taupīšanas režīms"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Ieslēgts"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Izslēgts"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigācijas josla"</string>
- <string name="start" msgid="6873794757232879664">"Sākums"</string>
- <string name="center" msgid="4327473927066010960">"Centrs"</string>
- <string name="end" msgid="125797972524818282">"Beigas"</string>
- <string name="space" msgid="804232271282109749">"Atstarpes elements"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Izkārtojums"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Pa kreisi"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Pa labi"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Pogas veids"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(noklusējums)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Starpliktuve"</item>
+ <item msgid="5742013440802239414">"Taustiņu kods"</item>
+ <item msgid="8748101184830239843">"Izvēlnes/tastatūras slēdzis"</item>
+ <item msgid="8175437057325747277">"Neviens"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Sadalīts (noklusējums)"</item>
+ <item msgid="6210279084134579668">"Centrēts"</item>
+ <item msgid="89143234390889289">"Izlīdzināts pa kreisi"</item>
+ <item msgid="7715533883382410603">"Izlīdzināts pa labi"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Izvēlnes/tastatūras slēdzis"</string>
- <string name="select_button" msgid="1597989540662710653">"Pievienojamās pogas atlase"</string>
- <string name="add_button" msgid="4134946063432258161">"Pievienot pogu"</string>
<string name="save" msgid="2311877285724540644">"Saglabāt"</string>
<string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Netika atrasta poga Sākums"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Navigācijai šajā ierīcē ir nepieciešama poga Sākums. Lūdzu, pirms saglabāšanas pievienojiet pogu Sākums."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Pogas platuma pielāgošana"</string>
<string name="clipboard" msgid="1313879395099896312">"Starpliktuve"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Ja ir pieejama starpliktuve, tajā var tieši ievilkt vienumus, kā arī ievietotos vienumus var izvilkt no tās."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Pielāgota navigācijas poga"</string>
<string name="keycode" msgid="7335281375728356499">"Taustiņu kods"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Izmantojot taustiņu koda pogas, navigācijas joslai var pievienot tastatūras taustiņus. Nospiežot taustiņu, tiek imitēta atlasītā tastatūras taustiņa funkcija. Vispirms ir jāatlasa taustiņš attiecīgajai pogai, pēc tam ir jāpievieno uz pogas rādāmais attēls."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Tastatūras pogas atlase"</string>
- <string name="preview" msgid="9077832302472282938">"Priekšskatījums"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Velciet elementus, lai tos pievienotu"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lai noņemtu vienumus, velciet tos šeit."</string>
<string name="qs_edit" msgid="2232596095725105230">"Rediģēt"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizēt"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Noraidīt"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Tālrunis kļūst silts"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Dažas funkcijas ir ierobežotas, kamēr tālrunis mēģina atdzist"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Pa kreisi"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Pa labi"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Pielāgot īsinājumtaustiņu"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Īsinājumtaustiņš"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Pieprasīt paroli"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Brīdinājumi"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrānuzņēmumi"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Vispārīgi ziņojumi"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Krātuve"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 500cb4fe9ce9..5308d657dc17 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим на работа"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноќно светло"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC е оневозможено"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC е овозможено"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Нема неодамнешни ставки"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Исчистивте сѐ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Поделен екран во горниот дел"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Поделен екран на левата страна"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Поделен екран на десната страна"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Наполнета"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Исклучи ВПН"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> управува со уредов."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ја користи <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> за да управува со вашиот уред."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Администраторот може да следи и да управува со: поставки, корпоративен пристап, апликации, податоци за уредот и информации за локација."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Дознајте повеќе"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Поврзани сте на <xliff:g id="VPN_APP">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-сајтовите."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отворете „Поставки за VPN“"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Вашиот администратор вклучил евиденција на мрежата, што подразбира следење на сообраќајот на вашиот уред.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Дозволивте апликацијата да постави поврзување преку ВПН.\n\nАпликацијата може да го следи уредот и активноста на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил.\n\nАдминистратор е во можност да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот.\n\nYИсто така, поврзани сте на VPN којашто може да ја следи вашата активност на мрежата."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"ВПН"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<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="4946600443852045903">"<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_disabled" msgid="7412534203633528135">"Уредот ќе остане заклучен додека рачно не го отклучите"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Добивајте известувања побрзо"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Испушти звук и прикажи го на екранот"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известувања на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"контроли за известувањето"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"опции за одложување на известувањето"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минути"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минути"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 час"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Не одложувај"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ВРАТИ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Одложено за <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Користење батерија"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Штедачот на батерија не е достапен при полнење"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Штедач на батерија"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Вклучено"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Исклучено"</string>
<string name="nav_bar" msgid="1993221402773877607">"Лента за навигација"</string>
- <string name="start" msgid="6873794757232879664">"Почеток"</string>
- <string name="center" msgid="4327473927066010960">"Центар"</string>
- <string name="end" msgid="125797972524818282">"Крај"</string>
- <string name="space" msgid="804232271282109749">"Оддалечувач"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Распоред"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Лево"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Десно"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тип копче"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(стандардно)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Табла со исечоци"</item>
+ <item msgid="5742013440802239414">"Код на копче"</item>
+ <item msgid="8748101184830239843">"Менувач на мени/тастатура"</item>
+ <item msgid="8175437057325747277">"Ништо"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Поделен (стандардно)"</item>
+ <item msgid="6210279084134579668">"Во средина"</item>
+ <item msgid="89143234390889289">"Порамнет налево"</item>
+ <item msgid="7715533883382410603">"Порамнет надесно"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Менување мени/тастатура"</string>
- <string name="select_button" msgid="1597989540662710653">"Изберете копче за додавање"</string>
- <string name="add_button" msgid="4134946063432258161">"Додај копче"</string>
<string name="save" msgid="2311877285724540644">"Зачувај"</string>
<string name="reset" msgid="2448168080964209908">"Ресетирај"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Не е пронајдено копче „Дома“"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Потребно е копче „Дома“ за да може да го движите уредот. Додајте копче „Дома“ пред зачувувањето."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Приспособи ја ширината на копчето"</string>
<string name="clipboard" msgid="1313879395099896312">"Табла со исечоци"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Таблата со исечоци овозможува ставките да се довлечат директно на неа. Исто така, ставките може да се извлечат директно од таблата со исечоци кога таа е присутна."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Приспособено копче за навигација"</string>
<string name="keycode" msgid="7335281375728356499">"Код од тастери"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Копчињата на кодовите од тастери овозможуваат тастерите на тастатурата да се додадат на лентата за навигација. Кога се притиснати тие го поддржуваат избраниот тастер на тастатурата. Прво мора да се избере тастерот за копчето, по што на копчето се прикажува слика."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Изберете копче за тастатура"</string>
- <string name="preview" msgid="9077832302472282938">"Преглед"</string>
+ <string name="icon" msgid="8732339849035837289">"Икона"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Повлечете за додавање плочки"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Повлечете тука за да се отстрани"</string>
<string name="qs_edit" msgid="2232596095725105230">"Уреди"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Минимизирај"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Отфрли"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефонот се загрева"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Некои функции се ограничени додека телефонот се лади"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Лево"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Десно"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Приспособете ја кратенката"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Кратенка"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Побарај лозинка"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Предупредувања"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Слики од екранот"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Општи пораки"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Меморија"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1787d21a8a2d..cf32631a1d35 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -44,7 +44,7 @@
<string name="battery_saver_start_action" msgid="5576697451677486320">"ബാറ്ററി സേവർ ഓണാക്കുക"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ക്രമീകരണം"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"വൈഫൈ"</string>
- <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"സ്‌ക്രീൻ സ്വയമേതിരിക്കുക"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"സ്‌ക്രീൻ സ്വയമേ തിരിക്കുക"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"മ്യൂട്ടുചെയ്യുക"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"യാന്ത്രികം"</string>
<string name="status_bar_settings_notifications" msgid="397146176280905137">"അറിയിപ്പുകൾ"</string>
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"പ്രവർത്തന മോഡ്"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"നൈറ്റ് ലൈറ്റ്"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="recents_empty_message" msgid="808480104164008572">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"നിങ്ങൾ എല്ലാം മായ്ച്ചിരിക്കുന്നു"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ആപ്പ് വിവരം"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"സ്ക്രീൻ മുകളിലേക്ക് സ്പ്ലിറ്റ് ചെയ്യുക"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"സ്ക്രീൻ ഇടതുവശത്തേക്ക് സ്പ്ലിറ്റ് ചെയ്യുക"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"സ്ക്രീൻ വലതുവശത്തേക്ക് പിളർത്തുക"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ചാർജായി"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN വിച്‌ഛേദിക്കുക"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"നിങ്ങളുടെ ഉപകരണം മാനേജുചെയ്യുന്നത് <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ആണ്."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"നിങ്ങളുടെ ഉപകരണം മാനേജുചെയ്യാൻ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ഉപയോഗിക്കുന്നത് <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ആണ്."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ക്രമീകരണങ്ങൾ, കോർപ്പറേറ്റ് ആക്‌സസ്സ്, ആപ്‌സ്, ഉപകരണത്തിന്റെ ഡാറ്റ, ലൊക്കേഷൻ എന്നിവ നിരീക്ഷിക്കാനും നിയന്ത്രിക്കാനും അഡ്‌മിന് കഴിയും."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" 5"</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"കൂടുതലറിയുക"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"നിങ്ങൾ <xliff:g id="VPN_APP">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" 5"</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ക്രമീകരണം തുറക്കുക"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"നിങ്ങളുടെ ഉപകരണത്തിലെ ട്രാഫിക്ക് നിരീക്ഷിക്കുന്ന നെറ്റ്‌വർക്ക് ലോഗിംഗ് അഡ്‌മിൻ ഓണാക്കിയിട്ടുണ്ട്.\n\nകൂടുതൽ ‌വിവരങ്ങൾക്ക് അഡ്‌മിനുമായി‌ ബന്ധപ്പെടുക."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN കണക്ഷൻ സജ്ജീകരിക്കാൻ നിങ്ങൾ ഒരു ആപ്പിന് അനുമതി നൽകി.\n\nഈ ആപ്പിന് നിങ്ങളുടെ ഇമെയിലുകളും ആപ്സും വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെ, ഉപകരണവും നെറ്റ്‌വർക്ക് പ്രവർത്തനവും നിരീക്ഷിക്കാൻ കഴിയും."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവയടങ്ങുന്ന നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ അഡ്‌മിന് കഴിയും.\n\nകൂടുതൽ ‌വിവരങ്ങൾക്ക് അഡ്‌മിനുമായി‌ ബന്ധപ്പെടുക.\n\nനെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി ‌നിരീക്ഷിക്കാൻ സാധിക്കുന്ന ഒരു VPN-ലേക്ക് കൂടി നിങ്ങൾ കണക്റ്റ് ‌ചെയ്യപ്പെട്ടിരിക്കുന്നു."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <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="4946600443852045903">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <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_disabled" msgid="7412534203633528135">"നിങ്ങൾ സ്വമേധയാ അൺലോക്കുചെയ്യുന്നതുവരെ ഉപകരണം ലോക്കുചെയ്‌തതായി തുടരും"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"അറിയിപ്പുകൾ വേഗത്തിൽ സ്വീകരിക്കുക"</string>
@@ -475,10 +461,10 @@
<string name="stream_notification" msgid="2563720670905665031">"അറിയിപ്പ്"</string>
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ബ്ലൂടൂത്ത്"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ഡ്യുവൽ മൾട്ടി റ്റോൺ ഫ്രീക്വൻസി"</string>
- <string name="stream_accessibility" msgid="301136219144385106">"പ്രവേശനക്ഷമത"</string>
+ <string name="stream_accessibility" msgid="301136219144385106">"ഉപയോഗസഹായി"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
- <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
- <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
+ <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
+ <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
<string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s വോളിയം നിയന്ത്രണങ്ങൾ കാണിച്ചിരിക്കുന്നു. ഡിസ്മിസ് ചെയ്യുന്നതിന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്യുക."</string>
<string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"വോളിയം നിയന്ത്രണങ്ങൾ മറച്ചിരിക്കുന്നു"</string>
<string name="system_ui_tuner" msgid="708224127392452018">"സിസ്റ്റം UI ട്യൂണർ"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ശബ്ദമുണ്ടാക്കുക, സ്ക്രീനിൽ കാണിക്കുക"</string>
<string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
<string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"അറിയിപ്പ് സ്‌നൂസ് ഓപ്ഷനുകൾ"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 മിനിറ്റ്"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 മിനിറ്റ്"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"ഒരു മണിക്കൂർ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"സ്‌നൂസ് ‌ചെയ്യരുത്"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"പഴയപടിയാക്കുക"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> സമയത്തേക്ക് സ്‌നൂസ് ‌ചെയ്‌തു"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ബാറ്ററി ഉപയോഗം"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി സേവർ ലഭ്യമല്ല"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ബാറ്ററി സേവർ"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ഓൺ"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ഓഫ്"</string>
<string name="nav_bar" msgid="1993221402773877607">"നാവിഗേഷൻ ബാർ"</string>
- <string name="start" msgid="6873794757232879664">"ആരംഭിക്കൂ"</string>
- <string name="center" msgid="4327473927066010960">"മധ്യം"</string>
- <string name="end" msgid="125797972524818282">"അവസാനിപ്പിക്കുക"</string>
- <string name="space" msgid="804232271282109749">"സ്പേസർ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ലേ‌ഔട്ട്"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ഇടത്"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"വലത്"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ബട്ടൺ തരം"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ഡിഫോൾട്ട്)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ക്ലിപ്പ്ബോർഡ്"</item>
+ <item msgid="5742013440802239414">"കീകോഡ്"</item>
+ <item msgid="8748101184830239843">"മെനു / കീബോർഡ് സ്വിച്ചർ"</item>
+ <item msgid="8175437057325747277">"ഒന്നുമില്ല"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"വിഭജിച്ചത് (ഡിഫോൾട്ട്)"</item>
+ <item msgid="6210279084134579668">"മധ്യഭാഗത്ത് വിന്യസിച്ചത്"</item>
+ <item msgid="89143234390889289">"ഇടതുവശത്ത് വിന്യസിച്ചത്"</item>
+ <item msgid="7715533883382410603">"വലതുവശത്ത് വിന്യസിച്ചത്"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"മെനു / കീബോർഡ് സ്വിച്ചർ"</string>
- <string name="select_button" msgid="1597989540662710653">"ചേർക്കാൻ, ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
- <string name="add_button" msgid="4134946063432258161">"ബട്ടൺ ചേർക്കുക"</string>
<string name="save" msgid="2311877285724540644">"സംരക്ഷിക്കുക"</string>
<string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ഒരു ഹോം ബട്ടണും കണ്ടെത്തിയില്ല"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ഈ ഉപകരണം നാവിഗേറ്റ് ചെയ്യുന്നതിന് ഒരു ഹോം ബട്ടൺ ആവശ്യമാണ്, സംരക്ഷിക്കുന്നതിന് മുമ്പ് ഒരു ഹോം ബട്ടൺ ചേർക്കുക."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ബട്ടൺ വീതി ക്രമീകരിക്കുക"</string>
<string name="clipboard" msgid="1313879395099896312">"ക്ലിപ്പ്ബോർഡ്"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ഇനങ്ങളെ ക്ലിപ്പ്‌ബോർഡിലേക്ക് നേരിട്ട് വലിച്ചിടാൻ ക്ലിപ്പ്‌ബോർഡ് അനുവദിക്കുന്നു. ഇനങ്ങളെ ക്ലിപ്പ്‌ബോർഡിന് പുറത്തേക്ക് നേരിട്ട് വലിച്ചിടുകയുമാകാം."</string>
<string name="accessibility_key" msgid="5701989859305675896">"ഇഷ്ടാനുസൃത നാവിഗേഷൻ ബട്ടൺ"</string>
<string name="keycode" msgid="7335281375728356499">"കീകോഡ്"</string>
- <string name="keycode_description" msgid="1403795192716828949">"നാവിഗേഷൻ ബാറിലേക്ക് കീബോർഡ് കീകൾ ചേർക്കുന്നതിനെ കീകോഡ് ബട്ടണുകൾ അനുവദിക്കുന്നു. അമർത്തുമ്പോൾ, തിരഞ്ഞെടുത്ത കീയെ അവ അനുകരിക്കുന്നു. ആദ്യം ബട്ടണിനായി കീ തിരഞ്ഞെടുക്കണം, തുടർന്ന് ബട്ടണിൽ കാണിക്കാനുള്ള ചിത്രം തിരഞ്ഞെടുക്കണം."</string>
- <string name="select_keycode" msgid="7413765103381924584">"കീബോർഡ് ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
- <string name="preview" msgid="9077832302472282938">"പ്രിവ്യു നടത്തുക"</string>
+ <string name="icon" msgid="8732339849035837289">"ഐക്കൺ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
<string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
@@ -671,8 +671,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ചെറുതാക്കുക‍"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"നിരസിക്കുക"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ഫോൺ ചൂടായിക്കൊണ്ടിരിക്കുന്നു"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ഇടത്"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"വലത്"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"കുറുക്കുവഴി ഇഷ്‌ടാനുസൃതമാക്കുക"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"കുറുക്കുവഴി"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"പാസ്‌വേഡ് ആവശ്യപ്പെടുക"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"അലേർട്ടുകൾ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"സ്‌ക്രീൻഷോട്ടുകൾ"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"സ്റ്റോറേജ്"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b8b92220535b..336429f159e5 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -319,12 +319,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ажлын горим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Шөнийн гэрэл"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC-г цуцалсан"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC-г идэвхжүүлсэн"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Сүүлийн үеийн зүйл байхгүй"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Та бүгдийг нь устгасан"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
@@ -338,16 +335,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Дэлгэцийг дээд хэсэгт хуваах"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Дэлгэцийг зүүн хэсэгт хуваах"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Дэлгэцийг баруун хэсэгт хуваах"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
@@ -428,24 +418,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN таслах"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Таны төхөөрөмжийг <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> удирддаг."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> таны төхөөрөмжийг удирдахын тулд <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>-г ашигладаг."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Таны админ тохиргоо, байгууллагын хандалт, апп, төхөөрөмжтэй холбоотой өгөгдөл болон таны төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Дэлгэрэнгүй үзэх"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN тохиргоог нээх"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вэбсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<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="4946600443852045903">"Таны ажлын профайлыг <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_disabled" msgid="7412534203633528135">"Таныг гараар онгойлгох хүртэл төхөөрөмж түгжээтэй байх болно"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Мэдэгдлийг хурдан авах"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Дуу гаргаж, дэлгэцэд гэнэт гаргах"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
<string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> мэдэгдлийн хяналт"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"мэдэгдлийн удирдлага"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"мэдэгдэл түр хойшлуулагчийн сонголт"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минут"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минут"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 цаг"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Түр хойшлуулахгүй"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"БУЦААХ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>-д түр хойшлуулсан"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Тэжээл ашиглалт"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Цэнэглэх үед тэжээл хэмнэгч ажиллахгүй"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Тэжээл хэмнэгч"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Идэвхтэй"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Идэвхгүй"</string>
<string name="nav_bar" msgid="1993221402773877607">"Навигацийн самбар"</string>
- <string name="start" msgid="6873794757232879664">"Эхлэх"</string>
- <string name="center" msgid="4327473927066010960">"Гол хэсэг"</string>
- <string name="end" msgid="125797972524818282">"Төгсгөл"</string>
- <string name="space" msgid="804232271282109749">"Зай авагч"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Бүдүүвч"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Зүүн"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Баруун"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Товчлуурын төрөл"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(өгөгдмөл)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Түр санах ой"</item>
+ <item msgid="5742013440802239414">"Түлхүүр код"</item>
+ <item msgid="8748101184830239843">"Цэс / Гар солигч"</item>
+ <item msgid="8175437057325747277">"Хоосон"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Хуваагдсан (өгөгдмөл)"</item>
+ <item msgid="6210279084134579668">"Голлосон"</item>
+ <item msgid="89143234390889289">"Зүүн зэрэгцүүлсэн"</item>
+ <item msgid="7715533883382410603">"Баруун зэрэгцүүлсэн"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Цэс / Гар солигч"</string>
- <string name="select_button" msgid="1597989540662710653">"Нэмэх товчлуурыг сонгох"</string>
- <string name="add_button" msgid="4134946063432258161">"Нэмэх товчлуур"</string>
<string name="save" msgid="2311877285724540644">"Хадгалах"</string>
<string name="reset" msgid="2448168080964209908">"Бүгдийг цэвэрлэх"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Нүүр хуудас товчлуур байхгүй"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Энэ төхөөрөмжийг удирдахын тулд нүүр хуудас товчлуур шаардлагатай байна. Хадгалахын өмнө нүүр хуудасны товчлуур нэмнэ үү."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Товчлуурын өргөнг тохируулах"</string>
<string name="clipboard" msgid="1313879395099896312">"Түр санах ой"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Түр санах ой нь аливаа зүйлийг түр санах ойд зөөх боломжийг олгодог. Мөн тухайн зүйлсийг түр санах ойгоос зөөх боломжтой."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Навигацийн товчлуурыг өөрчлөх"</string>
<string name="keycode" msgid="7335281375728356499">"Түлхүүр код"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Түлхүүр код товчлуур нь гарын түлхүүрийг навигацийн самбарт нэмэхийг зөвшөөрдөг. Дарсан үед гарын сонгосон товчлуурыг дуурайдаг. Эхлээд товчлуурын түлхүүрийг сонгох шаардлагатай бөгөөд дараа нь зохих зургийг сонгоно."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Гарын товчлуур сонгох"</string>
- <string name="preview" msgid="9077832302472282938">"Урьдчилж харах"</string>
+ <string name="icon" msgid="8732339849035837289">"Дүрс тэмдэг"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Дөрвөлж нэмэхийн тулд чирнэ үү"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Устгахын тулд энд зөөнө үү"</string>
<string name="qs_edit" msgid="2232596095725105230">"Засах"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Багасгах"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Хаах"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Утас халж эхэлж байна"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Таны утас хөрж байх зуур зарим онцлогийг хязгаарласан"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Зүүн"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Баруун"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Товчлолыг өөрчлөх"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Товчлол"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Нууц үг шаардах"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Сануулга"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Дэлгэцийн зураг дарах"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Энгийн зурвас"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Хадгалах сан"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 4c8d59c5fe59..7b09c9d44241 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रीचा प्रकाश"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC अक्षम केले आहे"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC सक्षम केले आहे"</string>
<string name="recents_empty_message" msgid="808480104164008572">"अलीकडील कोणतेही आयटम नाहीत"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपण सर्वकाही साफ केले"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग माहिती"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"स्क्रीन शीर्षस्थानी विभाजित करा"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"स्क्रीन डावीकडे विभाजित करा"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"स्क्रीन उजवीकडे विभाजित करा"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज झाली"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN डिस्कनेक्ट करा"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"आपले डिव्हाइस <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ने व्यवस्थापित केले आहे."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"आपले डिव्हाइस व्यवस्थापित करण्यासाठी <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> वापरते."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"आपला प्रशासक सेटिंग्ज, कॉर्पोरेट प्रवेश, अॅप्स, आपल्या डिव्हाइशी संबंधित डेटा आणि डिव्हाइसच्या स्थान माहितीचे निरीक्षण आणि व्यवस्थापन करू शकतो."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"अधिक जाणून घ्या"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"आपण <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सेटिंग्ज उघडा"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"आपण VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, आपल्या डिव्हाइस आणि नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"आपले कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nआपला प्रशासक ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nआपण VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क क्रियाकलापाचे निरीक्षण करू शकते."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"आपले कार्य प्रोफाइल <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="4946600443852045903">"आपले कार्य प्रोफाईल <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_disabled" msgid="7412534203633528135">"आपण व्यक्तिचलितपणे अनलॉक करेपर्यंत डिव्हाइस लॉक केलेले राहील"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"सूचना अधिक जलद मिळवा"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ध्वनी करा आणि स्क्रीनवर पॉप करा"</string>
<string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
<string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> सूचना नियंत्रणे"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना नियंत्रणे"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना स्नूझ पर्याय"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 मिनिटे"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 मिनिटे"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 तास"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"स्नूझ करू नका"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"पूर्ववत करा"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> साठी स्नूझ करा"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"बॅटरी वापर"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज करताना बॅटरी बचतकर्ता उपलब्ध नाही"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"बॅटरी बचतकर्ता"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
<string name="nav_bar" msgid="1993221402773877607">"नॅव्हिगेशन बार"</string>
- <string name="start" msgid="6873794757232879664">"प्रारंभ"</string>
- <string name="center" msgid="4327473927066010960">"मध्यवर्ती"</string>
- <string name="end" msgid="125797972524818282">"शेवटच्या"</string>
- <string name="space" msgid="804232271282109749">"स्पेसर"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"डावा"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"उजवा"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"बटणाचा प्रकार"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(डीफॉल्ट)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"क्लिपबोर्ड"</item>
+ <item msgid="5742013440802239414">"कीकोड"</item>
+ <item msgid="8748101184830239843">"मेनू / कीबोर्ड स्विचर"</item>
+ <item msgid="8175437057325747277">"काहीही नाही"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"विभाजित (डीफॉल्ट)"</item>
+ <item msgid="6210279084134579668">"मध्यवर्ती"</item>
+ <item msgid="89143234390889289">"डावे-संरेखित"</item>
+ <item msgid="7715533883382410603">"उजवे-संरेखित"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"मेनू / कीबोर्ड स्विचर"</string>
- <string name="select_button" msgid="1597989540662710653">"जोडण्यासाठी बटण निवडा"</string>
- <string name="add_button" msgid="4134946063432258161">"बटण जोडा"</string>
<string name="save" msgid="2311877285724540644">"जतन करा"</string>
<string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
- <string name="no_home_title" msgid="1563808595146071549">"मुख्यपृष्ठ बटण आढळले नाही"</string>
- <string name="no_home_message" msgid="5408485011659260911">"हे डिव्हाइस नेव्हिगेट करण्यासाठी मुख्यपृष्ठ बटण सक्षम असणे आवश्यक आहे. कृपया जतन करण्यापूर्वी एक मुख्यपृष्ठ बटण जोडा."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"बटण रूंदी समायोजित करा"</string>
<string name="clipboard" msgid="1313879395099896312">"क्लिपबोर्ड"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"थेट क्लिपबोर्डवर ड्रॅग केले जाण्यासाठी क्लिपबोर्ड आयटमना अनुमती देते. क्लिपबोर्डवर आयटम असताना ते थेट क्लिपबोर्ड बाहेर देखील ड्रॅग केले जाऊ शकतात."</string>
<string name="accessibility_key" msgid="5701989859305675896">"सानुकूल नेव्हिगेशन बटण"</string>
<string name="keycode" msgid="7335281375728356499">"कीकोड"</string>
- <string name="keycode_description" msgid="1403795192716828949">"कीकोड बटणे नेव्हिगेशन बारमध्ये कीबोर्ड की ना जोडण्यासाठी अनुमती देतात. दाबल्यानंतर ते निवडलेल्या कीबोर्ड की चे अनुकरण करतात. बटणासाठी प्रथम की त्यानंतर बटणावर दर्शविली जाण्यासाठी प्रतिमा निवडणे आवश्यक आहे."</string>
- <string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटण निवडा"</string>
- <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
+ <string name="icon" msgid="8732339849035837289">"चिन्ह"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
<string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
@@ -671,8 +671,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"लहान करा"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"डिसमिस करा"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"फोन ऊष्ण होत आहे"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"फोन थंड होत असताना काही वैशिष्‍ट्ये मर्यादित असतात"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"आपला फोन स्वयंचलितपणे थंड होईल. आपण अद्यापही आपला फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nआपला फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"डावा"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"उजवा"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"शॉर्टकट सानुकूल करा"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"शॉर्टकट"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"संकेतशब्दासाठी संकेत"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचना"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रीनशॉट"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"संचय"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6e29cc96eeff..9ba75b224b4f 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mod kerja"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC dilumpuhkan"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC didayakan"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Tiada item terbaharu"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda telah mengetepikan semua item"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Pisahkan skrin ke atas"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Pisahkan skrin ke kiri"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Pisahkan skrin ke kanan"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Putuskan sambungan VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Peranti anda diurus oleh <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengurus peranti anda."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Pentadbir anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti dan maklumat lokasi peranti anda."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ketahui lebih lanjut"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Anda disambungkan ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buka Tetapan VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Pentadbir anda telah menghidupkan pengelogan rangkaian yang memantau trafik pada peranti anda.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Anda memberikan kebenaran kepada apl untuk menyediakan sambungan VPN.\n\nApl ini boleh memantau aktiviti peranti dan rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau aktiviti rangkaian, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda.\n\nAnda juga disambungkan ke VPN, yang boleh memantau aktiviti rangkaian."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil disambungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut disambungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Berbunyi dan paparkan pada skrin"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kawalan pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kawalan pemberitahuan"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"pilihan tunda pemberitahuan"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minit"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minit"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 jam"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Jangan tunda"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"BUAT ASAL"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Ditunda selama <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Penggunaan bateri"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penjimat Bateri tidak tersedia semasa mengecas"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Penjimat Bateri"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Hidup"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Mati"</string>
<string name="nav_bar" msgid="1993221402773877607">"Bar navigasi"</string>
- <string name="start" msgid="6873794757232879664">"Mula"</string>
- <string name="center" msgid="4327473927066010960">"Tengah"</string>
- <string name="end" msgid="125797972524818282">"Tamat"</string>
- <string name="space" msgid="804232271282109749">"Peruang"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Reka letak"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kiri"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Kanan"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Jenis butang"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(lalai)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Papan Keratan"</item>
+ <item msgid="5742013440802239414">"Kod Kunci"</item>
+ <item msgid="8748101184830239843">"Penukar Menu/Papan Kekunci"</item>
+ <item msgid="8175437057325747277">"Tiada"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Terbahagi (lalai)"</item>
+ <item msgid="6210279084134579668">"Ditengahkan"</item>
+ <item msgid="89143234390889289">"Jajar kiri"</item>
+ <item msgid="7715533883382410603">"Jajar kanan"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Penukar Menu/Papan Kekunci"</string>
- <string name="select_button" msgid="1597989540662710653">"Pilih butang untuk ditambahkan"</string>
- <string name="add_button" msgid="4134946063432258161">"Tambahkan butang"</string>
<string name="save" msgid="2311877285724540644">"Simpan"</string>
<string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Butang laman utama tdk ditemui"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Butang laman utama diperlukan untuk menavigasi peranti ini. Sila tambahkan butang laman utama sebelum menyimpan."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Laraskan lebar butang"</string>
<string name="clipboard" msgid="1313879395099896312">"Papan Keratan"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Papan Keratan membolehkan item diseret secara langsung ke papan keratan. Jika terdapat item pada papan keratan, item itu boleh diseret keluar daripada papan keratan juga."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Butang navigasi tersuai"</string>
<string name="keycode" msgid="7335281375728356499">"Kod Kunci"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Butang Kod Kunci membolehkan kunci papan kekunci ditambahkan pada Bar Navigasi. Apabila ditekan, butang ini meniru kunci papan kekunci yang dipilih. Mula-mula, kunci mesti dipilih untuk butang tersebut, diikuti dengan imej yang hendak dipaparkan pada butang."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Pilih Butang Papan Kekunci"</string>
- <string name="preview" msgid="9077832302472282938">"Pratonton"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan jubin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Seret ke sini untuk mengalih keluar"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimumkan"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ketepikan"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon semakin panas"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Sesetengah ciri adalah terhad semasa telefon menyejuk"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kiri"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Kanan"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Sesuaikan pintasan"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Pintasan"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Gesa untuk kata laluan"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Makluman"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Tangkapan skrin"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mesej Am"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Storan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index a439a010e7bc..32ff25dcbdfa 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"အလုပ် မုဒ်"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ညအလင်းရောင်"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ကို ပိတ်ထားသည်"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ကို ဖွင့်ထားသည်"</string>
<string name="recents_empty_message" msgid="808480104164008572">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"သင်အားလုံးကို ရှင်းလင်းပြီးပါပြီ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"အပလီကေးရှင်းအင်ဖို"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"မျက်နှာပြင်ကို အပေါ်သို့ ခွဲရန်"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"မျက်နှာပြင်ကို ဘယ်ဘက်သို့ ခွဲရန်"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"မျက်နှာပြင်ကို ညာဘက်သို့ ခွဲရန်"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"အားသွင်းပြီး"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ကို အဆက်ဖြတ်ရန်"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"သင့်စက်ပစ္စည်းကို <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> က စီမံခန့်ခွဲထားပါသည်။"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> သည် သင့်စက်ပစ္စည်းကို စီမံခန့်ခွဲရန် <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ကို အသုံးပြုပါသည်။"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"စီမံသူသည် ဆက်တင်၊ ကော်ပိုရိတ်သုံးခွင့်၊ အက်ပ်၊ စက်ပစ္စည်းနှင့်ဆိုင်သောဒေတာနှင့် ၎င်း၏တည်နေရာအချက်အလက်ကိုစောင့်ကြည့်စီမံနိုင်ပါသည်။"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ပိုမိုလေ့လာရန်"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="VPN_APP">%1$s</xliff:g> သို့ သင်သည် ချိတ်ဆက်ထားပါသည်။"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN ဆက်တင်များ"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"သင့်စီမံခန့်ခွဲသူသည် စက်ပစ္စည်းပေါ်ရှိ ဒေတာအသွားအလာကို စောင့်ကြည့်နိုင်သည့် ကွန်ရက်အတွက် မှတ်တမ်းတင်ခြင်းကို ဖွင့်ထားပါသည်။\n\nနောက်ထပ် အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN ချိတ်ဆက်မှုပြုလုပ်ရန် အက်ပ်ကို သင်ခွင့်ပြုလိုက်သည်။ \n\n ဤအက်ပ်သည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> က စီမံခန့်ခွဲထားပါသည်။\n\nသင့်စီမံခန့်ခွဲသူသည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်ပါသည်။\n\nနောက်ထပ် အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။\n\nသင်သည် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည့် VPN သို့လည်း ချိတ်ဆက်ထားပါသေးသည်။"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးများ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"သင်သည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကိုယ်ရေးကိုယ်တာ ကွန်ရက်အသုံးပြုမှုကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"သင့်အလုပ်ပရိုဖိုင်ကို <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="4946600443852045903">"သင့်အလုပ် ပရိုဖိုင်ကို <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_disabled" msgid="7412534203633528135">"သင်က လက်ဖြင့် သော့မဖွင့်မချင်း ကိရိယာမှာ သော့ပိတ်လျက် ရှိနေမည်"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"အကြောင်းကြားချက်များ မြန်မြန်ရရန်"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"အသံဖွင့်၍ မျက်နှာပြင်ပေါ်တွင် ပြပါ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
<string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"အကြောင်းကြားချက်များကို ဆိုင်းငံ့ရန် ရွေးချယ်စရာများ"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"၁၅ မိနစ်"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"၃၀ မိနစ်"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"၁ နာရီ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ဆိုင်းငံ့ခြင်း မပြုလုပ်ပါနှင့်"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"တစ်ဆင့် နောက်ပြန်ပြန်ပါ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ဆိုင်းငံ့ရန်"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ဘက်ထရီ အသုံးပြုမှု"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"အားသွင်းနေချိန်မှာ Battery Saver ကို သုံးမရပါ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ဖွင့်ပါ"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ပိတ်ပါ"</string>
<string name="nav_bar" msgid="1993221402773877607">"ရွှေ့လျားရန်ဘားတန်း"</string>
- <string name="start" msgid="6873794757232879664">"စတင်ပါ"</string>
- <string name="center" msgid="4327473927066010960">"ဌာန"</string>
- <string name="end" msgid="125797972524818282">"ပြီးပါပြီ"</string>
- <string name="space" msgid="804232271282109749">"နေရာလွတ်ခြားစနစ်"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"အပြင်အဆင်"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ဘယ်"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ညာ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ခလုတ်အမျိုးအစား"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(မူရင်း)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ကလစ်ဘုတ်"</item>
+ <item msgid="5742013440802239414">"ကီးကုဒ်"</item>
+ <item msgid="8748101184830239843">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</item>
+ <item msgid="8175437057325747277">"တစ်ခုမျှမရှိ"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"ခွဲခြားထားသော (မူရင်း)"</item>
+ <item msgid="6210279084134579668">"အလယ်ဗဟိုပြုထားသော"</item>
+ <item msgid="89143234390889289">"ဘယ်ဘက်ကပ်ထားသော"</item>
+ <item msgid="7715533883382410603">"ညာဘက်ကပ်ထားသော"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
- <string name="select_button" msgid="1597989540662710653">"ပေါင်းထည့်ရန် ခလုတ်ကိုရွေးပါ"</string>
- <string name="add_button" msgid="4134946063432258161">"ခလုတ်ပေါင်းထည့်ပါ"</string>
<string name="save" msgid="2311877285724540644">"သိမ်းရန်"</string>
<string name="reset" msgid="2448168080964209908">"ပြန်လည်သတ်မှတ်ရန်"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ပင်မခလုတ်မတွေ့ပါ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ဤစက်ပစ္စည်းကိုရွှေ့လျားနိုင်ရန် ပင်မခလုတ် လိုအပ်ပါသည်။ မသိမ်းဆည်းမီ ပင်မခလုတ်ကို ပေါင်းထည့်ပါ။"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ခလုတ်အလျားကို ချိန်ညှိပါ"</string>
<string name="clipboard" msgid="1313879395099896312">"ကလစ်ဘုတ်"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ကလစ်ဘုတ်သည် အရာဝတ္တုများကို ကလစ်ဘုတ်သို့တိုက်ရိုက် ဆွဲသွင်းရန်ခွင့်ပြုပါသည်။ အရာဝတ္တုများရှိနေလျှင်လည်း ကလစ်ဘုတ်၏အပြင်သို့ ၎င်းတို့ကိုတိုက်ရိုက် ဆွဲထုတ်နိုင်သည်။"</string>
<string name="accessibility_key" msgid="5701989859305675896">"စိတ်ကြိုက်ရွှေ့လျားရန် ခလုတ်"</string>
<string name="keycode" msgid="7335281375728356499">"ကီးကုဒ်"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ကီးကုဒ်ခလုတ်များသည် ကီးဘုတ်ခလုတ်များကို ရွှေ့လျားရန်ဘားတန်းသို့ ပေါင်းထည့်ရန်ခွင့်ပြုသည်။ နှိပ်လိုက်လျှင် ၎င်းသည် ရွေးချယ်ထားသည့် ကီးဘုတ်ခလုတ်အတိုင်း လုပ်ဆောင်ပါသည်။ ပထမဦးစွာ ခလုတ်အတွက် ကီးကိုရွေးချယ်ပြီး ခလုတ်ပေါ်တွင် ပြမည့်ပုံကို ဆက်လက်ရွေးချယ်ရပါမည်။"</string>
- <string name="select_keycode" msgid="7413765103381924584">"ကီးဘုတ်ခလုတ်ကို ရွေးချယ်ပါ"</string>
- <string name="preview" msgid="9077832302472282938">"အစမ်းကြည့်ပါ"</string>
+ <string name="icon" msgid="8732339849035837289">"သင်္ကေတ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"အချပ်များကိုထည့်ရန် ဖိဆွဲပါ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ဖယ်ရှားရန် ဤနေရာသို့ဖိဆွဲပါ"</string>
<string name="qs_edit" msgid="2232596095725105230">"တည်းဖြတ်ပါ"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ချုံ့ရန်"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"ပယ်ရန်"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ဖုန်း ပူနွေးလာပါပြီ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ဘယ်"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ညာ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ဖြတ်လမ်းလင့်ခ်ကို စိတ်ကြိုက်ပြင်ဆင်ရန်"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ဖြတ်လမ်းလင့်ခ်"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"စကားဝှက်ကို မေးရန်"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"သတိပေးချက်များ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"မျက်နှာပြင်ဓာတ်ပုံများ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"အထွေထွေ မက်ဆေ့ဂျ်များ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"သိုလှောင်မှုများ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index d95dd29cb5a7..66245833a2fa 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeidsmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattlys"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC er slått av"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC er slått på"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ingen nylige elementer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har fjernet alt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delt skjerm øverst"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delt skjerm til venstre"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delt skjerm til høyre"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Koble fra VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Enheten din administreres av <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> bruker <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til å administrere enheten din."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data som er tilknyttet denne enheten, og enhetens posisjonsinformasjon."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Finn ut mer"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Enheten er koblet til <xliff:g id="VPN_APP">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Åpne VPN-innstillingene"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratoren din har slått på loggføring av nettverk, som overvåker trafikken på enheten din.\n\nKontakt administratoren for mer informasjon."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Du ga en app tillatelse til å konfigurere en VPN-tilkobling.\n\nDenne appen kan overvåke enheten og nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nKontakt administratoren for mer informasjon.\n\nDu er også tilkoblet en VPN som kan overvåke nettverksaktiviteten din."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-poster, apper og nettsteder.\n\nKontakt administratoren din for mer informasjon."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten forblir låst til du låser den opp manuelt"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Motta varsler raskere"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Lag lyd og vis i forgrunnen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Varselinnstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"varselinnstillinger"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"slumrealternativer for varsler"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutter"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutter"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 time"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ikke slumre"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANGRE"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Slumrer i <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteribruk"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparing er ikke tilgjengelig under lading"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparing"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"På"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Av"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigasjonsrad"</string>
- <string name="start" msgid="6873794757232879664">"Start"</string>
- <string name="center" msgid="4327473927066010960">"Midtstilt"</string>
- <string name="end" msgid="125797972524818282">"Slutt"</string>
- <string name="space" msgid="804232271282109749">"Mellomrom"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Oppsett"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Venstre"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Høyre"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Knappetype"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(standard)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Utklippstavle"</item>
+ <item msgid="5742013440802239414">"Nøkkelkode"</item>
+ <item msgid="8748101184830239843">"Bytteknapp for meny/tastatur"</item>
+ <item msgid="8175437057325747277">"Ingen"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Delt (standardt)"</item>
+ <item msgid="6210279084134579668">"Midtstilt"</item>
+ <item msgid="89143234390889289">"Venstrejustert"</item>
+ <item msgid="7715533883382410603">"Høyrejustert"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Bytteknapp for meny/tastatur"</string>
- <string name="select_button" msgid="1597989540662710653">"Velg en knapp du vil legge til"</string>
- <string name="add_button" msgid="4134946063432258161">"Legg til knapp"</string>
<string name="save" msgid="2311877285724540644">"Lagre"</string>
<string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Fant ingen startsideknapp"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Det kreves en startsideknapp for å kunne navigere på denne enheten. Legg til en startsideknapp før du lagrer."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Juster bredden på knappen"</string>
<string name="clipboard" msgid="1313879395099896312">"Utklippstavle"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Med Clipboard-funksjonen kan elementer dras direkte til utklippstavlen. Hvis det finnes elementer på utklippstavlen, kan de også dras ut derfra."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Spesialtilpasset navigasjonsknapp"</string>
<string name="keycode" msgid="7335281375728356499">"Nøkkelkode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Du kan bruke nøkkelkodeknapper for å legge tastaturtaster direkte på navigasjonsraden. Når du trykker på disse knappene, fungerer de på samme måte som de valgte tastaturtastene. Du må først velge hvilken tast hver knapp skal fungere som, og deretter et bilde som vises på knappen."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Velg tastaturtast"</string>
- <string name="preview" msgid="9077832302472282938">"Forhåndsvisning"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dra for å legge til fliser"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dra hit for å fjerne"</string>
<string name="qs_edit" msgid="2232596095725105230">"Endre"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Avvis"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefonen begynner å bli varm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Enkelte funksjoner er begrenset mens telefonen kjøles ned"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Venstre"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Høyre"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Tilpass snarvei"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Snarvei"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Påminnelse for passord"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Varsler"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjermdumper"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meldinger"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 296d934b3b88..ee0499280c5a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रिको प्रकाश"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC लाई असक्षम पारिएको छ"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC लाई सक्षम पारिएको छ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"हालका कुनै पनि वस्तुहरू छैनन्"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"तपाईँले सबै कुरा खाली गर्नुभएको छ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग जानकारी"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"आफू अनुकूल विभाजन गर्नुहोस्"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"विभाजित-स्क्रिनलाई शीर्ष स्थानमा राख्नुहोस्‌"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"विभाजित-स्क्रिनलाई बायाँतर्फ राख्नुहोस्‌"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"विभाजित-स्क्रिनलाई दायाँतर्फ राख्नुहोस्‌"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज भयो"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"विच्छेद VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"तपाईंको यन्त्र <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> द्वारा व्यवस्थापन गरिएको छ।"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ले तपाईंको यन्त्रको व्यवस्थापन गर्न <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> को प्रयोग गर्दछ।"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"तपाईँको प्रशासकले सेटिङहरू, संस्थागत पहुँच, अनुप्रयोग, तपाईँको यन्त्रसँग सम्बन्धित डेटा र तपाईँको यन्त्रको स्थान सम्बन्धी जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्नुहुन्छ।"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"थप जान्नुहोस्"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"तपाईं <xliff:g id="VPN_APP">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायत तपाईंको नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सम्बन्धी सेटिङहरू खोल्नुहोस्"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"तपाईँको प्रशासकले तपाईँको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्कको लगिङलाई सक्रिय पार्नुभएको छ।\n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"तपाईँले VPN जडान गर्न अनुप्रयोगलाई अनुमति दिनुभयो।\n\nयो अनुप्रयोगले तपाईँका यन्त्र र नेटवर्क गतिविधि लगायत इमेल, अनुप्रयोग र वेबसाइटहरू अनुगमन गर्न सक्छ।"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> ले व्यवस्थापन गर्दछ।\n\nतपाईँको प्रशासकले तपाईँको इमेल, अनुप्रयोग र वेबसाइट सहित नेटवर्कमा तपाईँको गतिविधिको अनुगमन गर्न सक्नुहुन्छ। \n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।\n\n तपाईँ एउटा VPN मा जडित हुनुहुन्छ। यस VPN ले नेटवर्कमा तपाईँको गतिविधिको अनुगमन गर्न सक्छ।"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँका नेटवर्क गतिविधिको अनुगमन गर्न सक्छ।"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायतको तपाईंको व्यक्तिगत नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"तपाईँको कार्य प्रोफाइल <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="4946600443852045903">"तपाईँको कार्य प्रोफाइल <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_disabled" msgid="7412534203633528135">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"आवाज निकाल्ने र स्क्रिनमा पपअप देखाउने"</string>
<string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
<string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचनाका लागि नियन्त्रणहरू"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना सम्बन्धी नियन्त्रणहरू"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना स्नुज गर्ने विकल्पहरू"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"१५ मिनेट"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"३० मिनेट"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"१ घण्टा"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"स्नुज नगर्नुहोस्"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"अनडू गर्नुहोस्"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> का लागि स्नुज गरियो"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ब्याट्री उपयोग"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज गर्ने समयमा ब्याट्री सेभर उपलब्ध छैन"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ब्याट्री सेभर"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"सक्रिय गर्नुहोस्"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"निष्क्रिय"</string>
<string name="nav_bar" msgid="1993221402773877607">"नेभिगेशन पट्टी"</string>
- <string name="start" msgid="6873794757232879664">"सुरु गर्नुहोस्"</string>
- <string name="center" msgid="4327473927066010960">"केन्द्र"</string>
- <string name="end" msgid="125797972524818282">"अन्त्य गर्नुहोस्"</string>
- <string name="space" msgid="804232271282109749">"स्पेसर"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"बायाँ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"दायाँ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"बटनको प्रकार"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(पूर्वनिर्धारित)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"क्लिपबोर्ड"</item>
+ <item msgid="5742013440802239414">"किकोड"</item>
+ <item msgid="8748101184830239843">"मेनु / किबोर्ड परिवर्तक"</item>
+ <item msgid="8175437057325747277">"कुनै पनि होइन"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"विभाजित (पूर्वनिर्धारित)"</item>
+ <item msgid="6210279084134579668">"मध्य भागमा"</item>
+ <item msgid="89143234390889289">"बायाँतिर पङ्क्तिबद्ध"</item>
+ <item msgid="7715533883382410603">"दायाँतिर पङ्क्तिबद्ध"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"मेनु / किबोर्ड स्विचर"</string>
- <string name="select_button" msgid="1597989540662710653">"थप्नका लागि बटन चयन गर्नुहोस्"</string>
- <string name="add_button" msgid="4134946063432258161">"बटन थप्नुहोस्"</string>
<string name="save" msgid="2311877285724540644">"सुरक्षित गर्नुहोस्"</string>
<string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string>
- <string name="no_home_title" msgid="1563808595146071549">"गृह बटन फेला परेन"</string>
- <string name="no_home_message" msgid="5408485011659260911">"यस यन्त्रलाई नेभिगेट गर्न सक्षम हुन गृह बटन आवश्यक छ। कृपया सुरक्षित गर्नु पूर्व गृह बटन थप्नुहोस्।"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"बटनको चौडाइ समायोजन गर्नुहोस्"</string>
<string name="clipboard" msgid="1313879395099896312">"क्लिपबोर्ड"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"क्लिपबोर्डले वस्तुहरूलाई क्लिपबोर्डमा प्रत्यक्ष तान्न अनुमति दिन्छ। प्रस्तुत गर्दा वस्तुहरूलाई क्लिपबोर्डबाट प्रत्यक्ष रूपमा बाहिर तान्न पनि सकिन्छ।"</string>
<string name="accessibility_key" msgid="5701989859305675896">"अनुकूलनको नेभिगेशन बटन"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Keycode बटनहरूले किबोर्ड कुञ्जीहरूलाई नेभिगेशन पट्टीमा थपिने अनुमति दिन्छ। थिच्दा तिनीहरूले चयन गरिएको किबोर्ड कुञ्जी अनुकरण गर्छन्। सुरुमा बटनका लागि कुञ्जी चयन गर्नुपर्छ, त्यसपछि बटनमा छवि देखिनुपर्छ।"</string>
- <string name="select_keycode" msgid="7413765103381924584">"किबोर्ड बटन चयन गर्नुहोस्"</string>
- <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
+ <string name="icon" msgid="8732339849035837289">"आइकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
<string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
@@ -671,8 +671,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"सानो बनाउनुहोस्"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"खारेज गर्नुहोस्"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"फोन तातो भइरहेको छ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"फोन चिसो हुँदै गर्दा केही विशेषताहरूलाई सीमित गरिन्छ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्नेछ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"बायाँ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"दायाँ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"सर्टकट आफू अनुकूल पार्नुहोस्"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"सर्टकट"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"पासवर्ड माग्ने"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"अलर्टहरू"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रिनशटहरू"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"भण्डारण"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index cfb030de2688..f4c306a55854 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtverlichting"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC is uitgeschakeld"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC is ingeschakeld"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Geen recente items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Je hebt alles gewist"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Scherm bovenaan gesplitst"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Scherm links gesplitst"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Scherm rechts gesplitst"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Verbinding met VPN verbreken"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Je apparaat wordt beheerd door <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> gebruikt <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> om je apparaat te beheren."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Je beheerder kan instellingen, zakelijke toegang, apps, aan je apparaat gekoppelde gegevens en de locatiegegevens van je apparaat controleren en beheren."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Meer informatie"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Je bent verbonden met <xliff:g id="VPN_APP">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden gecontroleerd."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-instellingen openen"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Je beheerder heeft netwerkregistratie ingeschakeld, waarmee verkeer op je apparaat wordt bijgehouden.\n\nNeem contact op met je beheerder voor meer informatie."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Je hebt een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nJe bent ook verbonden met een VPN, waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Het is gekoppeld aan <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Het apparaat blijft vergrendeld totdat u het handmatig ontgrendelt"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Sneller meldingen ontvangen"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Geluid laten horen en op het scherm weergeven"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
<string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Beheeropties voor <xliff:g id="APP_NAME">%1$s</xliff:g>-meldingen"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"beheeropties voor meldingen"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"snooze-opties voor meldingen"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuten"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuten"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 uur"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Niet snoozen"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ONGEDAAN MAKEN"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Snoozefunctie <xliff:g id="TIME_AMOUNT">%1$s</xliff:g> actief"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Accugebruik"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Accubesparing niet beschikbaar tijdens opladen"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Accubesparing"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aan"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Uit"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigatiebalk"</string>
- <string name="start" msgid="6873794757232879664">"Begin"</string>
- <string name="center" msgid="4327473927066010960">"Midden"</string>
- <string name="end" msgid="125797972524818282">"Einde"</string>
- <string name="space" msgid="804232271282109749">"Opvulling"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Lay-out"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Links"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Rechts"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Knoptype"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(standaard)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Klembord"</item>
+ <item msgid="5742013440802239414">"Toetscode"</item>
+ <item msgid="8748101184830239843">"Menu/toetsenbord-schakelaar"</item>
+ <item msgid="8175437057325747277">"Geen"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Verdeeld (standaard)"</item>
+ <item msgid="6210279084134579668">"Gecentreerd"</item>
+ <item msgid="89143234390889289">"Links uitgelijnd"</item>
+ <item msgid="7715533883382410603">"Rechts uitgelijnd"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu/toetsenbord-schakelaar"</string>
- <string name="select_button" msgid="1597989540662710653">"Knop kiezen om toe te voegen"</string>
- <string name="add_button" msgid="4134946063432258161">"Knop toevoegen"</string>
<string name="save" msgid="2311877285724540644">"Opslaan"</string>
<string name="reset" msgid="2448168080964209908">"Resetten"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Geen startknop gevonden"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Er is een startknop vereist om te navigeren op dit apparaat. Voeg een startknop toe voordat je opslaat."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Breedte van knop aanpassen"</string>
<string name="clipboard" msgid="1313879395099896312">"Klembord"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Met Klembord kunnen items rechtstreeks naar het klembord worden gesleept. Indien aanwezig, kunnen items ook rechtstreeks van het klembord worden gesleept."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Aangepaste navigatieknop"</string>
<string name="keycode" msgid="7335281375728356499">"Toetscode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Met toetscodeknoppen kunnen toetsenbordtoetsen worden toegevoegd aan de navigatiebalk. Wanneer hierop wordt gedrukt, emuleren ze de geselecteerde toetsenbordtoets. Eerst moet de toets voor de knop worden geselecteerd, gevolgd door een afbeelding die wordt weergegeven op de knop."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Toetsenbordknop selecteren"</string>
- <string name="preview" msgid="9077832302472282938">"Voorbeeld"</string>
+ <string name="icon" msgid="8732339849035837289">"Pictogram"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om tegels toe te voegen"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hier naartoe om te verwijderen"</string>
<string name="qs_edit" msgid="2232596095725105230">"Bewerken"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Sluiten"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"De telefoon wordt warm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Links"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Rechts"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Snelkoppeling aanpassen"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Snelkoppeling"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Wachtwoordprompt"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Algemene berichten"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Opslag"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0ec824d5b444..97ec2f165f19 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ਕੰਮ ਮੋਡ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤਰੀ ਲਾਈਟ"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ਤੁਸੀਂ ਸਭ ਕੁਝ ਸਾਫ਼ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ਵਰਟੀਕਲ ਸਪਲਿਟ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ਕਸਟਮ ਸਪਲਿਟ"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ਸਕ੍ਰੀਨ ਨੂੰ ਉੱਪਰ ਵੱਲ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ਸਕ੍ਰੀਨ ਨੂੰ ਖੱਬੇ ਪਾਸੇ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ਸਕ੍ਰੀਨ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ਚਾਰਜ ਹੋਇਆ"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੇ ਪ੍ਰਬੰਧਨ ਲਈ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ।"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨਾਲ ਜੁੜੇ ਡੈਟੇ ਅਤੇ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ਹੋਰ ਜਾਣੋ"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ਤੁਸੀਂ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੀ ਡੀਵਾਈਸ \'ਤੇ ਟ੍ਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"ਤੁਸੀਂ ਇੱਕ ਐਪ ਨੂੰ ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈਟ ਅਪ ਕਰਨ ਦੀ ਅਨੁਮਤੀ ਦਿੱਤੀ ਹੈ।\n\nਇਹ ਐਪ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਅਤੇ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"ਤੁਹਾਡੇ ਕਾਰਜ-ਸਥਾਨ ਪ੍ਰੋਫ਼ਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਈਮੇਲ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰਨ ਦੇ ਸਮਰੱਥ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"ਤੁਹਾਡੇ ਕਾਰਜ-ਸਥਾਨ ਪ੍ਰੋਫ਼ਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <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="4946600443852045903">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <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_disabled" msgid="7412534203633528135">"ਡੀਵਾਈਸ ਲੌਕ ਰਹੇਗੀ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਨਲੌਕ ਨਹੀਂ ਕਰਦੇ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ਧੁਨੀ ਵਜਾਓ ਅਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਖਾਓ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ਸੂਚਨਾ ਸਨੂਜ਼ ਵਿਕਲਪ"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 ਮਿੰਟ"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 ਮਿੰਟ"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ਘੰਟਾ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ਸਨੂਜ਼ ਨਾ ਕਰੋ"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ਅਣਕੀਤਾ ਕਰੋ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ਲਈ ਸਨੂਜ਼ ਕੀਤਾ ਗਿਆ"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"ਬੈਟਰੀ ਵਰਤੋਂ"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ਬੈਟਰੀ ਸੇਵਰ"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ਚਾਲੂ"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ਬੰਦ"</string>
<string name="nav_bar" msgid="1993221402773877607">"ਆਵਾਗੌਣ ਪੱਟੀ"</string>
- <string name="start" msgid="6873794757232879664">"ਸ਼ੁਰੂ ਕਰੋ"</string>
- <string name="center" msgid="4327473927066010960">"ਕੇਂਦਰ"</string>
- <string name="end" msgid="125797972524818282">"ਸਮਾਪਤ"</string>
- <string name="space" msgid="804232271282109749">"ਸਪੇਸਰ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"ਖਾਕਾ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ਖੱਬੇ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ਸੱਜੇ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ਬਟਨ ਕਿਸਮ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"ਕਲਿੱਪਬੋਰਡ"</item>
+ <item msgid="5742013440802239414">"ਕੀ-ਕੋਡ"</item>
+ <item msgid="8748101184830239843">"ਮੀਨੂ/ਕੀ-ਬੋਰਡ ਸਵਿੱਚਰ"</item>
+ <item msgid="8175437057325747277">"ਕੋਈ ਨਹੀਂ"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"ਵਿਭਾਜਿਤ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="6210279084134579668">"ਕੇਂਦਰਿਤ"</item>
+ <item msgid="89143234390889289">"ਖੱਬੇ-ਇਕਸਾਰ ਕੀਤਾ ਗਿਆ"</item>
+ <item msgid="7715533883382410603">"ਸੱਜੇ-ਇਕਸਾਰ ਕੀਤਾ ਗਿਆ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"ਮੀਨੂ/ਕੀ-ਬੋਰਡ ਸਵਿੱਚਰ"</string>
- <string name="select_button" msgid="1597989540662710653">"ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਬਟਨ ਚੁਣੋ"</string>
- <string name="add_button" msgid="4134946063432258161">"ਬਟਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="save" msgid="2311877285724540644">"ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="reset" msgid="2448168080964209908">"ਰੀਸੈੱਟ ਕਰੋ"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ਕੋਈ ਹੋਮ ਬਟਨ ਨਹੀਂ ਮਿਲਿਆ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਆਵਾਗੌਣ ਕਰਨ ਲਈ ਇੱਕ ਹੋਮ ਬਟਨ ਦੀ ਲੋੜ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਰੱਖਿਅਤ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਇੱਕ ਹੋਮ ਬਟਨ ਸ਼ਾਮਲ ਕਰੋ।"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ਬਟਨ ਚੁੜਾਈ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
<string name="clipboard" msgid="1313879395099896312">"ਕਲਿੱਪਬੋਰਡ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"ਕਲਿੱਪਬੋਰਡ ਆਈਟਮਾਂ ਨੂੰ ਸਿੱਧੇ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਘਸੀਟਣ ਦਿੰਦਾ ਹੈ। ਮੌਜੂਦ ਹੋਣ \'ਤੇ ਆਈਟਮਾਂ ਸਿੱਧੇ ਕਲਿੱਪਬੋਰਡ ਤੋਂ ਬਾਹਰ ਵੀ ਘਸੀਟੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="accessibility_key" msgid="5701989859305675896">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਆਵਾਗੌਣ ਬਟਨ"</string>
<string name="keycode" msgid="7335281375728356499">"ਕੀਕੋਡ"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ਕੀਕੋਡ ਬਟਨ ਕੀ-ਬੋਰਡ ਕੁੰਜੀਆਂ ਨੂੰ ਆਵਾਗੌਣ ਪੱਟੀ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨ ਦਿੰਦੇ ਹਨ। ਦਬਾਏ ਜਾਣ \'ਤੇ ਇਹ ਚੁਣੀਆਂ ਗਈਆਂ ਕੀ-ਬੋਰਡ ਕੁੰਜੀਆਂ ਨੂੰ ਇਮੂਲੇਟ ਕਰਦੇ ਹਨ। ਬਟਨ \'ਤੇ ਵਿਖਾਈ ਜਾਣ ਵਾਲੀ ਤਸਵੀਰ ਦਾ ਅਨੁਸਰਣ ਕਰਦੇ ਹੋਏ, ਪਹਿਲਾਂ ਬਟਨ ਲਈ ਇੱਕ ਕੁੰਜੀ ਨੂੰ ਚੁਣਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ।"</string>
- <string name="select_keycode" msgid="7413765103381924584">"ਕੀ-ਬੋਰਡ ਬਟਨ ਚੁਣੋ"</string>
- <string name="preview" msgid="9077832302472282938">"ਝਲਕ"</string>
+ <string name="icon" msgid="8732339849035837289">"ਪ੍ਰਤੀਕ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ਛੋਟਾ ਕਰੋ"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"ਖਾਰਜ ਕਰੋ"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ਫ਼ੋਨ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਿਤ ਹੁੰਦੀਆਂ ਹਨ"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ਖੱਬੇ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ਸੱਜੇ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ਸ਼ਾਰਟਕੱਟ"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"ਪਾਸਵਰਡ ਲਈ ਪੁੱਛੋ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ਸੁਚੇਤਨਾਵਾਂ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ਆਮ ਸੁਨੇਹੇ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ਸਟੋਰੇਜ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4926e30089c6..04efcd4a9fb2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -325,12 +325,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Tryb pracy"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Podświetlenie nocne"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"Komunikacja NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Komunikacja NFC jest wyłączona"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Komunikacja NFC jest włączona"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Brak ostatnich elementów"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Wszystko zostało wyczyszczone"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
@@ -344,16 +341,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podziel ekran u góry"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podziel ekran z lewej"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podziel ekran z prawej"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
@@ -434,24 +424,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Rozłącz z VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Twoim urządzeniem zarządza <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> używa aplikacji <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> do zarządzania Twoim urządzeniem."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administrator może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane dotyczące urządzenia i lokalizacji oraz nimi zarządzać."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">"  "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Więcej informacji"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Łączysz się z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">"  "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otwórz ustawienia VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikacja otrzymała od Ciebie uprawnienia do konfigurowania połączenia VPN.\n\nMoże ona monitorować Twoją aktywność na urządzeniu i w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem.\n\nŁączysz się też z siecią VPN, która może monitorować Twoją aktywność w sieci."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Urządzenie pozostanie zablokowane, aż odblokujesz je ręcznie"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Szybszy dostęp do powiadomień"</string>
@@ -544,7 +530,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Sygnalizacja dźwiękiem i wyświetlenie komunikatu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> – ustawienia powiadomień"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"sterowanie powiadomieniami"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcje odkładania powiadomień"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 min"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 min"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 godz."</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Nie odkładaj"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"COFNIJ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Odłożono na <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Wykorzystanie baterii"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Oszczędzanie baterii"</string>
@@ -606,25 +600,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Wł."</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Wył."</string>
<string name="nav_bar" msgid="1993221402773877607">"Pasek nawigacji"</string>
- <string name="start" msgid="6873794757232879664">"Na początku"</string>
- <string name="center" msgid="4327473927066010960">"Na środku"</string>
- <string name="end" msgid="125797972524818282">"Na końcu"</string>
- <string name="space" msgid="804232271282109749">"Spacja"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Układ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Po lewej"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Po prawej"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Typ przycisku"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(wartość domyślna)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Schowek"</item>
+ <item msgid="5742013440802239414">"Klawisz"</item>
+ <item msgid="8748101184830239843">"Menu / przełączanie klawiatury"</item>
+ <item msgid="8175437057325747277">"Brak"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Podzielony (wartość domyślna)"</item>
+ <item msgid="6210279084134579668">"Wyśrodkowany"</item>
+ <item msgid="89143234390889289">"Wyrównany do lewej"</item>
+ <item msgid="7715533883382410603">"Wyrównany do prawej"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu / przełączanie klawiatury"</string>
- <string name="select_button" msgid="1597989540662710653">"Wybierz przycisk do dodania"</string>
- <string name="add_button" msgid="4134946063432258161">"Dodaj przycisk"</string>
<string name="save" msgid="2311877285724540644">"Zapisz"</string>
<string name="reset" msgid="2448168080964209908">"Resetuj"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Brak przycisku ekranu głównego"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Do prawidłowej obsługi urządzenia potrzebny jest przycisk ekranu głównego. Dodaj go, zanim zapiszesz zmiany."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Regulacja szerokości przycisku"</string>
<string name="clipboard" msgid="1313879395099896312">"Schowek"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Możesz przeciągać elementy bezpośrednio do schowka. Możesz też przeciągać umieszczone tam wcześniej elementy poza schowek."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Niestandardowy przycisk nawigacji"</string>
<string name="keycode" msgid="7335281375728356499">"Klawisz"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Na pasku nawigacji możesz umieszczać przyciski, które po naciśnięciu emulują funkcje klawiszy klawiatury. Najpierw musisz wybrać, jaki klawisz ma być przypisany do danego przycisku, a następnie wybrać dla niego grafikę."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Wybierz przycisk klawiatury"</string>
- <string name="preview" msgid="9077832302472282938">"Podgląd"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Przeciągnij, aby dodać kafelki"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Przeciągnij tutaj, by usunąć"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edytuj"</string>
@@ -675,8 +675,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizuj"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Zamknij"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon się nagrzewa"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Po lewej"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Po prawej"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Dostosuj skrót"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Skrót"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Pytaj o hasło"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerty"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Zrzuty ekranu"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Wiadomości"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Miejsce"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c89cdc9c4d53..e5a875474f1f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"A NFC está desativada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"A NFC está ativada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir a tela para a parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir a tela para a esquerda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir a tela para a direita"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Seu dispositivo é gerenciado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerenciar seu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"O admin. pode monitorar e gerenciar config., acesso corporativo, apps, dados associados ao dispos. e info de local do dispositivo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saber mais"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Você está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configurações de VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar sua atividade de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador.\n\nVocê também está conectado a uma VPN, que pode monitorar sua atividade de rede."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado ao app <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Receba notificações mais rápido"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controles de notificação"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opções de adiamento de notificação"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"Uma hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Não adiar"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESFAZER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
- <string name="start" msgid="6873794757232879664">"Iniciar"</string>
- <string name="center" msgid="4327473927066010960">"Centralizar"</string>
- <string name="end" msgid="125797972524818282">"Fim"</string>
- <string name="space" msgid="804232271282109749">"Espaçador"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Para a esquerda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Para a direita"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botão"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(padrão)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Área de transferência"</item>
+ <item msgid="5742013440802239414">"Código de tecla"</item>
+ <item msgid="8748101184830239843">"Alternador de teclado / menu"</item>
+ <item msgid="8175437057325747277">"Nenhum"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividido (padrão)"</item>
+ <item msgid="6210279084134579668">"Centralizado"</item>
+ <item msgid="89143234390889289">"Alinhado à esquerda"</item>
+ <item msgid="7715533883382410603">"Alinhado à direita"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Alternador de teclado / menu"</string>
- <string name="select_button" msgid="1597989540662710653">"Selecione o botão p/ adicionar"</string>
- <string name="add_button" msgid="4134946063432258161">"Adicionar botão"</string>
<string name="save" msgid="2311877285724540644">"Salvar"</string>
<string name="reset" msgid="2448168080964209908">"Redefinir"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nenhum botão de início encontrado"</string>
- <string name="no_home_message" msgid="5408485011659260911">"É necessário um botão de início para navegar neste dispositivo. Adicione um botão de início antes de salvar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustar largura do botão"</string>
<string name="clipboard" msgid="1313879395099896312">"Prancheta"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"A Prancheta permite que itens sejam arrastados diretamente para a área de transferência. Também é possível arrastar os itens diretamente para fora da área de transferência, quando estiver presente."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botão de navegação personalizado"</string>
<string name="keycode" msgid="7335281375728356499">"Código de tecla"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Os botões de código de tecla permitem que as teclas do teclado sejam adicionadas à barra de navegação. Quando pressionados, eles emulam a tecla selecionada. Primeiro, a tecla deve ser selecionada para o botão, seguida de uma imagem a ser exibida no botão."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Visualização"</string>
+ <string name="icon" msgid="8732339849035837289">"Ícone"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dispensar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"O smartphone está esquentando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Para a esquerda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Para a direita"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar atalho"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Atalho"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar senha"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 5f87c122b3ff..4304d9992a0b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz noturna"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"O NFC está desativado"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"O NFC está ativado"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ecrã dividido na parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ecrã dividido à esquerda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ecrã dividido à direita"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desligar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"O seu dispositivo é gerido pelo <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"A <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza o <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerir o seu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"O administ. pode monitorizar e gerir definições, acesso empresarial, aplic. e dados associados ao dispositivo, bem como inf. de localiz. do disp."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saiba mais"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Está ligado à rede <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorizar a sua atividade de rede, incluindo emails, aplicações e Websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir as definições de VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"O seu administrador ativou os registos de rede, que monitorizam o tráfego no seu dispositivo.\n\nPara obter mais informações, contacte o administrador."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Concedeu autorização a uma aplicação para configurar uma ligação VPN.\n\nEsta aplicação pode monitorizar a atividade do dispositivo e da rede, incluindo emails, aplicações e Websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu administrador tem a capacidade de monitorizar a sua atividade da rede, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador.\n\nAlém disso, está ligado a uma VPN, que pode monitorizar a sua atividade da rede."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está associado à aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a sua atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nTambém está ligado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até ser desbloqueado manualmente"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Receber notificações mais rapidamente"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e aparecer no ecrã"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlos de notificações do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controlos de notificação"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opções de suspensão de notificações"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Não suspender"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANULAR"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Utiliz. da bateria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Poupança de bateria não disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Poupança de bateria"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
- <string name="start" msgid="6873794757232879664">"Início"</string>
- <string name="center" msgid="4327473927066010960">"Centro"</string>
- <string name="end" msgid="125797972524818282">"Fim"</string>
- <string name="space" msgid="804232271282109749">"Espaçador"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Esquema"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Esquerda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Direita"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botão"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predefinição)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Área de transferência"</item>
+ <item msgid="5742013440802239414">"Código de tecla"</item>
+ <item msgid="8748101184830239843">"Menu/comutador de teclado"</item>
+ <item msgid="8175437057325747277">"Nenhum"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividido (predefinição)"</item>
+ <item msgid="6210279084134579668">"Centrado"</item>
+ <item msgid="89143234390889289">"Alinhado à esquerda"</item>
+ <item msgid="7715533883382410603">"Alinhado à direita"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu/comutador de teclado"</string>
- <string name="select_button" msgid="1597989540662710653">"Selecionar o botão a adicionar"</string>
- <string name="add_button" msgid="4134946063432258161">"Adicionar botão"</string>
<string name="save" msgid="2311877285724540644">"Guardar"</string>
<string name="reset" msgid="2448168080964209908">"Repor"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Sem botão de página inicial"</string>
- <string name="no_home_message" msgid="5408485011659260911">"É necessário um botão de página inicial para navegar neste dispositivo. Adicione um botão de página inicial antes de guardar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustar largura do botão"</string>
<string name="clipboard" msgid="1313879395099896312">"Área de transferência"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"A Área de transferência permite arrastar itens diretamente para a área de transferência. Também é possível arrastar itens diretamente para fora da mesma, quando aí se encontram."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botão de navegação personalizado"</string>
<string name="keycode" msgid="7335281375728356499">"Código de tecla"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Os códigos de tecla permitem adicionar teclas do teclado à Barra de navegação. Quando são premidos, emulam a tecla do teclado selecionada. É necessário selecionar primeiro a tecla para botão e depois uma imagem que será apresentada no mesmo."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selecionar o botão do teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Pré-visualizar"</string>
+ <string name="icon" msgid="8732339849035837289">"Ícone"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar mosaicos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastar para aqui para remover"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"O telemóvel está a aquecer"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Esquerda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Direita"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar atalho"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Atalho"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar palavra-passe"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de ecrã"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c89cdc9c4d53..e5a875474f1f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"A NFC está desativada"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"A NFC está ativada"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir a tela para a parte superior"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir a tela para a esquerda"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir a tela para a direita"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Seu dispositivo é gerenciado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerenciar seu dispositivo."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"O admin. pode monitorar e gerenciar config., acesso corporativo, apps, dados associados ao dispos. e info de local do dispositivo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saber mais"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Você está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configurações de VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar sua atividade de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador.\n\nVocê também está conectado a uma VPN, que pode monitorar sua atividade de rede."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado ao app <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Receba notificações mais rápido"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"controles de notificação"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opções de adiamento de notificação"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"Uma hora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Não adiar"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"DESFAZER"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
- <string name="start" msgid="6873794757232879664">"Iniciar"</string>
- <string name="center" msgid="4327473927066010960">"Centralizar"</string>
- <string name="end" msgid="125797972524818282">"Fim"</string>
- <string name="space" msgid="804232271282109749">"Espaçador"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Para a esquerda"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Para a direita"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botão"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(padrão)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Área de transferência"</item>
+ <item msgid="5742013440802239414">"Código de tecla"</item>
+ <item msgid="8748101184830239843">"Alternador de teclado / menu"</item>
+ <item msgid="8175437057325747277">"Nenhum"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Dividido (padrão)"</item>
+ <item msgid="6210279084134579668">"Centralizado"</item>
+ <item msgid="89143234390889289">"Alinhado à esquerda"</item>
+ <item msgid="7715533883382410603">"Alinhado à direita"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Alternador de teclado / menu"</string>
- <string name="select_button" msgid="1597989540662710653">"Selecione o botão p/ adicionar"</string>
- <string name="add_button" msgid="4134946063432258161">"Adicionar botão"</string>
<string name="save" msgid="2311877285724540644">"Salvar"</string>
<string name="reset" msgid="2448168080964209908">"Redefinir"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nenhum botão de início encontrado"</string>
- <string name="no_home_message" msgid="5408485011659260911">"É necessário um botão de início para navegar neste dispositivo. Adicione um botão de início antes de salvar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustar largura do botão"</string>
<string name="clipboard" msgid="1313879395099896312">"Prancheta"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"A Prancheta permite que itens sejam arrastados diretamente para a área de transferência. Também é possível arrastar os itens diretamente para fora da área de transferência, quando estiver presente."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Botão de navegação personalizado"</string>
<string name="keycode" msgid="7335281375728356499">"Código de tecla"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Os botões de código de tecla permitem que as teclas do teclado sejam adicionadas à barra de navegação. Quando pressionados, eles emulam a tecla selecionada. Primeiro, a tecla deve ser selecionada para o botão, seguida de uma imagem a ser exibida no botão."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
- <string name="preview" msgid="9077832302472282938">"Visualização"</string>
+ <string name="icon" msgid="8732339849035837289">"Ícone"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dispensar"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"O smartphone está esquentando"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Para a esquerda"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Para a direita"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar atalho"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Atalho"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar senha"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 66f7bdebe8c2..535b5c3ea22e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -325,12 +325,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modul de lucru"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Lumină de noapte"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Serviciul NFC este dezactivat"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Serviciul NFC este activat"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
@@ -344,16 +341,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Divizați ecranul în partea de sus"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Divizați ecranul la stânga"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divizați ecranul la dreapta"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Încărcată"</string>
@@ -434,24 +424,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Deconectați rețeaua VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Dispozitivul dvs. este gestionat de <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> folosește <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pentru a vă gestiona dispozitivul."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Admin. dvs. poate monit. și gest. set., accesul la niv. companiei, ap., datele asoc. cu disp. dvs. și info. despre locația disp."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Aflați mai multe"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"V-ați conectat la aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Deschideți Setări VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratorul dvs. a activat înregistrarea în jurnal pentru rețea, funcție ce monitorizează traficul de pe dispozitivul dvs.\n\nPentru mai multe informații, contactați administratorul."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Ați acordat unei aplicații permisiunea de a configura o conexiune VPN.\n\nAceastă aplicație poate monitoriza activitatea de pe dispozitiv și în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Profilul dvs. de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul dvs. vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul.\n\nDe asemenea, sunteți conectat(ă) la o rețea VPN care vă poate monitoriza activitatea în rețea."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"V-ați conectat la aplicația <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea personală în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Profilul dvs. de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Acesta este conectat la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nDe asemenea, sunteți conectat(ă) la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Dispozitivul va rămâne blocat până când îl deblocați manual"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Obțineți notificări mai rapid"</string>
@@ -544,7 +530,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Se emite un sunet și se evidențiază pe ecran"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Opțiuni privind notificările pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"comenzile notificării"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opțiuni de amânare a notificării"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minute"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 de minute"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 oră"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Nu amânați"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ANULAȚI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Amânată <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Utilizarea bateriei"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Economisirea bateriei nu este disponibilă pe durata încărcării"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economisirea bateriei"</string>
@@ -606,25 +600,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Activați"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Dezactivați"</string>
<string name="nav_bar" msgid="1993221402773877607">"Bară de navigare"</string>
- <string name="start" msgid="6873794757232879664">"La început"</string>
- <string name="center" msgid="4327473927066010960">"În centru"</string>
- <string name="end" msgid="125797972524818282">"La final"</string>
- <string name="space" msgid="804232271282109749">"Buton de spațiu"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Aspect"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Stânga"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Dreapta"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tip de buton"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(prestabilit)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Clipboard"</item>
+ <item msgid="5742013440802239414">"Cod de tastă"</item>
+ <item msgid="8748101184830239843">"Comutator meniu/tastatură"</item>
+ <item msgid="8175437057325747277">"Niciunul"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Împărțită (prestabilit)"</item>
+ <item msgid="6210279084134579668">"Centrată"</item>
+ <item msgid="89143234390889289">"Aliniată la stânga"</item>
+ <item msgid="7715533883382410603">"Aliniată la dreapta"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Comutator meniu/tastatură"</string>
- <string name="select_button" msgid="1597989540662710653">"Selectați butonul de adăugat"</string>
- <string name="add_button" msgid="4134946063432258161">"Adăugați un buton"</string>
<string name="save" msgid="2311877285724540644">"Salvați"</string>
<string name="reset" msgid="2448168080964209908">"Resetați"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nu s-a găsit niciun buton Ecran de pornire"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Pentru a naviga pe acest dispozitiv este necesar un buton Ecran de pornire. Adăugați un buton Ecran de pornire înainte să salvați."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Ajustați lățimea butonului"</string>
<string name="clipboard" msgid="1313879395099896312">"Clipboard"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Folosind butonul Clipboard puteți să trageți elemente direct în clipboard. De asemenea, elementele pot fi trase direct din clipboard atunci când există."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Buton personalizat pentru navigare"</string>
<string name="keycode" msgid="7335281375728356499">"Cod de tastă"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Folosind butoanele cu coduri de taste puteți să adăugați taste de la tastatură în Bara de navigare. Când le apăsați, acestea simulează tasta selectată de la tastatură. Mai întâi, trebuie să selectați o tastă pentru un buton, apoi o imagine care să apară pe buton."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Selectați butonul de la tastatură"</string>
- <string name="preview" msgid="9077832302472282938">"Previzualizare"</string>
+ <string name="icon" msgid="8732339849035837289">"Pictogramă"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Trageți pentru a adăuga sectoare"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trageți aici pentru a elimina"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editați"</string>
@@ -675,8 +675,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizați"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Respingeți"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefonul se încălzește"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Anumite funcții sunt limitate în timp ce telefonul se răcește"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonul va încerca automat să se răcească. Puteți folosi telefonul în continuare, dar este posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Stânga"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Dreapta"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizați comanda rapidă"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Comandă rapidă"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitați parola"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerte"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturi de ecran"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mesaje generale"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Stocare"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0571e8d29c9a..68d499d1cc2e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рабочий режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ночной режим"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"Модуль NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Модуль NFC отключен"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Модуль NFC включен"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Недавних приложений нет"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы очистили всё"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Разделить экран по верхнему краю"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Разделить экран по левому краю"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Разделить экран по правому краю"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Отключить VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Этим устройством управляет приложение \"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>\""</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Компания \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\" управляет устройством с помощью приложения \"<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>\""</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Администратор контролирует настройки, приложения, доступ к ресурсам компании, связанные с устройством данные и передачу геоданных."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Подробнее…"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Запущено приложение \"<xliff:g id="VPN_APP">%1$s</xliff:g>\". Оно может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и сайтами."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Открыть настройки VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Администратор включил ведение сетевого журнала, чтобы отслеживать трафик на вашем устройстве.\n\nДля получения подробной информации обращайтесь к администратору."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Вы разрешили приложению подключаться к сети VPN.\n\nОно может отслеживать ваши действия на устройстве и в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Вашим рабочим профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может отслеживать ваши действия в сети, в том числе работу с электронной почтой, приложениями и веб-сайтами.\n\nДля получения подробной информации обращайтесь к администратору.\n\nВы также подключены к сети VPN, в которой можно отслеживать ваши действия."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"Сеть VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Вашим рабочим профилем управляет <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="4946600443852045903">"Вашим рабочим профилем управляет \"<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_disabled" msgid="7412534203633528135">"Устройство необходимо будет разблокировать вручную"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Быстрый доступ к уведомлениям"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Звук и всплывающее окно"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g>: <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"настройки уведомлений"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"параметры отсрочки уведомлений"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минут"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минут"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 час"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Не откладывать"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ОТМЕНИТЬ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Отложено на <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Уровень заряда"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим энергосбережения нельзя включить во время зарядки"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим энергосбережения"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Включено"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Отключено"</string>
<string name="nav_bar" msgid="1993221402773877607">"Панель навигации"</string>
- <string name="start" msgid="6873794757232879664">"Вверху"</string>
- <string name="center" msgid="4327473927066010960">"В центре"</string>
- <string name="end" msgid="125797972524818282">"Внизу"</string>
- <string name="space" msgid="804232271282109749">"Пробел"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Раскладка"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Влево"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Вправо"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тип кнопки"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(по умолчанию)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Буфер обмена"</item>
+ <item msgid="5742013440802239414">"Код клавиши"</item>
+ <item msgid="8748101184830239843">"Меню/переключение раскладки"</item>
+ <item msgid="8175437057325747277">"Нет"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Раздельно (по умолчанию)"</item>
+ <item msgid="6210279084134579668">"По центру"</item>
+ <item msgid="89143234390889289">"По левому краю"</item>
+ <item msgid="7715533883382410603">"По правому краю"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Меню/переключение раскладки"</string>
- <string name="select_button" msgid="1597989540662710653">"Выберите кнопку"</string>
- <string name="add_button" msgid="4134946063432258161">"Добавить кнопку"</string>
<string name="save" msgid="2311877285724540644">"Сохранить"</string>
<string name="reset" msgid="2448168080964209908">"Сбросить"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ошибка"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Прежде чем сохранить настройки, добавьте кнопку перехода на главный экран."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Выбор ширины кнопки"</string>
<string name="clipboard" msgid="1313879395099896312">"Буфер обмена"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"С помощью этой кнопки можно копировать файлы в буфер обмена и извлекать их из него."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Персонализированная кнопка навигации"</string>
<string name="keycode" msgid="7335281375728356499">"Код клавиши"</string>
- <string name="keycode_description" msgid="1403795192716828949">"С помощью этой кнопки можно добавлять клавиши с клавиатуры на панель навигации. Необходимо выбрать клавишу и изображение для соответствующей кнопки."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Выберите клавишу"</string>
- <string name="preview" msgid="9077832302472282938">"Просмотр"</string>
+ <string name="icon" msgid="8732339849035837289">"Значок"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетащите нужные элементы"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Чтобы удалить, перетащите сюда"</string>
<string name="qs_edit" msgid="2232596095725105230">"Изменить"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Свернуть"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Закрыть"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефон нагревается"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Пока телефон не остынет, некоторые функции могут быть недоступны."</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Левая сторона"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Правая сторона"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Настроить ярлык"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Ярлык"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Подсказка для пароля"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Уведомления"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоты"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Сообщения"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 5987fe549047..9c58ba1e3d7a 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"වැඩ ප්‍රකාරය"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"රාත්‍රී ආලෝකය"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC අබලයි"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC සබලයි"</string>
<string name="recents_empty_message" msgid="808480104164008572">"මෑත අයිතම නැත"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ඔබ සියලු දේ හිස් කර ඇත"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"තිරය ඉහළට බෙදන්න"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"තිරය වමට බෙදන්න"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"තිරය දකුණට බෙදන්න"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"අරෝපිතයි"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN විසන්ධි කරන්න"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ඔබගේ උපාංගය <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> මගින් කළමනාකරණය කෙරේ."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ඔබගේ උපාංගය කළමනාකරණය කිරීමට <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> භාවිත කරයි."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ඔබේ උපාංගයට සම්බන්ධ සැකසීම්, ආයතනික ප්‍රවේශය, යෙදුම්, දත්ත, සහ ඔබේ උපාංගයේ ස්ථාන තතු ඔබේ පරිපාලකට නිරීක්ෂණය සහ කළමනාකරණය කළ හැකිය."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"තව දැන ගන්න"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි <xliff:g id="VPN_APP">%1$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN සැකසීම් විවෘත කරන්න"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"ඔබගේ පරිපාලක ඔබගේ උපාංගය මත තදබදය නිරීක්ෂණය කරන, ජාල ඇතුළු වීම ක්‍රියාත්මක කර ඇත.\n\nවැඩිදුර තොරතුරු සඳහා ඔබේ පරිපාලක අමතන්න."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"ඔබ VPN සම්බන්ධතාවක් පිහිටුවීමට යෙදුමකට අවසරයක් දී ඇත.\n\nමෙම යෙදුමට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු, ඔබගේ උපාංග සහ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකිය."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"ඔබේ කාර්ය පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nඔබේ පරිපාලකට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු, ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකිය.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න.\n\nඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, VPN එකකටද ඔබ සබැඳී ඇත"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"ඔබේ කාර්ය පැතිකඩ කළමනාකරණය කරන්නේ <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="4946600443852045903">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <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_disabled" msgid="7412534203633528135">"ඔබ අතින් අගුළු අරින තුරු උපකරණය අගුළු වැටි තිබේ"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"දැනුම්දීම් ඉක්මනින් ලබාගන්න"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ශබ්ද කර තිරය මත උත්පතනය කරන්න"</string>
<string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
<string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> දැනුම්දීම් පාලන"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"දැනුම්දීම් පාලන"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"දැනුම්දීම් මදක් නතර කිරීමේ විකල්ප"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"මිනිත්තු 15"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"මිනිත්තු 30"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"පැය 1"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"මදක් නතර කරන්න එපා"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"අස් කරන්න"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ක් මදක් නතර කරන ලදී"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"බැටරි භාවිතය"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ආරෝපණය අතරතුර බැටරි සුරැකුම ලබා ගත නොහැකිය."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"බැටරි සුරැකුම"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ක්‍රියාත්මකයි"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ක්‍රියාවිරහිතයි"</string>
<string name="nav_bar" msgid="1993221402773877607">"සංචලන තීරුව"</string>
- <string name="start" msgid="6873794757232879664">"ආරම්භ කරන්න"</string>
- <string name="center" msgid="4327473927066010960">"මධ්‍ය"</string>
- <string name="end" msgid="125797972524818282">"අවසානයි"</string>
- <string name="space" msgid="804232271282109749">"ඉඩ"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"පිරිසැලසුම"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"වම්"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"දකුණු"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"බොත්තම් වර්ගය"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(පෙරනිමි)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"පසුරු පුවරුව"</item>
+ <item msgid="5742013440802239414">"යතුරු කේතය"</item>
+ <item msgid="8748101184830239843">"මෙනු / යතුරු පුවරු මාරුව"</item>
+ <item msgid="8175437057325747277">"කිසිවක් නැත"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"බෙදූ (පෙරනිමි)"</item>
+ <item msgid="6210279084134579668">"මැදට ගත්"</item>
+ <item msgid="89143234390889289">"වමට පෙළගැස්වූ"</item>
+ <item msgid="7715533883382410603">"දකුණට පෙළගැස්වූ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"මෙනු / යතුරු පුවරු මාරුව"</string>
- <string name="select_button" msgid="1597989540662710653">"එක් කිරීමට බොත්තම තෝරන්න"</string>
- <string name="add_button" msgid="4134946063432258161">"එක් කරන්න බොත්තම"</string>
<string name="save" msgid="2311877285724540644">"සුරකින්න"</string>
<string name="reset" msgid="2448168080964209908">"යළි පිහිටුවන්න"</string>
- <string name="no_home_title" msgid="1563808595146071549">"මුල් පිටු බොත්තමක් හමු නොවිණි"</string>
- <string name="no_home_message" msgid="5408485011659260911">"මෙම උපාංගය සංචලනය කිරීමට හැකි වීමට මුල් පිටු යතුරක් අවශ්‍යයි. කරුණාකර සුරැකීමට පෙර මුල් පිටු යතුරක් එක් කරන්න."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"බොත්තම් පළල සීරුමාරු කරන්න"</string>
<string name="clipboard" msgid="1313879395099896312">"පසුරු පුවරුව"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"අයිතම කෙලින්ම පසුරු පුවරුවට ඇද ගෙන ඒමට පසුරු පුවරුව ඉඩ දෙයි. අයිතම පසුරු පුවරුවෙහි ඇති විට කෙලින්ම ඉවතට ඇද ගෙන යාමටද හැකිය."</string>
<string name="accessibility_key" msgid="5701989859305675896">"අභිරුචි සංචලන බොත්තම"</string>
<string name="keycode" msgid="7335281375728356499">"යතුරු කේතය"</string>
- <string name="keycode_description" msgid="1403795192716828949">"යතුරු කේත බොත්තම් යතුරු පුවරු යතුරු සංචලන තීරුවට එක් කිරීමට ඉඩ දෙයි. එබූ විට ඒවා තෝරන ලද යතුරු පුවරු යතුර ලබා දෙයි. පළමුව යතුර, ඊට පසු බොත්තම මත පෙන්වන රූපයක් සමගින් බොත්තම සඳහා තේරිය යුතුය."</string>
- <string name="select_keycode" msgid="7413765103381924584">"යතුරු පුවරු බොත්තම තෝරන්න"</string>
- <string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
+ <string name="icon" msgid="8732339849035837289">"නිරූපකය"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
<string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"කුඩා කරන්න"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"අස් කරන්න"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"දුරකථනය උණුසුම් වෙමින්"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"ඔබගේ දුරකථනය ස්වයංක්‍රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්‍ය ලෙස ධාවනය වනු ඇත."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"වම්"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"දකුණු"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"කෙටි මග අභිරුචිකරණය කරන්න"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"කෙටි මග"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"මුරපදය සඳහා ප්‍රේරණය කරන්න"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"ඇඟවීම්"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"තිර රු"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"පොදු පණිවිඩ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"ගබඩාව"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9ace1530c04d..cddcaf0a5855 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovný režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočný režim"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC je deaktivované"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC je aktivované"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Žiadne nedávne položky"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vymazali ste všetko"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Rozdelená obrazovka hore"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Rozdelená obrazovka naľavo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Rozdelená obrazovka napravo"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Odpojiť sieť VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vaše zariadenie spravuje aplikácia <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> spravuje vaše zariadenie pomocou aplikácie <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Správca môže sledovať a spravovať nastavenia, firemný prístup, aplikácie a údaje súvisiace s týmto zariadením vrátane informácií o polohe vášho zariadenia."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ďalšie informácie"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ste pripojený/-á k aplikácii <xliff:g id="VPN_APP">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvoriť Nastavenia pripojenia VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Správca aktivoval zapisovanie do denníka siete, ktoré sleduje premávku na vašom zariadení.\n\nĎalšie informácie vám poskytne správca."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Určitej aplikácii ste udelili povolenie nastaviť pripojenie VPN.\n\nTáto aplikácia môže sledovať vaše zariadenie a aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a webov.\n\nĎalšie informácie vám poskytne správca.\n\nMáte tiež aktívne pripojenie k sieti VPN, ktorá môže sledovať vašu aktivitu v rámci siete."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webov.\n\nĎalšie informácie vám poskytne správca."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nSte tiež pripojený/-á k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Zariadenie zostane uzamknuté, dokým ho ručne neodomknete."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Získavať upozornenia rýchlejšie"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Vydať zvukový signál a vyskočiť na obrazovku"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Ovládacie prvky pre upozornenia z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ovládacie prvky pre upozornenia"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"možnosti stlmenia upozornení"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minút"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minút"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hod."</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Nestlmiť"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"SPÄŤ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Stlmené na <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Využitie batérie"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Šetrič batérie"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Zapnuté"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Vypnuté"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigačný panel"</string>
- <string name="start" msgid="6873794757232879664">"Začiatok"</string>
- <string name="center" msgid="4327473927066010960">"Stred"</string>
- <string name="end" msgid="125797972524818282">"Koniec"</string>
- <string name="space" msgid="804232271282109749">"Medzerník"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Rozloženie"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Doľava"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Doprava"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Typ tlačidla"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(predvolené)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Schránka"</item>
+ <item msgid="5742013440802239414">"Kód klávesnice"</item>
+ <item msgid="8748101184830239843">"Prepínač – ponuka/klávesnica"</item>
+ <item msgid="8175437057325747277">"Žiadne"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Rozdelené (predvolené)"</item>
+ <item msgid="6210279084134579668">"V strede"</item>
+ <item msgid="89143234390889289">"Zarovnané doľava"</item>
+ <item msgid="7715533883382410603">"Zarovnané doprava"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Prepínač – ponuka/klávesnica"</string>
- <string name="select_button" msgid="1597989540662710653">"Výber tlačidla"</string>
- <string name="add_button" msgid="4134946063432258161">"Pridať tlačidlo"</string>
<string name="save" msgid="2311877285724540644">"Uložiť"</string>
<string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nenašlo sa tlačidlo plochy"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Ak chcete používať navigáciu v tomto zariadení, musíte použiť tlačidlo plochy. Pred uložením pridajte tlačidlo plochy."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Upraviť šírku tlačidla"</string>
<string name="clipboard" msgid="1313879395099896312">"Schránka"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Schránka umožňuje presunúť položky priamo do schránky. Ak ju máte k dispozícii, môžete ich z nej aj priamo vytiahnuť."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Vlastné tlačidlo navigácie"</string>
<string name="keycode" msgid="7335281375728356499">"Kód klávesnice"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tlačidlá kódov klávesnice umožňujú pridanie klávesov na navigačný panel. Po stlačení simulujú funkcie vybraných klávesov. Najprv musíte pre tlačidlo vybrať kláves a následne musí byť na tlačidle obrázok."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Výber tlačidla klávesnice"</string>
- <string name="preview" msgid="9077832302472282938">"Ukážka"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice pridáte presunutím"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Presunutím sem odstránite"</string>
<string name="qs_edit" msgid="2232596095725105230">"Upraviť"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovať"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odmietnuť"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Teplota telefónu stúpa"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vľavo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Vpravo"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Prispôsobiť skratku"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Skratka"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Požadovať heslo"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornenia"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovky"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné správy"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Úložisko"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ec26b53185d9..da993b4eb9ef 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način za delo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočna svetloba"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Tehnologija NFC je onemogočena"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Tehnologija NFC je omogočena"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ni nedavnih elementov"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vse te počistili"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Razdeljen zaslon na vrhu"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Razdeljen zaslon na levi"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Razdeljen zaslon na desni"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Prekini povezavo z VPN-jem"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Napravo upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uporablja aplikacijo <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje naprave."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Skrbnik lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, podatke, povezane z napravo, in podatke o lokaciji naprave."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Več o tem"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste z aplikacijo <xliff:g id="VPN_APP">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Odpri nastavitve omrežja VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Skrbnik je vklopil beleženje omrežnega prometa, ki nadzoruje promet v napravi.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikaciji ste dovolili vzpostavitev povezave VPN.\n\nTa aplikacija lahko nadzira napravo in omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Delovni profil upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira vašo omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika.\n\nPovezani ste tudi z omrežjem VPN, ki lahko nadzira vašo omrežno dejavnost."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Delovni profil upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Naprava bo ostala zaklenjena, dokler je ročno ne odklenete."</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Hitrejše prejemanje obvestil"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Predvajaj zvok in prikaži na zaslonu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
<string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolniki obvestil za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolniki obvestil"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"možnosti preložitve obvestil"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minut"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minut"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ura"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ne preloži"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"RAZVELJAVI"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Preloženo za <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Poraba akumulatorja"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Varčevanje z energijo akumulatorja"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Vklopljeno"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Izklop"</string>
<string name="nav_bar" msgid="1993221402773877607">"Vrstica za krmarjenje"</string>
- <string name="start" msgid="6873794757232879664">"Začetek"</string>
- <string name="center" msgid="4327473927066010960">"Sredina"</string>
- <string name="end" msgid="125797972524818282">"Konec"</string>
- <string name="space" msgid="804232271282109749">"Preslednica"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Postavitev"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Levo"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Desno"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Vrsta gumba"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(privzeto)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Odložišče"</item>
+ <item msgid="5742013440802239414">"Koda tipke"</item>
+ <item msgid="8748101184830239843">"Preklopnik menija/tipkovnice"</item>
+ <item msgid="8175437057325747277">"Brez"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Razdeljeno (privzeto)"</item>
+ <item msgid="6210279084134579668">"Na sredini"</item>
+ <item msgid="89143234390889289">"Poravnano na levo"</item>
+ <item msgid="7715533883382410603">"Poravnano na desno"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Preklopnik menija/tipkovnice"</string>
- <string name="select_button" msgid="1597989540662710653">"Izbira gumba za dodajanje"</string>
- <string name="add_button" msgid="4134946063432258161">"Dodaj gumb"</string>
<string name="save" msgid="2311877285724540644">"Shrani"</string>
<string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ni gumba za začetni zaslon"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Če želite krmariti po tej napravi, potrebujete gumb za začetni zaslon. Pred shranjevanjem dodajte gumb za začetni zaslon."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Prilagajanje širine gumba"</string>
<string name="clipboard" msgid="1313879395099896312">"Odložišče"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Odložišče omogoča, da elemente povlečete neposredno vanj. Ko je odložišče na voljo, je elemente prav tako mogoče povleči iz njega."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Gumb za krmarjenje po meri"</string>
<string name="keycode" msgid="7335281375728356499">"Koda tipke"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Gumbi za kode tipk omogočajo dodajanje tipk tipkovnice v vrstico za krmarjenje. Ko jih pritisnete, posnemajo izbrano tipko tipkovnice. Najprej je treba izbrati tipko za gumb, nato pa sliko, ki bo prikazana na gumbu."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Izbira gumba tipkovnice"</string>
- <string name="preview" msgid="9077832302472282938">"Predogled"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povlecite, če želite dodati ploščice"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Če želite odstraniti, povlecite sem"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiraj"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Opusti"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon se segreva"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Nekatere funkcije bodo med ohlajanjem omejene."</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Levo"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Desno"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Prilagodi bližnjico"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Bližnjica"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Poziv za geslo"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Opozorila"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Posnetki zaslona"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Splošna sporočila"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 009b0bee519c..6b8bb9725757 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modaliteti i punës"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Drita e natës"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC është çaktivizuar"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC është aktivizuar"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nuk ka asnjë artikull të fundit"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"I ke pastruar të gjitha"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacioni i aplikacionit"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Ndaje horizontalisht"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ndaj vertikalisht"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ndaj të personalizuarën"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ndaje ekranin lart"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ndaje ekranin në të majtë"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ndaje ekranin në të djathtë"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"I ngarkuar"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Shkëput VPN-në"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Pajisja jote menaxhohet nga <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> përdor <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> për të menaxhuar pajisjen tënde."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administratori yt mund të monitorojë dhe të menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat në lidhje me pajisjen si dhe informacionet e vendndodhjes së pajisjes tënde."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Mëso më shumë"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Je i lidhur me aplikacionin <xliff:g id="VPN_APP">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Hap cilësimet e VPN-së"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratori yt ka aktivizuar regjistrimin e rrjetit, i cili monitoron trafikun në pajisjen tënde.\n\nPër më shumë informacione, kontakto me administratorin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë email-et, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacion, kontakto me administratorin tënd.\n\nJe i lidhur edhe me një VPN, që mund të monitorojë aktivitetin tënd të rrjetit."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë email-et, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Pajisje do të qëndrojë e kyçur derisa ta shkyçësh manualisht"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Merr njoftime më shpejt"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Bëj një tingull dhe shfaq në ekran"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
<string name="notification_done" msgid="5279426047273930175">"U krye"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrollet e njoftimeve të <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrollet e njoftimit"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"opsionet e shtyrjes së njoftimit"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuta"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuta"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 orë"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Mos e shty alarmin"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ZHBËJ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"U shty për <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Përdorimi i baterisë"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"\"Kursyesi i baterisë\" nuk është i disponueshëm gjatë karikimit"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Kursyesi i baterisë"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Aktiv"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Joaktiv"</string>
<string name="nav_bar" msgid="1993221402773877607">"Shiriti i navigimit"</string>
- <string name="start" msgid="6873794757232879664">"Nis"</string>
- <string name="center" msgid="4327473927066010960">"Qendror"</string>
- <string name="end" msgid="125797972524818282">"Fundi"</string>
- <string name="space" msgid="804232271282109749">"Tasti i hapësirës"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Struktura"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Majtas"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Djathtas"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Lloji i butonit"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(e parazgjedhura)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Kujtesa e fragmenteve"</item>
+ <item msgid="5742013440802239414">"Kodi i tasteve"</item>
+ <item msgid="8748101184830239843">"Ndërruesi i menysë/tastierës"</item>
+ <item msgid="8175437057325747277">"Asnjë"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"E ndarë (e parazgjedhura)"</item>
+ <item msgid="6210279084134579668">"Në qendër"</item>
+ <item msgid="89143234390889289">"Bashkërenditur në të majtë"</item>
+ <item msgid="7715533883382410603">"Bashkërenditur në të djathtë"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Ndërruesi i menysë/tastierës"</string>
- <string name="select_button" msgid="1597989540662710653">"Zgjidh butonin për ta shtuar"</string>
- <string name="add_button" msgid="4134946063432258161">"Shto buton"</string>
<string name="save" msgid="2311877285724540644">"Ruaj"</string>
<string name="reset" msgid="2448168080964209908">"Rivendos"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Nuk u gjet asnjë buton \"Kreu\""</string>
- <string name="no_home_message" msgid="5408485011659260911">"Kërkohet një buton \"Kreu\" për të naviguar në këtë pajisje. Shto një buton \"Kreu\" përpara se ta ruash."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Rregullo gjerësinë e butonit"</string>
<string name="clipboard" msgid="1313879395099896312">"Kujtesa e fragmenteve"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Kujtesa e fragmenteve lejon që artikujt të zvarriten direkt në kujtesën e fragmenteve. Artikujt mund të zvarriten gjithashtu direkt jashtë kujtesës së fragmenteve kur janë të pranishëm."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Butoni i personalizuar i navigimit"</string>
<string name="keycode" msgid="7335281375728356499">"Kodi i tasteve"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Butonat e kodit të tasteve lejojnë që të shtohen në shiritin e navigimit tastet e tastierës. Kur shtypen ato shfaqin tastin e zgjedhur të tastierës. Në fillim duhet të zgjidhet tasti për butonin, i ndjekur nga një imazh që do të tregohet në buton."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Zgjidh butonin e tastierës"</string>
- <string name="preview" msgid="9077832302472282938">"Pamja paraprake"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikona"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Zvarrit për të shtuar pllakëzat"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zvarrit këtu për ta hequr"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redakto"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizo"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Hiqe"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefoni po bëhet i ngrohtë"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Disa funksione janë të kufizuara kur telefoni është duke u ftohur"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Majtas"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Djathtas"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizo shkurtoren"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Shkurtore"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Kërko fjalëkalimin"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Sinjalizimet"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Pamjet e ekranit"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mesazhe të përgjithshme"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Hapësira ruajtëse"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a82ff68c6f30..0af49e4e68f0 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим рада"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноћно светло"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC је онемогућен"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC је омогућен"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Нема недавних ставки"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Обрисали сте све"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Подели екран нагоре"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Подели екран налево"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Подели екран надесно"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Прекини везу са VPN-ом"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Уређајем управља <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> користи <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> за управљање уређајем."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Администратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Сазнајте више"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Повезани сте са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отворите подешавања VPN-а"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Администратор је укључио евидентирање мреже, које прати саобраћај на уређају.\n\nКонтактирајте администратора за више информација."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Дали сте дозволу апликацији да подешава VPN везу.\n\nТа апликација може да надгледа активности на уређају и мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управља профилом за Work.\n\nАдминистратор може да прати активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nКонтактирајте администратора за више информација.\n\nПовезани сте и са VPN-ом, који може да прати активности на мрежи."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управља профилом за Work. Он је повезан са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да прати активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nКонтактирајте администратора за више информација."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Уређај ће остати закључан док га не откључате ручно"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Брже добијајте обавештења"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Емитује се звучни сигнал и приказује се на екрану"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроле обавештења за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"контроле обавештења"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"опције за одлагање обавештења"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 минута"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 минута"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 сат"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Не одлажи"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ОПОЗОВИ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Одложено је за <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Потрошња батерије"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Уштеда батерије није доступна током пуњења"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Уштеда батерије"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Укључено"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Искључено"</string>
<string name="nav_bar" msgid="1993221402773877607">"Трака за навигацију"</string>
- <string name="start" msgid="6873794757232879664">"Покрени"</string>
- <string name="center" msgid="4327473927066010960">"Центар"</string>
- <string name="end" msgid="125797972524818282">"Дно"</string>
- <string name="space" msgid="804232271282109749">"Ознака за размак"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Распоред"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Лево"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Десно"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тип дугмета"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(подразумевано)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Меморија"</item>
+ <item msgid="5742013440802239414">"Кôд тастера"</item>
+ <item msgid="8748101184830239843">"Пребацивач мени/тастатура"</item>
+ <item msgid="8175437057325747277">"Ништа"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Подељено (подразумевано)"</item>
+ <item msgid="6210279084134579668">"Центрирано"</item>
+ <item msgid="89143234390889289">"Поравнато улево"</item>
+ <item msgid="7715533883382410603">"Поравнато удесно"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Мени/Тастатура пребацивач"</string>
- <string name="select_button" msgid="1597989540662710653">"Изаберите дугме за додавање"</string>
- <string name="add_button" msgid="4134946063432258161">"Додај дугме"</string>
<string name="save" msgid="2311877285724540644">"Сачувај"</string>
<string name="reset" msgid="2448168080964209908">"Поново постави"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Нисмо пронашли дугме Почетна"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Дугме Почетна је неопходно за навигацију на овом уређају. Додајте дугме Почетна пре него што сачувате измене."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Прилагоди ширину дугмета"</string>
<string name="clipboard" msgid="1313879395099896312">"Привремена меморија"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Привремена меморија омогућава да се ставке превлаче директно у привремену меморију. Постојеће ставке могу да се превлаче и директно из привремене меморије."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Прилагођено дугме за навигацију"</string>
<string name="keycode" msgid="7335281375728356499">"Кôд тастера"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Дугмад за кодове тастера омогућава да се на траку за навигацију додају тастери на тастатури. Када притиснете дугме, симулира се изабрани тастер на тастатури. Прво морате да изаберете тастер за дугме, па слику коју ће се приказивати на дугмету."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Изаберите дугме за тастатуру"</string>
- <string name="preview" msgid="9077832302472282938">"Преглед"</string>
+ <string name="icon" msgid="8732339849035837289">"Икона"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Превуците да бисте додали плочице"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Превуците овде да бисте уклонили"</string>
<string name="qs_edit" msgid="2232596095725105230">"Измени"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Умањи"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Одбаци"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефон се загрејао"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Неке функције су ограничене док се телефон не охлади"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Лево"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Десно"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Прилагоди пречицу"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Пречица"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Упит за лозинку"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Обавештења"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Снимци екрана"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Опште поруке"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Меморијски простор"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8c778d022b47..9700f0a331d5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbetsläge"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattljus"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC är inaktiverat"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC är aktiverat"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Listan med de senaste åtgärderna är tom"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har tömt listan"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delad skärm till överkanten"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delad skärm åt vänster"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delad skärm åt höger"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Koppla från VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Enheten hanteras av <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> hanterar enheten med hjälp av <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administratören kan övervaka och hantera inställningar, företagsåtkomst, appar, data med koppling till enheten och enhetens plats."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Läs mer"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du är ansluten till <xliff:g id="VPN_APP">%1$s</xliff:g> som kan övervaka din aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Öppna VPN-inställningar"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratören har aktiverat nätverksloggning som övervakar trafik på enheten.\n\nKontakta administratören om du vill veta mer."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Du har gett en app behörighet att upprätta en VPN-anslutning.\n\nAppen kan bevaka aktivitet på enheten och nätverket, inklusive e-post, appar och webbplatser."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan övervaka nätverksaktivitet, till exempel e-postmeddelanden, appar och webbplatser.\n\nKontakta administratören om du vill veta mer.\n\nDu är även ansluten till ett VPN som kan övervaka nätverksaktivitet."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan övervaka din privata aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan övervaka nätverksaktivitet på jobbet, till exempel e-postmeddelanden, appar och webbplatser.\n\nKontakta administratören om du vill veta mer."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan hantera privat aktivitet på nätverket."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten förblir låst tills du låser upp den manuellt"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Få aviseringar snabbare"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Spela upp ljud och visa på skärmen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
<string name="notification_done" msgid="5279426047273930175">"Klar"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-aviseringar"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"inställningar för aviseringar"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"alternativ för att snooza aviseringar"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuter"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuter"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 timme"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Snooza inte"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ÅNGRA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Snoozad i <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteriförbrukning"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparläget är inte tillgängligt vid laddning"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparläge"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"På"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Inaktiverat"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigeringsfält"</string>
- <string name="start" msgid="6873794757232879664">"Början"</string>
- <string name="center" msgid="4327473927066010960">"Centrera"</string>
- <string name="end" msgid="125797972524818282">"Slutet"</string>
- <string name="space" msgid="804232271282109749">"Mellanslag"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Vänster"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Höger"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Knapptyp"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(standard)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Urklipp"</item>
+ <item msgid="5742013440802239414">"Tangentkod"</item>
+ <item msgid="8748101184830239843">"Byt mellan meny/tangentbord"</item>
+ <item msgid="8175437057325747277">"Ingen"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"delad (standard)"</item>
+ <item msgid="6210279084134579668">"Centrerad"</item>
+ <item msgid="89143234390889289">"Vänsterjusterad"</item>
+ <item msgid="7715533883382410603">"Högerjusterad"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Byt mellan meny/tangentbord"</string>
- <string name="select_button" msgid="1597989540662710653">"Välj en knapp att lägga till"</string>
- <string name="add_button" msgid="4134946063432258161">"Lägg till knapp"</string>
<string name="save" msgid="2311877285724540644">"Spara"</string>
<string name="reset" msgid="2448168080964209908">"Återställ"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Startskärmsknapp hittades inte"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Det behövs en startskärmsknapp för att kunna navigera den här enheten. Lägg till en startskärmsknapp innan du sparar."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Justera knappens bredd"</string>
<string name="clipboard" msgid="1313879395099896312">"Urklipp"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Objekt kan dras direkt till urklipp. Objekt kan också dras direkt från urklipp när de visas."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Anpassad navigeringsknapp"</string>
<string name="keycode" msgid="7335281375728356499">"Tangentkod"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Med knappar för tangentkod kan tangenter läggas till i navigeringsfältet. När du trycker på dem förvandlas de till den valda tangenten. Först måste du välja en tangent för knappen och därefter en bild som ska visas på knappen."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Välj tangentbordsknapp"</string>
- <string name="preview" msgid="9077832302472282938">"Förhandsgranskning"</string>
+ <string name="icon" msgid="8732339849035837289">"Ikon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lägg till rutor genom att dra"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Ta bort genom att dra här"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redigera"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorera"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Mobilen börjar bli varm"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Vissa funktioner är begränsade medan mobilen svalnar"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Vänster"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Höger"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Anpassa genväg"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Kortkommando"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Kräv lösenord"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Varningar"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skärmdumpar"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Allmänna meddelanden"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 28ecc5018a3a..fc9439c94433 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Hali ya kazi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Mwanga wa Usiku"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC imezimwa"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC imewashwa"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hakuna vipengee vya hivi karibuni"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Umeondoa vipengee vyote"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Gawa skrini kuelekea juu"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Gawa skrini upande wa kushoto"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Gawa skrini upande wa kulia"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Ondoa VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Kifaa chako kinadhibitiwa na <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> inatumia <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> kudhibiti kifaa chako."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Msimamizi wako anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa maudhui ya shirika, programu, data inayohusiana na kifaa chako na maelezo kuhusu mahali kifaa kipo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Pata maelezo zaidi"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Umeunganishwa kwenye <xliff:g id="VPN_APP">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Fungua Mipangilio ya VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Msimamizi wako amewasha kumbukumbu ya kuingia mtandaoni ambayo hufuatilia shughuli kwenye kifaa chako.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Uliruhusu programu iweke muunganisho wa VPN.\n\nProgramu hii inaweza kufuatilia shughuli za kifaa na mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Wasifu wako wa kazini unadhibitiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandaoni, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako.\n\nUmeunganishwa pia kwenye VPN, ambayo inaweza kufuatilia shughuli zako mtandaoni."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Wasifu wako wa kazini unadhibitiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako za mtandaoni, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti. \n\n Wewe pia umeunganishwa kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako kibinafsi."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Pata arifa kwa haraka"</string>
@@ -481,13 +467,13 @@
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Gonga ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
<string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Inaonyesha %s ya vidhibiti vya sauti. Telezesha kidole juu ili uondoe."</string>
<string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Imeficha vidhibiti vya sauti"</string>
- <string name="system_ui_tuner" msgid="708224127392452018">"Kipokea Ishara cha SystemUI"</string>
+ <string name="system_ui_tuner" msgid="708224127392452018">"Kirekebishi cha kiolesura cha mfumo"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"Onyesha asilimia ya betri iliyopachikwa"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"Onyesha asilimia ya kiwango cha betri ndani ya aikoni ya sehemu ya arifa inapokuwa haichaji"</string>
<string name="quick_settings" msgid="10042998191725428">"Mipangilio ya Haraka"</string>
<string name="status_bar" msgid="4877645476959324760">"Sehemu ya kuonyesha hali"</string>
<string name="overview" msgid="4018602013895926956">"Muhtasari"</string>
- <string name="demo_mode" msgid="2532177350215638026">"Hali ya onyesho la UI ya mfumo"</string>
+ <string name="demo_mode" msgid="2532177350215638026">"Hali ya onyesho la kirekebishi cha kiolesura cha mfumo"</string>
<string name="enable_demo_mode" msgid="4844205668718636518">"Washa hali ya onyesho"</string>
<string name="show_demo_mode" msgid="2018336697782464029">"Onyesha hali ya onyesho"</string>
<string name="status_bar_ethernet" msgid="5044290963549500128">"Ethaneti"</string>
@@ -504,12 +490,12 @@
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Mtandao-hewa"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"Wasifu wa kazini"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"Kinafurahisha kwa baadhi ya watu lakini si wote"</string>
- <string name="tuner_warning" msgid="8730648121973575701">"Kipokea Ishara cha System UI kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika, au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"Kirekebishi cha kiolesura cha mfumo kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika, au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
<string name="got_it" msgid="2239653834387972602">"Nimeelewa"</string>
- <string name="tuner_toast" msgid="603429811084428439">"Hongera! Kipokea Ishara cha System UI kimeongezwa kwenye Mipangilio"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"Hongera! Kirekebishi cha kiolesura cha mfumo kimeongezwa kwenye mipangilio"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"Ondoa kwenye Mipangilio"</string>
- <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kipokea ishara cha SystemUI kwenye Mipangilio na uache kutumia vipengele vyake vyote?"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kirekebishi cha kiolesura cha mfumo kwenye mipangilio na uache kutumia vipengele vyake vyote?"</string>
<string name="activity_not_found" msgid="348423244327799974">"Programu haijasakinishwa kwenye kifaa chako"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Onyesha sekunde za saa"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Toa sauti na ibukizi kwenye skrini"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
<string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Vidhibiti vya arifa za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"vidhibiti vya arifa"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"chaguo za kuahirisha arifa"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"Dakika 15"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"Dakika 30"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"Saa 1"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Usiahirishe"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"TENDUA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Imeahirishwa kwa <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Matumizi ya betri"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Kiokoa Betri hakipatikani unapochaji betri"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Kiokoa Betri"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Imewashwa"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Imezimwa"</string>
<string name="nav_bar" msgid="1993221402773877607">"Sehemu ya viungo muhimu"</string>
- <string name="start" msgid="6873794757232879664">"Anza"</string>
- <string name="center" msgid="4327473927066010960">"Weka katikati"</string>
- <string name="end" msgid="125797972524818282">"Mwisho"</string>
- <string name="space" msgid="804232271282109749">"Kiweka nafasi"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Mpangilio"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kushoto"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Kulia"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Aina ya kitufe"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(chaguo-msingi)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Ubao wa kunakili"</item>
+ <item msgid="5742013440802239414">"Msimbo wa ufunguo"</item>
+ <item msgid="8748101184830239843">"Swichi ya Menyu / Kibodi"</item>
+ <item msgid="8175437057325747277">"Hamna"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Iliyogawanywa (chaguo-msingi)"</item>
+ <item msgid="6210279084134579668">"Iliyopangiliwa katikati"</item>
+ <item msgid="89143234390889289">"Iliyopangiliwa kushoto"</item>
+ <item msgid="7715533883382410603">"Iliyopangiliwa kulia"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Swichi ya Menyu / Kibodi"</string>
- <string name="select_button" msgid="1597989540662710653">"Chagua kitufe ili uongeze"</string>
- <string name="add_button" msgid="4134946063432258161">"Ongeza kitufe"</string>
<string name="save" msgid="2311877285724540644">"Hifadhi"</string>
<string name="reset" msgid="2448168080964209908">"Weka upya"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Kitufe cha mwanzo hakijapatikana"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Kitufe cha Mwanzo kinahitajika ili uweze kutumia viungo vya kifaa hiki. Tafadhali ongeza kitufe cha mwanzo kabla ya kuhifadhi."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Rekebisha upana wa kitufe"</string>
<string name="clipboard" msgid="1313879395099896312">"Ubao klipu"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Kipengele cha Ubao klipu hukuwezesha kuburuta vipengee moja kwa moja hadi kwenye ubao klipu. Unaweza pia kuburuta vipengee moja kwa moja kutoka kwenye ubao klipu kama vipo."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Kitufe maalum cha uelekezaji"</string>
<string name="keycode" msgid="7335281375728356499">"Msimbo wa ufunguo"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Vitufe vya msimbo wa ufunguo vinaruhusu vitufe vya kibodi kuongezwa kwenye Sehemu ya viungo muhimu. Vikibonyezwa, vinaiga kitufe kilichochaguliwa cha kibodi. Kwanza, ufunguo lazima uchaguliwe kwa kitufe, kisha picha itakayoonyeshwa kwenye kitufe."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Chagua Kitufe cha Kibodi"</string>
- <string name="preview" msgid="9077832302472282938">"Onyesho la kuchungulia"</string>
+ <string name="icon" msgid="8732339849035837289">"Aikoni"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Buruta ili uongeze vigae"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Buruta hapa ili uondoe"</string>
<string name="qs_edit" msgid="2232596095725105230">"Badilisha"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Punguza"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ondoa"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Joto la simu linaongezeka"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kushoto"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Kulia"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Njia ya mkato maalum"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Njia ya mkato"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Omba nenosiri"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Arifa"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Picha za skrini"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Ujumbe wa Jumla"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Hifadhi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index fd147cd17404..63b9d75f5054 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -34,7 +34,7 @@
<bool name="config_keyguardUserSwitcher">true</bool>
<!-- Nav bar button default ordering/layout -->
- <string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string>
+ <string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string>
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">290</integer>
diff --git a/packages/SystemUI/res/values-sw900dp/config.xml b/packages/SystemUI/res/values-sw900dp/config.xml
index d8f9ef4e9b2f..221b0139e713 100644
--- a/packages/SystemUI/res/values-sw900dp/config.xml
+++ b/packages/SystemUI/res/values-sw900dp/config.xml
@@ -19,6 +19,6 @@
<resources>
<!-- Nav bar button default ordering/layout -->
- <string name="config_navBarLayout" translatable="false">back,home;space;menu_ime,recent</string>
+ <string name="config_navBarLayout" translatable="false">back,home,left;space;right,recent</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 34daf43743c8..b79e8a9ed3cb 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"பணிப் பயன்முறை"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"இரவு ஒளி"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC முடக்கப்பட்டது"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC இயக்கப்பட்டது"</string>
<string name="recents_empty_message" msgid="808480104164008572">"சமீபத்திய பணிகள் இல்லை"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"எல்லாவற்றையும் அழித்துவிட்டீர்கள்"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"திரையை மேல்புறமாகப் பிரி"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"திரையை இடப்புறமாகப் பிரி"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"திரையை வலப்புறமாகப் பிரி"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"சார்ஜ் செய்யப்பட்டது"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPNஐத் துண்டி"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"உங்கள் சாதனத்தை நிர்வகிப்பது: <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"உங்கள் சாதனத்தை நிர்வகிக்க, <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> பயன்பாட்டை <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> பயன்படுத்தும்."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"உங்கள் நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், பயன்பாடுகள், சாதனத்துடன் தொடர்புடைய தரவு, சாதன இருப்பிடத் தகவல் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"மேலும் அறிக"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN அமைப்புகளைத் திற"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"உங்கள் நிர்வாகி நெட்வொர்க் பதிவெடுத்தலை இயக்கியுள்ளார், இது சாதனத்தில் ட்ராஃபிக்கைக் கண்காணிக்கும்.\n\nமேலும் தகவலுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN இணைப்பை அமைக்க, பயன்பாட்டிற்கு அனுமதி வழங்கியுள்ளீர்கள்.\n\nஇந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட, உங்கள் சாதனத்தையும் நெட்வொர்க் செயல்பாட்டையும் கண்காணிக்க முடியும்."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"உங்கள் பணி விவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது.\n\nஉங்கள் நிர்வாகியால் பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்.\n\nமேலும் தகவலுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்.\n\nஉங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய VPN உடனும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"உங்கள் பணி விவரத்தை <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="4946600443852045903">"உங்கள் பணி சுயவிவரத்தை <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_disabled" msgid="7412534203633528135">"நீங்கள் கைமுறையாகத் திறக்கும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"விரைவாக அறிவிப்புகளைப் பெறுதல்"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ஒலியெழுப்பி, திரையில் காட்டும்"</string>
<string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
<string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புக் கட்டுப்பாடுகள்"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"அறிவிப்புக் கட்டுப்பாடுகள்"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"அறிவிப்பை உறக்கநிலையாக்கும் விருப்பங்கள்"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 நிமிடங்கள்"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 நிமிடங்கள்"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 மணிநேரம்"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"உறக்கநிலையில் வைக்காதே"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"செயல்தவிர்"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"உறக்கநிலையில் வைத்திருந்த நேரம்: <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"பேட்டரி உபயோகம்"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"சார்ஜ் செய்யும் போது பேட்டரி சேமிப்பானைப் பயன்படுத்த முடியாது"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"பேட்டரி சேமிப்பான்"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"இயக்கு"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"முடக்கு"</string>
<string name="nav_bar" msgid="1993221402773877607">"வழிசெலுத்தல் பட்டி"</string>
- <string name="start" msgid="6873794757232879664">"தொடங்கு"</string>
- <string name="center" msgid="4327473927066010960">"மையம்"</string>
- <string name="end" msgid="125797972524818282">"முடிவு"</string>
- <string name="space" msgid="804232271282109749">"இடைவெளி"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"தளவமைப்பு"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"இடது"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"வலது"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"பொத்தான் வகை"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(இயல்பு)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"கிளிப்போர்டு"</item>
+ <item msgid="5742013440802239414">"விசைக்குறியீடு"</item>
+ <item msgid="8748101184830239843">"மெனு / விசைப்பலகை மாற்றி"</item>
+ <item msgid="8175437057325747277">"ஏதுமில்லை"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"பிரிக்கப்பட்டது (இயல்பு)"</item>
+ <item msgid="6210279084134579668">"மையப்படுத்தப்பட்டது"</item>
+ <item msgid="89143234390889289">"இடப்புறமாகச் சீரமைக்கப்பட்டது"</item>
+ <item msgid="7715533883382410603">"வலப்புறமாகச் சீரமைக்கப்பட்டது"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"மெனு / விசைப்பலகை மாற்றி"</string>
- <string name="select_button" msgid="1597989540662710653">"சேர்க்க, பொத்தானை தேர்வுசெய்க"</string>
- <string name="add_button" msgid="4134946063432258161">"பொத்தானைச் சேர்"</string>
<string name="save" msgid="2311877285724540644">"சேமி"</string>
<string name="reset" msgid="2448168080964209908">"மீட்டமை"</string>
- <string name="no_home_title" msgid="1563808595146071549">"முகப்புப் பொத்தான் இல்லை"</string>
- <string name="no_home_message" msgid="5408485011659260911">"இந்தச் சாதனத்தில் வழிசெலுத்த, முகப்புப் பொத்தான் தேவை. சேமிக்கும் முன், முகப்புப் பொத்தானைச் சேர்க்கவும்."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"பொத்தானின் அகலத்தை மாற்று"</string>
<string name="clipboard" msgid="1313879395099896312">"கிளிப்போர்டு"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"கிளிப்ஃபோர்டில் உருப்படிகளை இழுத்து விடுவதற்கு கிளிப்போர்டு அனுமதிக்கும். கிளிப்போர்டில் உள்ள உருப்படிகளை வெளியேயும் இழுத்து விடலாம்."</string>
<string name="accessibility_key" msgid="5701989859305675896">"தனிப்பயன் வழிசெலுத்தல் பொத்தான்"</string>
<string name="keycode" msgid="7335281375728356499">"விசைக்குறியீடு"</string>
- <string name="keycode_description" msgid="1403795192716828949">"விசைக்குறியீட்டுப் பொத்தான்கள் மூலம் விசைப்பலகை விசைகளை வழிசெலுத்தல் பட்டியில் சேர்க்கலாம். அழுத்தும் போது, தேர்ந்தெடுத்த விசைப்பலகை விசையாக அது செயல்படும். பொத்தானுக்கான விசையை முதலில் தேர்ந்தெடுக்க வேண்டும், பிறகு பொத்தானில் காட்ட வேண்டிய படத்தைத் தேர்வுசெய்யவும்."</string>
- <string name="select_keycode" msgid="7413765103381924584">"விசைப்பலகைப் பொத்தானைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="preview" msgid="9077832302472282938">"மாதிரிக்காட்சி"</string>
+ <string name="icon" msgid="8732339849035837289">"ஐகான்"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"கட்டங்களைச் சேர்க்க, இழுக்கவும்"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"அகற்ற, இங்கே இழுக்கவும்"</string>
<string name="qs_edit" msgid="2232596095725105230">"மாற்று"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"சிறிதாக்கு"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"நிராகரி"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"மொபைல் சூடாகிறது"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"மொபைலின் வெப்ப அளவு குறையும் போது, சில அம்சங்களைப் பயன்படுத்த முடியாது"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"இடது"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"வலது"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"குறுக்குவழியைத் தனிப்பயனாக்கு"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"குறுக்குவழி"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"கடவுச்சொல்லைக் கேள்"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"விழிப்பூட்டல்கள்"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ஸ்கிரீன் ஷாட்டுகள்"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"பொதுச் செய்திகள்"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"சேமிப்பிடம்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 681bac290cc3..2175c5a49d25 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"పని మోడ్"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"రాత్రి కాంతి"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC నిలిపివేయబడింది"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ప్రారంభించబడింది"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"మీరు అన్నింటినీ తీసివేసారు"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"అనువర్తన సమాచారం"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"స్క్రీన్‌ని ఎగువకు విభజించు"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"స్క్రీన్‌ని ఎడమ వైపుకి విభజించు"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"స్క్రీన్‌ని కుడి వైపుకి విభజించు"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ఛార్జ్ చేయబడింది"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPNను డిస్‌కనెక్ట్ చేయి"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్‌లు, కార్పొరేట్ ప్రాప్యత, అనువర్తనాలు, డేటా మరియు మీ పరికరం యొక్క స్థాన సమాచారాన్ని మీ నిర్వాహకులు పర్యవేక్షించగలరు మరియు నిర్వహించగలరు."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"మరింత తెలుసుకోండి"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN సెట్టింగ్‌లను తెరవండి"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక అనువర్తనానికి అనుమతి ఇచ్చారు.\n\nఈ అనువర్తనం ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ పరికరం మరియు నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌‍సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"<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="4946600443852045903">"మీ కార్యాలయ ప్రొఫైల్‌ను <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_disabled" msgid="7412534203633528135">"మీరు మాన్యువల్‌గా అన్‌లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"నోటిఫికేషన్‌లను వేగంగా పొందండి"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"శబ్దం చేసి, స్క్రీన్‌పై చూపు"</string>
<string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
<string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్ నియంత్రణలు"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"నోటిఫికేషన్ నియంత్రణలు"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"నోటిఫికేషన్ తాత్కాలిక ఆపివేత ఎంపికలు"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 నిమిషాలు"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 నిమిషాలు"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 గంట"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"తాత్కాలిక ఆపివేత ఎంపికను ఎంచుకోవద్దు"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"చర్య రద్దు చేయి"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> వరకు తాత్కాలికంగా ఆపివేయబడింది"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"బ్యాటరీ వినియోగం"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ఛార్జ్ అవుతున్న సమయంలో బ్యాటరీ సేవర్ అందుబాటులో ఉండదు"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"బ్యాటరీ సేవర్"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"ఆన్"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ఆఫ్ చేయి"</string>
<string name="nav_bar" msgid="1993221402773877607">"నావిగేషన్ బార్"</string>
- <string name="start" msgid="6873794757232879664">"ప్రారంభం"</string>
- <string name="center" msgid="4327473927066010960">"మధ్య"</string>
- <string name="end" msgid="125797972524818282">"ముగించు"</string>
- <string name="space" msgid="804232271282109749">"స్పేసర్"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"లేఅవుట్"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ఎడమ"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"కుడి"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"బటన్ రకం"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(డిఫాల్ట్)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"క్లిప్‌బోర్డ్"</item>
+ <item msgid="5742013440802239414">"కీకోడ్"</item>
+ <item msgid="8748101184830239843">"మెను / కీబోర్డ్ స్విచర్"</item>
+ <item msgid="8175437057325747277">"ఏదీ వద్దు"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"విభజించినవి (డిఫాల్ట్)"</item>
+ <item msgid="6210279084134579668">"మద్యస్తంగా ఉంచండి"</item>
+ <item msgid="89143234390889289">"ఎడమవైపుకు సమలేఖనం చేయబడింది"</item>
+ <item msgid="7715533883382410603">"కుడివైపుకు సమలేఖనం చేయబడింది"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"మెను / కీబోర్డ్ స్విచర్"</string>
- <string name="select_button" msgid="1597989540662710653">"జోడించడానికి బటన్‌ను ఎంచుకోండి"</string>
- <string name="add_button" msgid="4134946063432258161">"బటన్‌ను జోడించు"</string>
<string name="save" msgid="2311877285724540644">"సేవ్ చేయి"</string>
<string name="reset" msgid="2448168080964209908">"రీసెట్ చేయి"</string>
- <string name="no_home_title" msgid="1563808595146071549">"హోమ్ బటన్ ఏదీ కనుగొనబడలేదు"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ఈ పరికరాన్ని నావిగేట్ చేయడానికి హోమ్ బటన్ అవసరం. దయచేసి సేవ్ చేయడానికి ముందు హోమ్ బటన్‌ను జోడించండి."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"బటన్ వెడల్పును సర్దుబాటు చేయండి"</string>
<string name="clipboard" msgid="1313879395099896312">"క్లిప్‌బోర్డ్"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"క్లిప్‌బోర్డ్ అంశాలను నేరుగా క్లిప్‌బోర్డ్‌కి లాగడానికి అనుమతిస్తుంది. అలాగే క్లిప్‌బోర్డ్‌లో అంశాలు ఉన్నప్పుడు వాటిని నేరుగా క్లిప్‌బోర్డ్ నుండి బయటకు లాగవచ్చు."</string>
<string name="accessibility_key" msgid="5701989859305675896">"అనుకూల నావిగేషన్ బటన్"</string>
<string name="keycode" msgid="7335281375728356499">"కీకోడ్"</string>
- <string name="keycode_description" msgid="1403795192716828949">"కీకోడ్ బటన్‌లు నావిగేషన్ బార్‌లో కీబోర్డ్ కీలను జోడించడానికి అనుమతిస్తాయి. నొక్కినప్పుడు అవి ఎంచుకోబడిన కీబోర్డ్ కీ చర్యను పునరుత్పాదిస్తాయి. ముందుగా బటన్ కోసం తప్పనిసరిగా కీని ఎంచుకోవాలి, తర్వాత బటన్‌పై చూపాల్సిన చిత్రాన్ని ఎంచుకోవాలి."</string>
- <string name="select_keycode" msgid="7413765103381924584">"కీబోర్డ్ బటన్‌ను ఎంచుకోండి"</string>
- <string name="preview" msgid="9077832302472282938">"పరిదృశ్యం"</string>
+ <string name="icon" msgid="8732339849035837289">"చిహ్నం"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"టైల్‌లను జోడించడానికి లాగండి"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"తీసివేయడానికి ఇక్కడికి లాగండి"</string>
<string name="qs_edit" msgid="2232596095725105230">"సవరించు"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"కనిష్టీకరించు"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"తీసివేయి"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"ఫోన్ వేడెక్కుతోంది"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని లక్షణాలు పరిమితం చేయబడ్డాయి"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"మీ ఫోన్ స్వయంచాలకంగా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ఎడమ"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"కుడి"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"సత్వరమార్గాన్ని అనుకూలీకరించండి"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"సత్వరమార్గం"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"పాస్‌వర్డ్ కోసం ప్రాంప్ట్ చేయి"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"హెచ్చరికలు"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"స్క్రీన్‌షాట్‌లు"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"సాధారణ సందేశాలు"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"నిల్వ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 230c258976ba..e4d489d2c7c0 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"โหมดการทำงาน"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"แสงตอนกลางคืน"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC ถูกปิดใช้งาน"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"เปิดใช้งาน NFC แล้ว"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ไม่มีรายการล่าสุด"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"คุณได้ล้างทุกอย่างแล้ว"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"แยกหน้าจอไปด้านบน"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"แยกหน้าจอไปทางซ้าย"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"แยกหน้าจอไปทางขวา"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"ยกเลิกการเชื่อมต่อ VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"อุปกรณ์ของคุณได้รับการจัดการโดย <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ใช้ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> เพื่อจัดการอุปกรณ์"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"ผู้ดูแลระบบสามารถตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ของคุณ และข้อมูลตำแหน่งของอุปกรณ์"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"เรียนรู้เพิ่มเติม"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"คุณเชื่อมต่อกับ <xliff:g id="VPN_APP">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"เปิดการตั้งค่า VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"ผู้ดูแลระบบได้เปิดการทำบันทึกเครือข่าย ซึ่งจะติดตามดูการรับส่งข้อมูลบนอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"คุณได้ให้สิทธิ์แอปในการตั้งค่าการเชื่อมต่อ VPN\n\nแอปนี้จะสามารถตรวจสอบอุปกรณ์และกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"โปรไฟล์งานของคุณได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูแลระบบสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ต่างๆ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณยังเชื่อมต่อกับ VPN ซึ่งตรวจสอบกิจกรรมในเครือข่ายของคุณได้"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"โปรไฟล์งานของคุณได้รับการจัดการโดย <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="4946600443852045903">"โปรไฟล์งานได้รับการจัดการโดย <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_disabled" msgid="7412534203633528135">"อุปกรณ์จะล็อกจนกว่าคุณจะปลดล็อกด้วยตนเอง"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"รับการแจ้งเตือนเร็วขึ้น"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"ส่งเสียงและแสดงบนหน้าจอ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
<string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"ส่วนควบคุมการแจ้งเตือนของ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"ส่วนควบคุมการแจ้งเตือน"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ตัวเลือกการปิดเสียงแจ้งเตือนชั่วคราว"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 นาที"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 นาที"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ชั่วโมง"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ไม่ต้องปิดเสียงเตือนชั่วคราว"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"เลิกทำ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"ปิดเสียงเตือนชั่วคราวไว้เป็นเวลา <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"การใช้งานแบตเตอรี่"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"โหมดประหยัดแบตเตอรี่"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"เปิด"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"ปิด"</string>
<string name="nav_bar" msgid="1993221402773877607">"แถบนำทาง"</string>
- <string name="start" msgid="6873794757232879664">"บนสุด"</string>
- <string name="center" msgid="4327473927066010960">"กึ่งกลาง"</string>
- <string name="end" msgid="125797972524818282">"ล่างสุด"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"การจัดวาง"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"ซ้าย"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"ขวา"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"ประเภทปุ่ม"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ค่าเริ่มต้น)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"คลิปบอร์ด"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"ปุ่มสลับเมนู/แป้นพิมพ์"</item>
+ <item msgid="8175437057325747277">"ไม่มี"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"แยก (ค่าเริ่มต้น)"</item>
+ <item msgid="6210279084134579668">"ตรงกลาง"</item>
+ <item msgid="89143234390889289">"จัดข้อความชิดซ้าย"</item>
+ <item msgid="7715533883382410603">"จัดข้อความชิดขวา"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"ปุ่มสลับเมนู/แป้นพิมพ์"</string>
- <string name="select_button" msgid="1597989540662710653">"เลือกปุ่มที่จะเพิ่ม"</string>
- <string name="add_button" msgid="4134946063432258161">"เพิ่มปุ่ม"</string>
<string name="save" msgid="2311877285724540644">"บันทึก"</string>
<string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
- <string name="no_home_title" msgid="1563808595146071549">"ไม่พบปุ่มหน้าแรก"</string>
- <string name="no_home_message" msgid="5408485011659260911">"ต้องใช้ปุ่มหน้าแรกเพื่อให้สามารถไปยังส่วนต่างๆ ในอุปกรณ์นี้ โปรดเพิ่มปุ่มหน้าแรกก่อนที่จะบันทึก"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"ปรับความกว้างของปุ่ม"</string>
<string name="clipboard" msgid="1313879395099896312">"คลิปบอร์ด"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"คลิปบอร์ดช่วยให้สามารถลากรายการไปยังคลิปบอร์ดได้โดยตรง นอกจากนี้ คุณยังสามารถลากรายการออกจากคลิปบอร์ดได้โดยตรงหากมีรายการอยู่ในคลิปบอร์ด"</string>
<string name="accessibility_key" msgid="5701989859305675896">"ปุ่มนำทางที่กำหนดเอง"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"ปุ่ม Keycode ช่วยให้สามารถเพิ่มแป้นของแป้นพิมพ์ไปยังแถบนำทาง เมื่อกดปุ่มนี้ ปุ่มจะเลียนแบบการทำงานของแป้นพิมพ์ที่เลือก โดยจะต้องเลือกแป้นให้กับปุ่มก่อน จากนั้นเลือกรูปภาพที่จะแสดงบนปุ่ม"</string>
- <string name="select_keycode" msgid="7413765103381924584">"เลือกปุ่มแป้นพิมพ์"</string>
- <string name="preview" msgid="9077832302472282938">"ดูตัวอย่าง"</string>
+ <string name="icon" msgid="8732339849035837289">"ไอคอน"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ลากเพื่อเพิ่มชิ้นส่วน"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ลากมาที่นี่เพื่อนำออก"</string>
<string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ย่อเล็กสุด"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"ปิด"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"โทรศัพท์เริ่มเครื่องร้อน"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"คุณลักษณะบางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์ลดอุณหภูมิลง"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"ซ้าย"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"ขวา"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"ปรับแต่งทางลัด"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"ทางลัด"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"แจ้งให้ป้อนรหัสผ่าน"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"การแจ้งเตือน"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"ภาพหน้าจอ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"ข้อความทั่วไป"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"พื้นที่เก็บข้อมูล"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7bd443cbce36..ac5aa927d9a7 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"Naka-disable ang NFC"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"Naka-enable ang NFC"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Walang mga kamakailang item"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Na-clear mo ang lahat"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"I-split ang screen pataas"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"I-split ang screen pakaliwa"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"I-split ang screen pakanan"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Idiskonekta ang VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Pinamamahalaan ng <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ang iyong device."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Ginagamit ng <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ang <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> upang pamahalaan ang iyong device."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Masusubaybayan at mapamamahalaan ng admin mo ang setting, pangkorporasyong access, app, data sa device at impormasyon tungkol sa lokasyon ng device mo."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Matuto pa"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Kumonekta ka sa <xliff:g id="VPN_APP">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kasama ang mga email, app at website."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buksan ang Mga Setting ng VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Na-on ng iyong admin ang pag-log sa network, na sumusubaybay sa trapiko ng device mo.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong admin."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Nagbigay ka ng pahintulot sa app upang mag-set up ng VPN na koneksyon.\n\nMaaaring subaybayan ng app na ito ang iyong aktibidad sa device at network, kabilang ang mga email, app at website."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Pinamamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g> ang iyong profile sa trabaho.\n\nMay kakayahan ang admin mo na subaybayan ang iyong aktibidad sa network, kasama ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa admin mo.\n\nNakakonekta ka rin sa isang VPN, na may kakayahang subaybayan ang iyong aktibidad sa network."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network kabilang ang mga email, app at website."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network, kabilang ang mga email, app at website."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Pinamamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g> ang iyong profile sa trabaho. Nakakonekta ito sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na may kakayahang subaybayan ang aktibidad mo sa network sa trabaho, kasama ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong admin."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Mananatiling naka-lock ang device hanggang sa manu-mano mong i-unlock"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Kunin ang notification nang mas mabilis"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Gumawa ng tunog at mag-pop up sa screen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
<string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Mga kontrol sa notification ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"mga kontrol ng notification"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"mga opsyon sa pag-snooze ng notification"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minuto"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 minuto"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 oras"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Huwag mag-snooze"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"I-UNDO"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Na-snooze ng <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Paggamit ng baterya"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Pangtipid sa Baterya"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"I-on"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"I-off"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
- <string name="start" msgid="6873794757232879664">"Simula"</string>
- <string name="center" msgid="4327473927066010960">"Gitna"</string>
- <string name="end" msgid="125797972524818282">"Dulo"</string>
- <string name="space" msgid="804232271282109749">"Spacer"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Layout"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kaliwa"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Kanan"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Uri ng button"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(default)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Clipboard"</item>
+ <item msgid="5742013440802239414">"Keycode"</item>
+ <item msgid="8748101184830239843">"Menu / Keyboard Switcher"</item>
+ <item msgid="8175437057325747277">"Wala"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Hati-hati (default)"</item>
+ <item msgid="6210279084134579668">"Nasa gitna"</item>
+ <item msgid="89143234390889289">"Naka-align sa kaliwa"</item>
+ <item msgid="7715533883382410603">"Naka-align sa kanan"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menu / Keyboard Switcher"</string>
- <string name="select_button" msgid="1597989540662710653">"Pumili ng button na idaragdag"</string>
- <string name="add_button" msgid="4134946063432258161">"Magdagdag ng button"</string>
<string name="save" msgid="2311877285724540644">"I-save"</string>
<string name="reset" msgid="2448168080964209908">"I-reset"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Walang nakitang home button"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Kailangan ng home button upang ma-navigate ang device na ito. Mangyaring magdagdag ng home button bago mag-save."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Isaayos ang lapad ng button"</string>
<string name="clipboard" msgid="1313879395099896312">"Clipboard"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Nagbibigay-daan ang Clipboard na direktang ma-drag sa clipboard ang mga item. Maaari ding direktang i-drag ang mga item palabas sa clipboard."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Custom na button ng navigation"</string>
<string name="keycode" msgid="7335281375728356499">"Keycode"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Nagbibigay-daan ang mga button na Keycode na maidagdag ang mga keyboard key sa Navigation Bar. Kapag pinindot, ginagaya ng mga ito ang napiling keyboard key. Una, dapat munang piliin ang key para sa button, kasunod ng larawan na ipapakita sa button."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Pumili ng Button na Keyboard"</string>
- <string name="preview" msgid="9077832302472282938">"I-preview"</string>
+ <string name="icon" msgid="8732339849035837289">"Icon"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Mag-drag upang magdagdag ng mga tile"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"I-drag dito upang alisin"</string>
<string name="qs_edit" msgid="2232596095725105230">"I-edit"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"I-minimize"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"I-dismiss"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Umiinit ang telepono"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Limitado ang ilang feature habang nagku-cool down ang telepono"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kaliwa"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Kanan"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"I-customize ang shortcut"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Shortcut"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Mag-prompt para sa password"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Mga Alerto"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Mga Screenshot"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Mga Pangkalahatang Mensahe"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f6b42c9d0489..8cf0633f073d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Çalışma modu"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gece Işığı"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC devre dışı"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC etkin"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Yeni öğe yok"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Her şeyi sildiniz"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranı yukarıya doğru böl"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranı sola doğru böl"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranı sağa doğru böl"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN bağlantısını kes"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Cihazınız <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tarafından yönetiliyor."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, cihazınızı yönetmek için <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> kullanıyor."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Yöneticiniz ayarları, kurumsal erişimi, uygulamaları, cihazınızla ilişkilendirilen verileri ve cihazınızın konum bilgilerini takip edip yönetebilir."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Daha fazla bilgi"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"E-postalarınız, uygulamalarınız ve web siteleriniz de dahil olmak üzere ağ etkinliğinizi takip edebilen <xliff:g id="VPN_APP">%1$s</xliff:g> ağına bağlısınız."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN Ayarlarını aç"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Yöneticiniz,cihazınızdaki trafiği izleyen ağ günlük kaydını açtı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN bağlantısı kurması için bir uygulamaya izin verdiniz.\n\nBu uygulama, cihazınızın yanı sıra e-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilir."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz e-postalar, uygulamalar ve web siteleri de dahil olmak üzere ağ etkinliğinizi izleyebilir.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun.\n\nAyrıca, ağ etkinliğinizi izleyebilen bir VPN\'ye de bağlısınız."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. Profiliniz e-postalar, uygulamalar ve web siteleri dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\n Ayrıca kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirimleri daha hızlı alın"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Ses çıkar ve ekranda göster"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
<string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirim denetimleri"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"Bildirim kontrolleri"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildirim erteleme seçenekleri"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 dakika"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 dakika"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 saat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Erteleme"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"GERİ AL"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> süreyle ertelendi"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Pil kullanımı"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Şarj sırasında Pil Tasarrufu özelliği kullanılamaz"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Pil Tasarrufu"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Açık"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Kapalı"</string>
<string name="nav_bar" msgid="1993221402773877607">"Gezinme çubuğu"</string>
- <string name="start" msgid="6873794757232879664">"Başlangıç"</string>
- <string name="center" msgid="4327473927066010960">"Merkez"</string>
- <string name="end" msgid="125797972524818282">"Son"</string>
- <string name="space" msgid="804232271282109749">"Ayırıcı"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Düzen"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Sol"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Sağ"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Düğme türü"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(varsayılan)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Pano"</item>
+ <item msgid="5742013440802239414">"Tuş kodu"</item>
+ <item msgid="8748101184830239843">"Menü / Klavye Değiştirici"</item>
+ <item msgid="8175437057325747277">"Yok"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Bölünmüş (varsayılan)"</item>
+ <item msgid="6210279084134579668">"Ortalanmış"</item>
+ <item msgid="89143234390889289">"Sola hizalanmış"</item>
+ <item msgid="7715533883382410603">"Sağa hizalanmış"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menü / Klavye Değiştirici"</string>
- <string name="select_button" msgid="1597989540662710653">"Eklenecek düğmeyi seçin"</string>
- <string name="add_button" msgid="4134946063432258161">"Düğme ekle"</string>
<string name="save" msgid="2311877285724540644">"Kaydet"</string>
<string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ana ekran düğmesi bulunamadı"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Ana ekran düğmesi bu cihazda gezinebilmek için gereklidir. Kaydetmeden önce lütfen bir ana ekran düğmesi ekleyin."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Düğme genişliğini düzenle"</string>
<string name="clipboard" msgid="1313879395099896312">"Pano"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Pano, öğelerin doğrudan panoya sürüklenmesine olanak sağlar. Panoda bulunan öğeler ayrıca doğrudan panodan dışarı sürüklenebilir."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Özel gezinme düğmesi"</string>
<string name="keycode" msgid="7335281375728356499">"Tuş kodu"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tuş kodu düğmeleri klavye tuşlarının Gezinme Çubuğu\'na eklenmesini sağlar. Tuşa basıldığında, seçili klavye tuşu taklit edilir. İlgili düğme için ilk olarak tuş, ardından düğmede görüntülenecek resim seçilmelidir."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Klavye Düğmesini Seçin"</string>
- <string name="preview" msgid="9077832302472282938">"Önizle"</string>
+ <string name="icon" msgid="8732339849035837289">"Simge"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Blok eklemek için sürükleyin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kaldırmak için buraya sürükleyin"</string>
<string name="qs_edit" msgid="2232596095725105230">"Düzenle"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Simge durumuna getir"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Kapat"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon ısınıyor"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Sol"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Sağ"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Kısayolu özelleştir"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Kısayol"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Şifre sor"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Uyarılar"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekran görüntüleri"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Genel Mesajlar"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Depolama alanı"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5d58046ef6ba..62c0c8c0968f 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -327,12 +327,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Робочий режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нічний режим"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC вимкнено"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC ввімкнено"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Немає нещодавніх завдань"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ви очистили все"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
@@ -346,16 +343,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Розділити екран угорі"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Розділити екран ліворуч"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Розділити екран праворуч"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
@@ -436,24 +426,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Від’єднатися від мережі VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Вашим пристроєм керує додаток <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Компанія <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> керує вашим пристроєм за допомогою додатка <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Адміністратор може відстежувати та контролювати налаштування, корпоративний доступ, додатки й дані, зв’язані з пристроєм, а також геодані пристрою."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Докладніше"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Під’єднано додаток <xliff:g id="VPN_APP">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, як-от доступ до електронної пошти, додатків і веб-сайтів."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Відкрити налаштування мережі VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Ваш адміністратор увімкнув реєстрацію в мережі, під час якої на вашому пристрої відстежується трафік.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Ви дозволили додатку під’єднуватися до мережі VPN.\n\nЦей додаток може відстежувати вашу активність на пристрої та в мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Вашим робочим профілем керує адміністратор організації <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВін може відстежувати ваші дії в мережі, зокрема електронні листи, додатки та веб-сайти.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором.\n\nВаш пристрій також під’єднано до мережі VPN, у якій можна відстежувати ваші дії в мережі."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема доступ до електронної пошти, додатків і веб-сайтів."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Вашим робочим профілем керує адміністратор організації <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="4946600443852045903">"Вашим робочим профілем керує <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_disabled" msgid="7412534203633528135">"Пристрій залишатиметься заблокованим, доки ви не розблокуєте його вручну"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Швидше отримуйте сповіщення"</string>
@@ -546,7 +532,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Зі звуком і спливаючими вікнами"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Елементи керування сповіщеннями додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"елементи керування сповіщеннями"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"параметри відкладення сповіщень"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 хвилин"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 хвилин"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 годину"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Не відкладати"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"ВІДМІНИТИ"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Відкладено на <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Використання заряду"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим енергозбереження не можна ввімкнути під час заряджання"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим енергозбереження"</string>
@@ -608,25 +602,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Увімкнено"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Вимкнути"</string>
<string name="nav_bar" msgid="1993221402773877607">"Панель навігації"</string>
- <string name="start" msgid="6873794757232879664">"На початку"</string>
- <string name="center" msgid="4327473927066010960">"У центрі"</string>
- <string name="end" msgid="125797972524818282">"У кінці"</string>
- <string name="space" msgid="804232271282109749">"Розділювач"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Макет"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Ліворуч"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Праворуч"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Тип кнопки"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(за умовчанням)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Буфер обміну"</item>
+ <item msgid="5742013440802239414">"Код клавіші"</item>
+ <item msgid="8748101184830239843">"Вибір меню або клавіатури"</item>
+ <item msgid="8175437057325747277">"Немає"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Розділений (за умовчанням)"</item>
+ <item msgid="6210279084134579668">"Вирівнювання по центру"</item>
+ <item msgid="89143234390889289">"Вирівнювання за лівим краєм"</item>
+ <item msgid="7715533883382410603">"Вирівнювання за правим краєм"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Вибір меню або клавіатури"</string>
- <string name="select_button" msgid="1597989540662710653">"Виберіть, яку кнопку додати"</string>
- <string name="add_button" msgid="4134946063432258161">"Додати кнопку"</string>
<string name="save" msgid="2311877285724540644">"Зберегти"</string>
<string name="reset" msgid="2448168080964209908">"Віднов."</string>
- <string name="no_home_title" msgid="1563808595146071549">"Немає кнопки \"Головний екран\""</string>
- <string name="no_home_message" msgid="5408485011659260911">"Для навігації пристроєм потрібна кнопка \"Головний екран\". Перш ніж зберегти, додайте цю кнопку."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Змінити ширину кнопки"</string>
<string name="clipboard" msgid="1313879395099896312">"Буфер обміну"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"За допомогою кнопки \"Буфер обміну\" можна перетягувати елементи просто в буфер або з нього."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Спеціальна кнопка навігації"</string>
<string name="keycode" msgid="7335281375728356499">"Код клавіші"</string>
- <string name="keycode_description" msgid="1403795192716828949">"За допомогою кнопок кодів клавіш можна додавати клавіші клавіатури на панель навігації. Якщо натиснути кнопку, вона імітує вибрану клавішу клавіатури. Потрібно вибрати клавішу та зображення для кнопки."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Вибрати кнопку клавіатури"</string>
- <string name="preview" msgid="9077832302472282938">"Переглянути"</string>
+ <string name="icon" msgid="8732339849035837289">"Значок"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетягуйте фрагменти, щоб додавати їх"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перетягніть сюди, щоб видалити"</string>
<string name="qs_edit" msgid="2232596095725105230">"Редагувати"</string>
@@ -677,8 +677,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Згорнути"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Вимкнути"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Телефон нагрівається"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Під час охолодження деякі функції обмежуються"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Ліворуч"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Праворуч"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Налаштувати ярлик"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Комбінація клавіш"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Запит пароля"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Сповіщення"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Знімки екрана"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Загальні повідомлення"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Пам’ять"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 53c67e7445db..9a7629b47fbe 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"کام موڈ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"نائٹ لائٹ"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"‏NFC غیر فعال ہے"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"‏NFC فعال ہے"</string>
<string name="recents_empty_message" msgid="808480104164008572">"کوئی حالیہ آئٹم نہیں"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"آپ نے سب کچھ صاف کر دیا ہے"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"اسکرین کو اوپر کی جانب تقسیم کریں"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"اسکرین کو بائیں جانب تقسیم کریں"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"اسکرین کو دائیں جانب تقسیم کریں"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"چارج ہوگئی"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"‏VPN کو غیر منسلک کریں"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"آپ کا آلہ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> کے زیر انتظام ہے۔"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> آپ کے آلہ کے نظم کیلئے <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> استعمال کرتا ہے۔"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"آپ کا ایڈمن ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کو مانیٹر اور ان کا نظم کر سکتا ہے۔"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"مزید جانیں"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"آپ <xliff:g id="VPN_APP">%1$s</xliff:g> سے منسلک ہیں جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏VPN کی ترتیبات کھولیں"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"آپ کے ایڈمن نے نیٹ ورک لاگنگ آن کر دی ہے، جو آپ کے آلہ پر ٹریفک کو مانیٹر کرتی ہے۔\n\nمزید معلومات کیلئے اپنے ایڈمن سے رابطہ کریں۔"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"‏آپ نے ایک ایپ کو VPN کنکشن ترتیب دینے کی اجازت دی ہے۔\n\nیہ ایپ ای میلز، ایپس اور ویب سائٹس سمیت آپ کے آلہ اور نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"‏آپ کی دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر نظم ہے۔\n\nآپ کا ایڈمن بشمول ای میلز، ایپس، اور ویب سائٹس، آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کرنے کا اہل ہے۔\n\nمزید معلومات کے لیے اپنے ایڈمن سے رابطہ کریں۔\n\nآپ ایک VPN سے بھی منسلک ہیں، جو آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کر سکتا ہے۔"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"آپ کی دفتری پروفائل <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="4946600443852045903">"آپ کا دفتری پروفائل <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_disabled" msgid="7412534203633528135">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"تیزی سے اطلاعات حاصل کریں"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"آواز نکالیں اور اسکرین پر پاپ کریں"</string>
<string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
<string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے نوٹیفکیشن کنٹرولز"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"اطلاع کے کنٹرولز"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"اطلاع اسنوز کرنے کے اختیارات"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 منٹ"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 منٹ"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 گھنٹہ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"اسنوز نہ کريں"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"کالعدم کریں"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> کیلئے اسنوز کیا گیا"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"بیٹری کا استعمال"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"بیٹری سیور"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"آن"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"آف"</string>
<string name="nav_bar" msgid="1993221402773877607">"نیویگیشن بار"</string>
- <string name="start" msgid="6873794757232879664">"شروع کریں"</string>
- <string name="center" msgid="4327473927066010960">"مرکز"</string>
- <string name="end" msgid="125797972524818282">"اختتام"</string>
- <string name="space" msgid="804232271282109749">"سپیسر"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"لے آؤٹ"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"بائیں"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"دائیں"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"بٹن کی قسم"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(ڈیفالٹ)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"کلپ بورڈ"</item>
+ <item msgid="5742013440802239414">"کی کوڈ"</item>
+ <item msgid="8748101184830239843">"مینو/ کی بورڈ سوئچر"</item>
+ <item msgid="8175437057325747277">"کوئی نہیں"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"تقسیم شدہ (ڈیفالٹ)"</item>
+ <item msgid="6210279084134579668">"بیچوں بیچ"</item>
+ <item msgid="89143234390889289">"بائیں جانب موافق کردہ"</item>
+ <item msgid="7715533883382410603">"دائیں جانب موافق کردہ"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"مینو/ کی بورڈ سوئچر"</string>
- <string name="select_button" msgid="1597989540662710653">"شامل کرنے کیلئے بٹن منتخب کریں"</string>
- <string name="add_button" msgid="4134946063432258161">"بٹن شامل کریں"</string>
<string name="save" msgid="2311877285724540644">"محفوظ کریں"</string>
<string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string>
- <string name="no_home_title" msgid="1563808595146071549">"کوئی ہوم بٹن نہیں ملا"</string>
- <string name="no_home_message" msgid="5408485011659260911">"اس آلہ کو نیویگیٹ کرنے کیلئے ایک ہوم بٹن درکار ہے۔ براہ کرم محفوظ کرنے سے پہلے ایک ہوم بٹن شامل کریں۔"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"بٹن کی چوڑائی ایڈجسٹ کریں"</string>
<string name="clipboard" msgid="1313879395099896312">"کلپ بورڈ"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"کلب بورڈ آئٹمز کو براہ راست کلپ بورڈ پر گھسیٹنے کی اجازت دیتا ہے۔ کلپ بورڈ پر آئٹمز موجود ہونے کی صورت میں انہیں بھی براہ راست باہر گھسیٹا جا سکتا ہے۔"</string>
<string name="accessibility_key" msgid="5701989859305675896">"حسب ضرورت نیویگیشن بٹن"</string>
<string name="keycode" msgid="7335281375728356499">"کی کوڈ"</string>
- <string name="keycode_description" msgid="1403795192716828949">"کی کوڈ بٹنز نیویگیشن بار میں کی بورڈ کلیدوں کو شامل ہونے کی اجازت دیتے ہیں۔ دبائے جانے پر یہ منتخب کردہ کی بورڈ کلید کی نقل کرتے ہیں۔ بٹن کیلئے پہلے کلید منتخب ہونی چاہیئے، اس کے بعد بٹن پر دکھائے جانے کیلئے ایک تصویر۔"</string>
- <string name="select_keycode" msgid="7413765103381924584">"کی بورڈ بٹن منتخب کریں"</string>
- <string name="preview" msgid="9077832302472282938">"پیش منظر"</string>
+ <string name="icon" msgid="8732339849035837289">"آئیکن"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ٹائٹلز شامل کرنے کیلئے گھسیٹیں"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ہٹانے کیلئے یہاں گھسیٹیں؟"</string>
<string name="qs_edit" msgid="2232596095725105230">"ترمیم کریں"</string>
@@ -671,8 +671,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"چھوٹی کریں"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"برخاست کریں"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"فون گرم ہو رہا ہے"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"بائیں"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"دائیں"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"شارٹ کٹ کو حسب ضرورت بنائیں"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"شارٹ کٹ"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"پاسورڈ کا اشارہ"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"الرٹس"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"اسکرین شاٹس"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"اسٹوریج"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 9ea82d6a00aa..f6df9068e9bc 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ish rejimi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Tungi rejim"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC o‘chiq"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC yoniq"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hozircha hech narsa yo‘q"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hammasi o‘chirildi"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranni tepaga qadash"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranni chap tomonga qadash"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranni o‘ng tomonga qadash"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"VPN ulanishini uzish"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Qurilmangiz <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tomonidan boshqariladi."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> qurilmangizni boshqarish uchun <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ilovasidan foydalanadi."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Administratoringiz qurilmangiz bilan bog‘liq sozlamalar, korporativ kirish huquqi, ilova va ma’lumotlarni hamda qurilmangizning joylashuv axborotini kuzatishi va boshqarishi mumkin."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Batafsil"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN sozlamalarini ochish"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi.\n\nBatafsil ma’lumot olish uchun administratoringizga murojaat qiling."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Siz ilovaga VPN tarmog‘iga ulanishga ruxsat bergansiz.\n\nUshbu ilova qurilmangiz va internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator internetdagi harakatlaringizni, jumladan, e-pochta, ilova va xavfsiz veb-saytlar bilan ishlashingizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning.\n\nShuningdek, siz VPN tarmog‘iga ham ulangansiz. U internetdagi harakatlaringizni kuzatishi mumkin."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirishnomalarni tezroq oling"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Ovoz va qalqib chiquvchi oyna"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
<string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalarini boshqarish"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"bildirishnoma sozlamalari"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildirishnomalarni kechiktirish parametrlari"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 daqiqa"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 daqiqa"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 soat"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Kechiktirilmasin"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"BEKOR QILISH"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> muddatga kechiktirildi"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batareya sarfi"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Quvvat tejash rejimi"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Yoniq"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"O‘chiq"</string>
<string name="nav_bar" msgid="1993221402773877607">"Navigatsiya paneli"</string>
- <string name="start" msgid="6873794757232879664">"Boshlash"</string>
- <string name="center" msgid="4327473927066010960">"Markazda"</string>
- <string name="end" msgid="125797972524818282">"Oxiri"</string>
- <string name="space" msgid="804232271282109749">"Ajratuvchi"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Sxema"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Chap"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"O‘ng"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Tugma turi"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(standart)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Vaqtinchalik xotira"</item>
+ <item msgid="5742013440802239414">"Tugma kodi"</item>
+ <item msgid="8748101184830239843">"Menyu/klaviaturani almashtirish"</item>
+ <item msgid="8175437057325747277">"Hech biri"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Alohida (standart)"</item>
+ <item msgid="6210279084134579668">"Markazda"</item>
+ <item msgid="89143234390889289">"Chapga tekislangan"</item>
+ <item msgid="7715533883382410603">"O‘ngga tekislangan"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Menyu yoki klaviatura"</string>
- <string name="select_button" msgid="1597989540662710653">"Qo‘shish uchun tugmani tanlang"</string>
- <string name="add_button" msgid="4134946063432258161">"Tugma qo‘shish"</string>
<string name="save" msgid="2311877285724540644">"Saqlash"</string>
<string name="reset" msgid="2448168080964209908">"Asliga qaytarish"</string>
- <string name="no_home_title" msgid="1563808595146071549">"“Bosh ekran” tugmasi topilmadi"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Qurilma bo‘ylab o‘tish uchun “Bosh ekran” tugmasi kerak. Saqlashdan oldin mazkur tugmani qo‘shing."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Tugma enini moslashtiring"</string>
<string name="clipboard" msgid="1313879395099896312">"Vaqtinchalik xotira"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"“Vaqtinchalik xotira” tugmasi yordamida elementlarni vaqtinchalik xotiraga olish va undan chiqarish qulay."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Maxsus navigatsiya tugmasi"</string>
<string name="keycode" msgid="7335281375728356499">"Tugma kodi"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Tugmalar kodi yordamida klaviatura tugmalarini navigatsiya paneliga qo‘shish mumkin. Ular bosilganda tanlangan klaviatura tugmasining bosilishini taqlid qiladi. Tugmalar kodi uchun klaviatura tugmasi va rasm tanlanishi kerak."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
- <string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
+ <string name="icon" msgid="8732339849035837289">"Nishoncha"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Kerakli elementni tortib qo‘shing"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga torting"</string>
<string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Yig‘ish"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Yopish"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Telefon qizib ketdi"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon sovish paytida ayrim funksiyalar ishlamasligi mumkin"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Chap"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"O‘ng"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Yorliqni sozlash"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Yorliq"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Parol uchun bildirgi"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Ogohlantirishlar"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinshotlar"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Umumiy xabarlar"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Xotira"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 681787196c8b..ce5d46fe1356 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Chế độ làm việc"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Đèn đọc sách"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC đã được tắt"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC đã được bật"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Không có mục gần đây nào"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Bạn đã xóa mọi nội dung"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Chia đôi màn hình lên trên"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Chia đôi màn hình sang trái"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Chia đôi màn hình sang phải"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc đầy"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Ngắt kết nối VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Thiết bị của bạn do <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> quản lý."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> sử dụng <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> để quản lý thiết bị của bạn."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Quản trị viên của bạn có thể giám sát và quản lý cài đặt, quyền truy cập dữ liệu công ty, ứng dụng, dữ liệu được liên kết với thiết bị và thông tin vị trí thiết bị của bạn."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Tìm hiểu thêm"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Bạn đang kết nối với <xliff:g id="VPN_APP">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Mở cài đặt VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Quản trị viên đã bật tính năng ghi nhật ký mạng. Tính năng này giám sát lưu lượng truy cập trên thiết bị của bạn.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Bạn đã cấp cho ứng dụng quyền thiết lập kết nối VPN.\n\nỨng dụng này có thể giám sát hoạt động mạng và thiết bị của bạn, bao gồm email, ứng dụng và trang web."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Hồ sơ công việc của bạn do <xliff:g id="ORGANIZATION">%1$s</xliff:g> quản lý.\n\nQuản trị viên có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn.\n\nBạn cũng được kết nối với VPN. Dịch vụ này có thể giám sát hoạt động mạng của bạn."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Hồ sơ công việc của bạn do <xliff:g id="ORGANIZATION">%1$s</xliff:g> quản lý. Hồ sơ này được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng được kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, có thể giám sát hoạt động mạng cá nhân của bạn."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Thiết bị sẽ vẫn bị khóa cho tới khi bạn mở khóa theo cách thủ công"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Nhận thông báo nhanh hơn"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Phát âm báo và hiển thị trên màn hình"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
<string name="notification_done" msgid="5279426047273930175">"Xong"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"Điều khiển thông báo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"điều khiển thông báo"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Tùy chọn báo lại thông báo"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 phút"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 phút"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 giờ"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Không báo lại"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"HOÀN TÁC"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Báo lại sau <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Mức sử dụng pin"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Trình tiết kiệm pin không khả dụng trong khi sạc"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Trình tiết kiệm pin"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Bật"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Tắt"</string>
<string name="nav_bar" msgid="1993221402773877607">"Thanh điều hướng"</string>
- <string name="start" msgid="6873794757232879664">"Đầu"</string>
- <string name="center" msgid="4327473927066010960">"Căn giữa"</string>
- <string name="end" msgid="125797972524818282">"Cuối"</string>
- <string name="space" msgid="804232271282109749">"Ký tự cách"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Bố cục"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Bên trái"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Bên phải"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Loại nút"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(mặc định)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Khay nhớ tạm"</item>
+ <item msgid="5742013440802239414">"Mã phím"</item>
+ <item msgid="8748101184830239843">"Trình chuyển đổi bàn phím / menu"</item>
+ <item msgid="8175437057325747277">"Không có"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Đã căn đều (mặc định)"</item>
+ <item msgid="6210279084134579668">"Đã căn giữa"</item>
+ <item msgid="89143234390889289">"Đã căn trái"</item>
+ <item msgid="7715533883382410603">"Đã căn phải"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Trình chuyển đổi bàn phím / menu"</string>
- <string name="select_button" msgid="1597989540662710653">"Chọn nút để thêm"</string>
- <string name="add_button" msgid="4134946063432258161">"Thêm nút"</string>
<string name="save" msgid="2311877285724540644">"Lưu"</string>
<string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Không tìm thấy nút trang chủ"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Cần có nút trang chủ để có thể điều hướng thiết bị này. Vui lòng thêm nút trang chủ trước khi lưu."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Điều chỉnh chiều rộng nút"</string>
<string name="clipboard" msgid="1313879395099896312">"Khay nhớ tạm"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Khay nhớ tạm cho phép kéo trực tiếp mục vào khay nhớ tạm. Bạn cũng có thể kéo trực tiếp mục ra khỏi khay nhớ tạm khi hiển thị."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Nút điều hướng tùy chỉnh"</string>
<string name="keycode" msgid="7335281375728356499">"Mã phím"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Các nút mã phím cho phép thêm các phím trên bàn phím vào Thanh điều hướng. Khi bạn nhấn, các nút này sẽ mô phỏng phím trên bàn phím được chọn. Trước tiên, bạn phải chọn phím cho nút, sau đó chọn một hình ảnh để hiển thị trên nút."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Chọn nút trên bàn phím"</string>
- <string name="preview" msgid="9077832302472282938">"Xem trước"</string>
+ <string name="icon" msgid="8732339849035837289">"Biểu tượng"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Kéo để thêm ô"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kéo vào đây để xóa"</string>
<string name="qs_edit" msgid="2232596095725105230">"Chỉnh sửa"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Thu nhỏ"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Loại bỏ"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Điện thoại đang nóng lên"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Bên trái"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Bên phải"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Tùy chỉnh lối tắt"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Lối tắt"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Lời nhắc nhập mật khẩu"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Cảnh báo"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ảnh chụp màn hình"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Thông báo chung"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Bộ nhớ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index f22fc3df40f0..d0c9e001941f 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜间模式"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC 已停用"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC 已启用"</string>
<string name="recents_empty_message" msgid="808480104164008572">"近期没有任何内容"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有内容"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"将屏幕分隔线移到上方"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"将屏幕分隔线移到左侧"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"将屏幕分隔线移到右侧"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充满"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"断开VPN连接"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"您的设备由<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>管理。"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>会使用<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>管理您的设备。"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"您的管理员能够监控和管理与您的设备相关的设置、企业权限、应用、数据,以及您设备的位置信息。"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"了解详情"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"您已连接到<xliff:g id="VPN_APP">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"打开 VPN 设置"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"您的管理员已开启网络日志功能,该功能会监控您设备上的流量。\n\n如需更多信息,请与您的管理员联系。"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授权应用设置 VPN 连接。\n\n该应用可以监控您的设备和网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”管理。\n\n您的管理员能够监控您的网络活动,其中包括收发电子邮件、使用应用和访问网站。\n\n如需更多信息,请与您的管理员联系。\n\n此外,您还连接到了 VPN,它同样可以监控您的网络活动。"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"您的工作资料由“<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="4946600443852045903">"您的工作资料由以下单位管理:<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_disabled" msgid="7412534203633528135">"在您手动解锁之前,设备会保持锁定状态"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"更快捷地查看通知"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"发出提示音并在屏幕上弹出通知"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>通知设置"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g><xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"通知设置"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知延后选项"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 分钟"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 分钟"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 小时"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"不延后"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"撤消"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"已延后 <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"电池使用情况"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用省电模式"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"省电模式"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"开启"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"关闭"</string>
<string name="nav_bar" msgid="1993221402773877607">"导航栏"</string>
- <string name="start" msgid="6873794757232879664">"顶部"</string>
- <string name="center" msgid="4327473927066010960">"中心位置"</string>
- <string name="end" msgid="125797972524818282">"底部"</string>
- <string name="space" msgid="804232271282109749">"空格键"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"布局"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"左侧"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"右侧"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"按钮类型"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(默认)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"剪贴板"</item>
+ <item msgid="5742013440802239414">"键码"</item>
+ <item msgid="8748101184830239843">"菜单/键盘切换器"</item>
+ <item msgid="8175437057325747277">"无"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"分割(默认)"</item>
+ <item msgid="6210279084134579668">"居中"</item>
+ <item msgid="89143234390889289">"左对齐"</item>
+ <item msgid="7715533883382410603">"右对齐"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"菜单/键盘切换器"</string>
- <string name="select_button" msgid="1597989540662710653">"选择要添加的按钮"</string>
- <string name="add_button" msgid="4134946063432258161">"添加按钮"</string>
<string name="save" msgid="2311877285724540644">"保存"</string>
<string name="reset" msgid="2448168080964209908">"重置"</string>
- <string name="no_home_title" msgid="1563808595146071549">"未找到主屏幕按钮"</string>
- <string name="no_home_message" msgid="5408485011659260911">"要在此设备上导航,您必须使用主屏幕按钮。请先添加主屏幕按钮,然后再保存。"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"调整按钮宽度"</string>
<string name="clipboard" msgid="1313879395099896312">"剪贴板"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"您可以利用“剪贴板”按钮将相应内容直接拖动到剪贴板中。剪贴板中有内容时,您也可以将剪贴板中的内容直接拖出来。"</string>
<string name="accessibility_key" msgid="5701989859305675896">"自定义导航按钮"</string>
<string name="keycode" msgid="7335281375728356499">"键码"</string>
- <string name="keycode_description" msgid="1403795192716828949">"您可以利用“键码”按钮将键盘按键添加到导航栏中。只要按下这些按钮,按钮即可模仿所选键盘按键执行相应的操作。要使用这项功能,您必须先为按钮选择相应的按键,然后再选择要在按钮上显示的图片。"</string>
- <string name="select_keycode" msgid="7413765103381924584">"选择键盘按钮"</string>
- <string name="preview" msgid="9077832302472282938">"预览"</string>
+ <string name="icon" msgid="8732339849035837289">"图标"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖动即可添加图块"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖动到此处即可移除"</string>
<string name="qs_edit" msgid="2232596095725105230">"修改"</string>
@@ -671,8 +671,19 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"关闭"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"手机温度上升中"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"手机降温时,部分功能的使用会受限制"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"左侧"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"右侧"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"自定义快捷方式"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"快捷方式"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"提示输入密码"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"提醒"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"屏幕截图"</string>
+ <!-- no translation found for notification_channel_general (4525309436693914482) -->
+ <skip />
+ <string name="notification_channel_storage" msgid="3077205683020695313">"存储空间"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9e74d4152dbb..f7bf78e6b3a8 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -323,12 +323,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈模式"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC 已停用"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC 已啟用"</string>
<string name="recents_empty_message" msgid="808480104164008572">"沒有最近項目"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有項目"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
@@ -342,16 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"將分割畫面顯示喺頂部"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"將分割畫面顯示喺左邊"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"將分割畫面顯示喺右邊"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
@@ -432,24 +422,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"中斷 VPN 連線"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"您的裝置由「<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>」管理。"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>使用「<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>」管理您的裝置。"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"您的管理員可以監控及管理您裝置的設定、公司存取權、應用程式、資料及位置資訊。"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"瞭解詳情"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"您已連接至「<xliff:g id="VPN_APP">%1$s</xliff:g>」,此應用程式可以監控您的網絡活動,包括電郵、應用程式及網站。"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"開啟 VPN 設定"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"您的管理員已開啟網絡記錄功能,以監控您裝置上的流量。\n\n如需瞭解詳情,請聯絡您的管理員。"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授權應用程式設定 VPN 連線。\n\n這個應用程式能夠監控您的裝置和網絡活動,包括電郵、應用程式和網站。"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。\n\n您的管理員可以監控您的網絡活動,包括收發電郵、使用應用程式和瀏覽網站。\n\n如需瞭解詳情,請聯絡您的管理員。\n\n此外,由於您已連接至 VPN,因此 VPN 可監控您的網絡活動。"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g> ,它能夠監控您的網絡活動,包括電郵、應用程式和網站。"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"您的工作設定檔由<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="4946600443852045903">"您的工作設定檔由<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_disabled" msgid="7412534203633528135">"裝置將保持上鎖,直到您手動解鎖"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
@@ -542,7 +528,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在螢幕上彈出通知"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"通知控制項"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知重響選項"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 分鐘"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 分鐘"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 小時"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"不要重響"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"復原"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"已隔 <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>重響"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用「省電模式」"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"省電模式"</string>
@@ -604,25 +598,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"開啟"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"關閉"</string>
<string name="nav_bar" msgid="1993221402773877607">"導覽列"</string>
- <string name="start" msgid="6873794757232879664">"畫面頂部"</string>
- <string name="center" msgid="4327473927066010960">"畫面中央"</string>
- <string name="end" msgid="125797972524818282">"畫面底部"</string>
- <string name="space" msgid="804232271282109749">"間隔"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"配置"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"左"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"右"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"按鈕類型"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(預設)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"剪貼簿"</item>
+ <item msgid="5742013440802239414">"按鍵碼"</item>
+ <item msgid="8748101184830239843">"選單/鍵盤切換工具"</item>
+ <item msgid="8175437057325747277">"無"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"分隔 (預設)"</item>
+ <item msgid="6210279084134579668">"置中"</item>
+ <item msgid="89143234390889289">"靠左對齊"</item>
+ <item msgid="7715533883382410603">"靠右對齊"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"選單/鍵盤切換工具"</string>
- <string name="select_button" msgid="1597989540662710653">"選取要新增的按鈕"</string>
- <string name="add_button" msgid="4134946063432258161">"新增按鈕"</string>
<string name="save" msgid="2311877285724540644">"儲存"</string>
<string name="reset" msgid="2448168080964209908">"重設"</string>
- <string name="no_home_title" msgid="1563808595146071549">"找不到主按鈕"</string>
- <string name="no_home_message" msgid="5408485011659260911">"您必須設定主按鈕才能操作此裝置。請先新增主按鈕,然後再儲存。"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"調整按鈕寬度"</string>
<string name="clipboard" msgid="1313879395099896312">"剪貼簿"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"「剪貼簿」讓您直接將項目拖曳至剪貼簿,亦可直接將剪貼簿內現有的項目拖曳出來。"</string>
<string name="accessibility_key" msgid="5701989859305675896">"自訂導覽按鈕"</string>
<string name="keycode" msgid="7335281375728356499">"按鍵碼"</string>
- <string name="keycode_description" msgid="1403795192716828949">"「按鍵碼」按鈕讓您將鍵盤按鍵新增至導覽列。按下按鈕後,系統便會執行與所選鍵盤按鍵對應的操作。如要使用此功能,請先為按鈕選取按鍵要模擬的鍵盤按鍵,然後指定按鈕的顯示圖像。"</string>
- <string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鈕"</string>
- <string name="preview" msgid="9077832302472282938">"預覽"</string>
+ <string name="icon" msgid="8732339849035837289">"圖示"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳這裡即可移除"</string>
<string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
@@ -673,8 +673,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"關閉"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"手機溫度正在上升"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"手機降溫時,部分功能會受限制"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"手機會自動嘗試降溫。您仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"左"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"右"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"自訂捷徑"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"捷徑"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"輸入密碼提示"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1d52de32f2fd..54ef0a6449ff 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC 已停用"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC 已啟用"</string>
<string name="recents_empty_message" msgid="808480104164008572">"最近沒有任何項目"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有工作"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"將分割畫面顯示在頂端"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"將分割畫面顯示在左邊"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"將分割畫面顯示在右邊"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"中斷 VPN 連線"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"你的裝置是由「<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>」所管理。"</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> 使用「<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>」管理你的裝置。"</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"你的管理員可以監控及管理與裝置相關聯的設定、公司系統權限、應用程式和資料,以及裝置的位置資訊。"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"瞭解詳情"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"由於你已連結至「<xliff:g id="VPN_APP">%1$s</xliff:g>」,你的網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"開啟 VPN 設定"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"你的管理員已啟用網路紀錄功能,可監控你裝置的流量。\n\n如需詳細資訊,請與你的管理員聯絡。"</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授權一個應用程式設定 VPN 連線。\n\n這個應用程式可以監控您的裝置和網路活動,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"你的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n你的管理員可以監控你的網路活動,包括收發電子郵件、使用應用程式及瀏覽網站。\n\n如需詳細資訊,請與你的管理員聯絡。\n\n此外,由於你已連線至 VPN,因此你的網路活動也會受到 VPN 監控。"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"你的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。你的 Work 設定檔已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,因此該應用程式可以監控你的 Work 網路活動,包括收發電子郵件、使用應用程式及瀏覽網站。\n\n如需詳細資訊,請與你的管理員聯絡。"</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n同時由於您也連線至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控。"</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在您手動解鎖前,裝置將保持鎖定狀態"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在畫面上彈出通知"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"通知控制項"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知延後選項"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 分鐘"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 分鐘"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 小時"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"不要延後"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"復原"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"已延後 <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用節約耗電量模式"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"節約耗電量"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"開啟"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"關閉"</string>
<string name="nav_bar" msgid="1993221402773877607">"導覽列"</string>
- <string name="start" msgid="6873794757232879664">"畫面頂端"</string>
- <string name="center" msgid="4327473927066010960">"畫面中央"</string>
- <string name="end" msgid="125797972524818282">"畫面底部"</string>
- <string name="space" msgid="804232271282109749">"空格字元"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"配置"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"左側"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"右側"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"按鈕類型"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(預設)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"剪貼簿"</item>
+ <item msgid="5742013440802239414">"按鍵碼"</item>
+ <item msgid="8748101184830239843">"選單/鍵盤切換工具"</item>
+ <item msgid="8175437057325747277">"無"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"分割 (預設)"</item>
+ <item msgid="6210279084134579668">"置中"</item>
+ <item msgid="89143234390889289">"靠左對齊"</item>
+ <item msgid="7715533883382410603">"靠右對齊"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"選單/鍵盤切換工具"</string>
- <string name="select_button" msgid="1597989540662710653">"選取要新增的按鈕"</string>
- <string name="add_button" msgid="4134946063432258161">"新增按鈕"</string>
<string name="save" msgid="2311877285724540644">"儲存"</string>
<string name="reset" msgid="2448168080964209908">"重設"</string>
- <string name="no_home_title" msgid="1563808595146071549">"找不到「主畫面」按鈕"</string>
- <string name="no_home_message" msgid="5408485011659260911">"您必須設定「主畫面」按鈕才能操作這部裝置。請先新增「主畫面」按鈕再儲存。"</string>
<string name="adjust_button_width" msgid="6138616087197632947">"調整按鈕寬度"</string>
<string name="clipboard" msgid="1313879395099896312">"剪貼簿"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"您可以利用「剪貼簿」按鈕將所需項目直接拖曳到剪貼簿中,或是將剪貼簿中的項目直接拖曳出來。"</string>
<string name="accessibility_key" msgid="5701989859305675896">"自訂導覽按鈕"</string>
<string name="keycode" msgid="7335281375728356499">"按鍵碼"</string>
- <string name="keycode_description" msgid="1403795192716828949">"您可以利用「按鍵碼」按鈕將鍵盤按鍵加到導覽列。只要按下這些按鈕,即可執行與所選鍵盤按鍵對應的操作。如要使用這項功能,請先為按鈕選取要模擬的鍵盤按鍵,然後指定按鈕的顯示圖示。"</string>
- <string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鍵"</string>
- <string name="preview" msgid="9077832302472282938">"預覽"</string>
+ <string name="icon" msgid="8732339849035837289">"圖示"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳到這裡即可移除"</string>
<string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"關閉"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"手機變熱"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"手機降溫時,部分功能會受限"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"左側"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"右側"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"自訂捷徑"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"捷徑"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"提示輸入密碼"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"快訊"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 0723e7e3f306..78589627d6e7 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -321,12 +321,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Imodi yomsebenzi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ukukhanya kwasebusuku"</string>
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"I-NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"I-NFC ikhutshaziwe"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"I-NFC inikwe amandla"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Azikho izinto zakamuva"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Usule yonke into"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
@@ -340,16 +337,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
- <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
- <skip />
- <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Hlukanisela isikrini phezulu"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Hlukanisela isikrini ngakwesokunxele"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Hlukanisela isikrini ngakwesokudla"</string>
<string-array name="recents_blacklist_array">
</string-array>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
@@ -430,24 +420,20 @@
<string name="disconnect_vpn" msgid="1324915059568548655">"Nqamula i-VPN"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Idivayisi yakho iphethwe yi-<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"I-<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> isebenzisa i-<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ukuze iphathe idivayisi yakho."</string>
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"Umlawuli wakho angaqaphela aphinde aphathe izilungiselelo, ukufinyelela kwezinkampani, izinhlelo zokusebenza, idatha ehlotshaniswa nedivayisi yakho, nolwazi lwendawo yedivayisi yakho."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Funda kabanzi"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Uxhumeke ku-<xliff:g id="VPN_APP">%1$s</xliff:g>, engaqapha umsebenzi wenethiwekhi yakho, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Vula izilungiselelo ze-VPN"</string>
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Umlawuli wakho uvule ukungena kwenethiwekhi, okuhlola ithrafikhi kudivayisi yakho.\n\nNgolwazi olubanzi xhumana nomlawuli wakho."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Unikeze uhlelo lokusebenza imvume yokusetha ukuxhumana kwe-VPN.\n\nLolu hlelo lokusebenza lungahlola idivayisi yakho nomsebenzi wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Iphrofayela yakho yomsebenzi iphethwe ngu-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmlawuli wakho uyakwazi ukwengamela umsebenzi wakho wenethiwekhi kufaka phakathi ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nNgolwazi olubanzi, xhumana nomlawuli wakho.\n\nFuthi uxhumekile ku-VPN, engangamela umsebenzi wakho wenethiwekhi."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"I-VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wakho wenethiwekhi ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho womuntu siqu wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
- <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
- <skip />
+ <string name="monitoring_description_app_work" msgid="7777228449969022305">"Iphrofayela yakho yomsebenzi iphethwe ngu-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engangamela umsebenzi wakho wenethiwekhi, kufaka phakathi ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nNgolwazi olubanzi, xhumana nomlawuli wakho."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomsebenzi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Idivayisi izohlala ikhiyekile uze uyivule ngokwenza"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Thola izaziso ngokushesha"</string>
@@ -540,7 +526,15 @@
<string name="notification_importance_high" msgid="3316555356062640222">"Yenza umsindo ne-pop kusikrini"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
<string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
- <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> izilawuli zasaziso"</string>
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"izilawuli zesaziso"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"izinketho zokusnuza zesaziso"</string>
+ <string name="snooze_option_15_min" msgid="1068727451405610715">"15 amaminithi"</string>
+ <string name="snooze_option_30_min" msgid="867081342535195788">"30 amaminithi"</string>
+ <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ihora"</string>
+ <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Ungasnuzi"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"HLEHLISA"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"Kusnuzwe u-<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Ukusetshenziswa kwebhethri"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Isilondolozi sebhethri asitholakali ngesikhathi sokushaja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Isilondolozi sebhethri"</string>
@@ -602,25 +596,31 @@
<string name="switch_bar_on" msgid="1142437840752794229">"Vuliwe"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"Valiwe"</string>
<string name="nav_bar" msgid="1993221402773877607">"Ibha yokuzula"</string>
- <string name="start" msgid="6873794757232879664">"Qala"</string>
- <string name="center" msgid="4327473927066010960">"Maphakathi"</string>
- <string name="end" msgid="125797972524818282">"Phelisa"</string>
- <string name="space" msgid="804232271282109749">"Okwenza isikhala"</string>
+ <string name="nav_bar_layout" msgid="3664072994198772020">"Isakhiwo"</string>
+ <string name="nav_bar_left" msgid="731491280511316123">"Kwesobunxele"</string>
+ <string name="nav_bar_right" msgid="2523774879720231974">"Kwesokudla"</string>
+ <string name="nav_bar_button_type" msgid="6947806619897153791">"Uhlobo lwenkinobho"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(okuzenzakalelayo)"</string>
+ <string-array name="nav_bar_buttons">
+ <item msgid="1545641631806817203">"Ibhodi lokumanathisela"</item>
+ <item msgid="5742013440802239414">"Ikhodi yokhiye"</item>
+ <item msgid="8748101184830239843">"Isishintshi semenyu / sekhibhodi"</item>
+ <item msgid="8175437057325747277">"Akunalutho"</item>
+ </string-array>
+ <string-array name="nav_bar_layouts">
+ <item msgid="4967898371682516967">"Kwehlukanisiwe (okuzenzakalelayo)"</item>
+ <item msgid="6210279084134579668">"Maphakathi"</item>
+ <item msgid="89143234390889289">"Kuqondaniswe kwesokunxele"</item>
+ <item msgid="7715533883382410603">"Kuqondaniswe kwesokudla"</item>
+ </string-array>
<string name="menu_ime" msgid="4943221416525250684">"Isishintshi semenyu / sekhibhodi"</string>
- <string name="select_button" msgid="1597989540662710653">"Khetha inkinobho ongayengeza"</string>
- <string name="add_button" msgid="4134946063432258161">"Inkinobho yokwengeza"</string>
<string name="save" msgid="2311877285724540644">"Londoloza"</string>
<string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
- <string name="no_home_title" msgid="1563808595146071549">"Ayikho inkinobho yasekhaya etholakele"</string>
- <string name="no_home_message" msgid="5408485011659260911">"Inkinobho yasekhaya iyadingeka ukuthi inikwe amandla ukuze uzule kule divayisi. Sicela ungeze inkinobho yasekhaya ngaphambi kokulondoloza."</string>
<string name="adjust_button_width" msgid="6138616087197632947">"Lungisa ububanzi benkinobho"</string>
<string name="clipboard" msgid="1313879395099896312">"Ibhodi lokunamathisela"</string>
- <string name="clipboard_description" msgid="3819919243940546364">"Ibhodi lokunamathisela livumela izinto ukuthi zihudulelwe ngqo ebhodini lokunamathisela. Izinto zingahudulelwa ngqo ngaphandle kwebhodi lokunamathisela uma zikhona."</string>
<string name="accessibility_key" msgid="5701989859305675896">"Inkinobho yokuzula yangokwezifiso"</string>
<string name="keycode" msgid="7335281375728356499">"Ikhodi yokhiye"</string>
- <string name="keycode_description" msgid="1403795192716828949">"Izinkinobho zebhodi yokhiye zivumela okhiye bekhibhodi ukuthi bangezwe kwibha yokuzula. Uma zicindezelwa zisula ukhiye wekhibhodi okhethiwe. Kokuqala ukhiye kufanele ukhethelwe inkinobho, ulandelwe isithombe esizoboniswa kwinkinobho."</string>
- <string name="select_keycode" msgid="7413765103381924584">"Khetha inkinobho yekhibhodi"</string>
- <string name="preview" msgid="9077832302472282938">"Hlola kuqala"</string>
+ <string name="icon" msgid="8732339849035837289">"Isithonjana"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Hudula ukuze ungeze amathayili"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Hudulela lapha ukuze ususe"</string>
<string name="qs_edit" msgid="2232596095725105230">"Hlela"</string>
@@ -671,8 +671,18 @@
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Nciphisa"</string>
- <string name="pip_phone_dismiss" msgid="1305916715402775904">"Cashisa"</string>
+ <!-- no translation found for pip_phone_close (8416647892889710330) -->
+ <skip />
<string name="high_temp_title" msgid="4589508026407318374">"Ifoni iyafudumala"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
+ <string name="lockscreen_left" msgid="6806490081187499505">"Kwesobunxele"</string>
+ <string name="lockscreen_right" msgid="6093496261656102989">"Kwesokudla"</string>
+ <string name="lockscreen_customize" msgid="1288691376862981950">"Yenza ngezifiso isinqamuleli"</string>
+ <string name="lockscreen_shortcut" msgid="3734369277470360642">"Isinqamulelo"</string>
+ <string name="lockscreen_unlock" msgid="4934466194763269051">"Yalela iphasiwedi"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"Izexwayiso"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Izithombe-skrini"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"Imilayezo ejwayelekile"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"Isitoreji"</string>
</resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
deleted file mode 100644
index bf0cba22ab0c..000000000000
--- a/packages/SystemUI/res/values/arrays.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR 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">
-
- <!-- BatteryMeterView parameters -->
- <array name="batterymeter_color_levels">
- <item>15</item>
- <item>100</item>
- </array>
- <array name="batterymeter_color_values">
- <item>@*android:color/battery_saver_mode_color</item>
- <item>#FFFFFFFF</item>
- </array>
- <array name="batterymeter_bolt_points">
- <item>73</item> <item>0</item>
- <item>392</item><item>0</item>
- <item>201</item><item>259</item>
- <item>442</item><item>259</item>
- <item>4</item> <item>703</item>
- <item>157</item><item>334</item>
- <item>0</item> <item>334</item>
- </array>
- <array name="batterymeter_plus_points">
- <item>3</item><item>0</item>
- <item>5</item><item>0</item>
- <item>5</item><item>3</item>
- <item>8</item><item>3</item>
- <item>8</item><item>5</item>
- <item>5</item><item>5</item>
- <item>5</item><item>8</item>
- <item>3</item><item>8</item>
- <item>3</item><item>5</item>
- <item>0</item><item>5</item>
- <item>0</item><item>3</item>
- <item>3</item><item>3</item>
- </array>
-</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 7fb513cda395..7632f87e7c78 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -115,5 +115,9 @@
<declare-styleable name="PluginInflateContainer">
<attr name="viewType" format="string" />
</declare-styleable>
+ <declare-styleable name="ScrimView">
+ <!-- The initial color for the scrim. -->
+ <attr name="scrimColor" format="color" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 30408143e30d..1249f44cfabf 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -26,9 +26,6 @@
<drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
<color name="notification_list_shadow_top">#80000000</color>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
- <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
- <color name="batterymeter_charge_color">#FFFFFFFF</color>
- <color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="system_warning_color">@*android:color/system_error</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
@@ -36,6 +33,7 @@
<color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
<color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_detail_transition">#66FFFFFF</color>
+ <color name="scrim_behind_color">@android:color/black</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
<color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
<color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
@@ -103,6 +101,10 @@
<color name="notification_guts_icon_tint">#8a000000</color>
<color name="notification_guts_disabled_icon_tint">#4d000000</color>
+ <!-- Colors of the snooze menu reached via snooze icon behind a notification -->
+ <color name="snooze_snackbar_bg">#FF4A4A4A</color>
+ <color name="snooze_snackbar_text">#FFA6BAFF</color>
+
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d6ed9d8092ca..64cac3c001d1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -43,7 +43,7 @@
<!-- Component to be used as the status bar service. Must implement the IStatusBar
interface. This name is in the ComponentName flattened format (package/class) -->
- <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
+ <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
@@ -106,7 +106,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane
+ wifi,cell,bt,dnd,flashlight,rotation,battery,airplane
</string>
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
@@ -286,7 +286,7 @@
<string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
<!-- Nav bar button default ordering/layout -->
- <string name="config_navBarLayout" translatable="false">space,back;home;recent,menu_ime</string>
+ <string name="config_navBarLayout" translatable="false">left,back;home;recent,right</string>
<bool name="quick_settings_show_full_alarm">false</bool>
@@ -301,7 +301,35 @@
<item type="id" name="action_split_task_to_left" />
<item type="id" name="action_split_task_to_right" />
<item type="id" name="action_split_task_to_top" />
- <item type="id" name="action_open" />
- <item type="id" name="action_dimiss" />
+
+ <!-- Whether or not the gear icon on notifications should be shown. The gear is shown when the
+ the notification is not swiped enough to dismiss it. -->
+ <bool name="config_showNotificationGear">true</bool>
+
+ <!-- Whether or not a background should be drawn behind a notification. -->
+ <bool name="config_drawNotificationBackground">true</bool>
+
+ <!-- Whether or not the edit icon on the quick settings header is shown. -->
+ <bool name="config_showQuickSettingsEditingIcon">true</bool>
+
+ <!-- Whether or not the multi-user switcher should be visible even if the quick settings are
+ not expanded. If there are not multiple users on the system, the switcher will still
+ hide itself. -->
+ <bool name="config_alwaysShowMultiUserSwitcher">false</bool>
+
+ <!-- Whether or not the expand indicator is visible for manually expanding the quick settings
+ panel. -->
+ <bool name="config_showQuickSettingsExpandIndicator">true</bool>
+
+ <!-- Whether or not to display the row of quick settings icons separate from the full quick
+ settings panel. -->
+ <bool name="config_showQuickSettingsRow">true</bool>
+
+ <!-- Whether or not the quick settings should be revealed on an overscroll of the
+ notifications panel. -->
+ <bool name="config_enableQuickSettingsOverscrollExpansion">true</bool>
+
+ <!-- Whether or the notifications can be shown and dismissed with a drag. -->
+ <bool name="config_enableNotificationShadeDrag">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79529a7abcbc..e69c4a3ed22b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -69,6 +69,9 @@
<!-- Height of a small notification in the status bar-->
<dimen name="notification_min_height">92dp</dimen>
+ <!-- Height of a small notification in the status bar if it is a large (like messaging)-->
+ <dimen name="notification_min_height_large">132dp</dimen>
+
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
@@ -106,11 +109,20 @@
<!-- Minimum layouted height of a notification in the statusbar-->
<dimen name="min_notification_layout_height">48dp</dimen>
- <!-- Width of the space containing the gear icon behind a notification -->
- <dimen name="notification_gear_width">64dp</dimen>
+ <!-- Size of the space to place a notification menu item -->
+ <dimen name="notification_menu_icon_size">64dp</dimen>
+
+ <!-- The space around a notification menu item -->
+ <dimen name="notification_menu_icon_padding">20dp</dimen>
+
+ <!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
+ <dimen name="snooze_snackbar_min_height">48dp</dimen>
- <!-- The space around the gear icon displayed behind a notification -->
- <dimen name="notification_gear_padding">20dp</dimen>
+ <!-- The text size of options in the snooze menu. -->
+ <dimen name="snooze_option_text_size">14sp</dimen>
+
+ <!-- The padding around options int the snooze menu. -->
+ <dimen name="snooze_option_padding">8dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dp</dimen>
@@ -338,6 +350,8 @@
<dimen name="keyguard_clock_notifications_margin_max">42dp</dimen>
<dimen name="heads_up_scrim_height">250dp</dimen>
+ <item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
+
<!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
<dimen name="keyguard_min_swipe_amount">110dp</dimen>
@@ -506,14 +520,6 @@
<!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
<dimen name="double_tap_slop">32dp</dimen>
- <!-- Margin on the right side of the system icon group on Keyguard. -->
- <fraction name="battery_button_height_fraction">10.5%</fraction>
-
- <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
- fraction of a pixel.-->
- <fraction name="battery_subpixel_smoothing_left">0%</fraction>
- <fraction name="battery_subpixel_smoothing_right">0%</fraction>
-
<dimen name="battery_margin_bottom">0dp</dimen>
<!-- Padding at the end of the view that displays the mobile signal icons. If the view is
@@ -628,9 +634,6 @@
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
- <dimen name="battery_height">14.5dp</dimen>
- <dimen name="battery_width">9.5dp</dimen>
-
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml
index 5858443f6d8d..febf65b834ee 100644
--- a/packages/SystemUI/res/values/dimens_grid.xml
+++ b/packages/SystemUI/res/values/dimens_grid.xml
@@ -22,6 +22,7 @@
<dimen name="recents_grid_task_view_header_height">44dp</dimen>
<dimen name="recents_grid_task_view_header_button_padding">8dp</dimen>
<dimen name="recents_grid_task_view_focused_frame_thickness">8dp</dimen>
- <dimen name="recents_grid_task_view_rounded_corners_radius">8dp</dimen>
+ <dimen name="recents_grid_task_view_rounded_corners_radius">4dp</dimen>
+ <dimen name="recents_grid_task_view_focused_frame_rounded_corners_radius">8dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 4a19dde44536..fc0c82cd54d2 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -58,7 +58,6 @@
<item type="id" name="transformation_start_y_tag"/>
<item type="id" name="transformation_start_scale_x_tag"/>
<item type="id" name="transformation_start_scale_y_tag"/>
- <item type="id" name="custom_background_color"/>
<!-- Whether the icon is from a notification for which targetSdk < L -->
<item type="id" name="icon_is_pre_L"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 422431e7b31a..f7cf444d2350 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -207,6 +207,8 @@
<string name="accessibility_home">Home</string>
<!-- Content description of the menu button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_menu">Menu</string>
+ <!-- Content description of the accessibility button in the navigation bar (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_accessibility_button">Accessibility</string>
<!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_recent">Overview</string>
<!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
@@ -794,10 +796,6 @@
<string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
<!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
- <!-- Recents: Accessibility dismiss label -->
- <string name="recents_accessibility_dismissed">Dismiss</string>
- <!-- Recents: Accessibility open label -->
- <string name="recents_accessibility_open">Open</string>
<!-- Recents: Accessibility split to the top -->
<string name="recents_accessibility_split_screen_top">Split screen to the top</string>
<!-- Recents: Accessibility split to the left -->
@@ -821,9 +819,6 @@
<!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
<string name="expanded_header_battery_not_charging">Not charging</string>
- <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
- <string name="battery_meter_very_low_overlay_symbol">!</string>
-
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted.
If the text fits on one line (~14 chars), it should start with a
@@ -1375,8 +1370,28 @@
<!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
<string name="notification_done">Done</string>
- <!-- Notification: Gear: Content description for the gear. [CHAR LIMIT=NONE] -->
- <string name="notification_gear_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> notification controls</string>
+ <!-- Notification: Menu row: Content description for menu items. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> <xliff:g id="menu_description" example="notification controls">%2$s</xliff:g></string>
+
+ <!-- Notification: Menu row: Content description for the gear menu item. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_gear_description">notification controls</string>
+
+ <!-- Notification: Menu row: Content description for the snooze icon. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_snooze_description">notification snooze options</string>
+
+ <!-- Notification: Menu row: Snooze options: 15 minute option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_15_min">15 minutes</string>
+ <!-- Notification: Menu row: Snooze options: 30 minute option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_30_min">30 minutes</string>
+ <!-- Notification: Menu row: Snooze options: 1 hour option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_1_hour">1 hour</string>
+ <!-- Notification: Menu row: Snooze options: don't snooze option. [CHAR LIMIT=50] -->
+ <string name="snooze_option_dont_snooze">Don\'t snooze</string>
+ <!-- Notification: Menu row: Snooze undo button label. [CHAR LIMIT=50]-->
+ <string name="snooze_undo">UNDO</string>
+
+ <!-- Notification: Menu row: Snooze: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
+ <string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
<!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
<string name="battery_panel_title">Battery usage</string>
@@ -1523,56 +1538,71 @@
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
- <!-- SysUI Tuner: Group of buttons that show on the start of the screen [CHAR LIMIT=30] -->
- <string name="start">Start</string>
- <!-- SysUI Tuner: Group of buttons that show on the center of the screen [CHAR LIMIT=30] -->
- <string name="center">Center</string>
- <!-- SysUI Tuner: Group of buttons that show on the end of the screen [CHAR LIMIT=30] -->
- <string name="end">End</string>
- <!-- SysUI Tuner: Name of space used in custom navigation bar layouts [CHAR LIMIT=30] -->
- <string name="space">Spacer</string>
+ <!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
+ <string name="nav_bar_layout">Layout</string>
+
+ <!-- SysUI Tuner: Label for section of settings about the left nav button [CHAR LIMIT=60] -->
+ <string name="nav_bar_left">Left</string>
+
+ <!-- SysUI Tuner: Label for section of settings about the right nav button [CHAR LIMIT=60] -->
+ <string name="nav_bar_right">Right</string>
+
+ <!-- SysUI Tuner: Setting for button type in nav bar [CHAR LIMIT=60] -->
+ <string name="nav_bar_button_type">Button type</string>
+
+ <!-- SysUI Tuner: Added to nav bar option to indicate it is the default [CHAR LIMIT=60] -->
+ <string name="nav_bar_default"> (default)</string>
+
+ <!-- SysUI Tuner: Labels for different types of navigation bar buttons [CHAR LIMIT=60] -->
+ <string-array name="nav_bar_buttons">
+ <item>Clipboard</item>
+ <item>Keycode</item>
+ <item>Menu / Keyboard Switcher</item>
+ <item>None</item>
+ </string-array>
+ <string-array name="nav_bar_button_values" translatable="false">
+ <item>clipboard</item>
+ <item>key</item>
+ <item>menu_ime</item>
+ <item>space</item>
+ </string-array>
+
+ <!-- SysUI Tuner: Labels for different types of navigation bar layouts [CHAR LIMIT=60] -->
+ <string-array name="nav_bar_layouts">
+ <item>Divided (default)</item>
+ <item>Centered</item>
+ <item>Left-aligned</item>
+ <item>Right-aligned</item>
+ </string-array>
+
+ <string-array name="nav_bar_layouts_values" translatable="false">
+ <item>default</item>
+ <item>left;back,home,recent;right</item>
+ <item>left,back,home,recent,right;space;space</item>
+ <item>space;space;left,back,home,recent,right</item>
+ </string-array>
+
<!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
<string name="menu_ime">Menu / Keyboard Switcher</string>
- <!-- SysUI Tuner: Title for dialog to add a button [CHAR LIMIT=30] -->
- <string name="select_button">Select button to add</string>
- <!-- SysUI Tuner: Button to add a button [CHAR LIMIT=30] -->
- <string name="add_button">Add button</string>
<!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
<string name="save">Save</string>
<!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
<string name="reset">Reset</string>
- <!-- SysUI Tuner: Title of no home warning dialog [CHAR LIMIT=30] -->
- <string name="no_home_title">No home button found</string>
- <!-- SysUI Tuner: Message of no home warning dialog [CHAR LIMIT=NONE] -->
- <string name="no_home_message">A home button is required to be able to navigate this device. Please add a home button before saving.</string>
-
<!-- SysUI Tuner: Adjust button width dialog title [CHAR LIMIT=60] -->
<string name="adjust_button_width">Adjust button width</string>
<!-- SysUI Tuner: Nav bar button that holds the clipboard [CHAR LIMIT=30] -->
<string name="clipboard">Clipboard</string>
- <!-- SysUI Tuner: Description of nav bar button that holds the clipboard [CHAR LIMIT=NONE] -->
- <string name="clipboard_description">The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present.</string>
-
<!-- SysUI Tuner: Accessibility description for custom nav key [CHAR LIMIT=NONE] -->
<string name="accessibility_key">Custom navigation button</string>
<!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
<string name="keycode">Keycode</string>
- <!-- SysUI Tuner: Description of nav bar button that emulates a keycode [CHAR LIMIT=NONE] -->
- <string name="keycode_description">Keycode buttons allow keyboard keys to
- be added to the Navigation Bar. When pressed they emulate the selected
- keyboard key. First the key must be selected for the button, followed
- by an image to be shown on the button.</string>
-
- <!-- SysUI Tuner: Title of dialog to select which key to emulate [CHAR LIMIT=60] -->
- <string name="select_keycode">Select Keyboard Button</string>
-
- <!-- SysUI Tuner: Label for preview area in navigation bar tuner [CHAR LIMIT=NONE] -->
- <string name="preview">Preview</string>
+ <!-- SysUI Tuner: Settings to change nav bar icon [CHAR LIMIT=30] -->
+ <string name="icon">Icon</string>
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
@@ -1715,8 +1745,8 @@
<!-- Label for PIP action to Minimize the PIP [CHAR LIMIT=25] -->
<string name="pip_phone_minimize">Minimize</string>
- <!-- Label for PIP action to Dismiss the PIP -->
- <string name="pip_phone_dismiss">Dismiss</string>
+ <!-- Label for PIP the drag to close zone [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_close">Close</string>
<!-- PIP section of the tuner. Non-translatable since it should
not appear on production builds ever. -->
@@ -1730,14 +1760,6 @@
not appear on production builds ever. -->
<string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
- <!-- PIP allow minimize title. Non-translatable since it should
- not appear on production builds ever. -->
- <string name="pip_allow_minimize_title" translatable="false">Allow PIP to minimize</string>
-
- <!-- PIP allow minimize description. Non-translatable since it should
- not appear on production builds ever. -->
- <string name="pip_allow_minimize_summary" translatable="false">Allow PIP to minimize slightly offscreen</string>
-
<!-- Tuner string -->
<string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
<!-- Tuner string -->
@@ -1752,5 +1774,28 @@
<!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
<string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+ <!-- SysUI Tuner: Group of settings for left lock screen affordance [CHAR LIMIT=60] -->
+ <string name="lockscreen_left">Left</string>
+
+ <!-- SysUI Tuner: Group of settings for right lock screen affordance [CHAR LIMIT=60] -->
+ <string name="lockscreen_right">Right</string>
+
+ <!-- SysUI Tuner: Switch controlling whether to customize lock screen button [CHAR LIMIT=60] -->
+ <string name="lockscreen_customize">Customize shortcut</string>
+
+ <!-- SysUI Tuner: Button to select lock screen shortcut [CHAR LIMIT=60] -->
+ <string name="lockscreen_shortcut">Shortcut</string>
+
+ <!-- SysUI Tuner: Switch to control if device gets unlocked [CHAR LIMIT=60] -->
+ <string name="lockscreen_unlock">Prompt for password</string>
+
+ <!-- Title for the notification channel containing important alerts like low battery. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_alerts">Alerts</string>
+ <!-- Title for the notification channel dedicated to screenshot progress. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_screenshot">Screenshots</string>
+ <!-- Title for the notification channel for miscellaneous notices. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_general">General Messages</string>
+ <!-- Title for the notification channel for problems with storage (i.e. low disk). [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_storage">Storage</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 6535a81d076b..c5a5518226d9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -383,6 +383,20 @@
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
+ <style name="TextAppearance.SnoozeSnackBar">
+ <item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">roboto-regular</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+
+ <style name="TextAppearance.SnoozeSnackBar.Button">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">@color/snooze_snackbar_text</item>
+ </style>
+
<style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
diff --git a/packages/SystemUI/res/xml/lockscreen_settings.xml b/packages/SystemUI/res/xml/lockscreen_settings.xml
new file mode 100644
index 000000000000..73e29af42821
--- /dev/null
+++ b/packages/SystemUI/res/xml/lockscreen_settings.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/other">
+
+ <PreferenceCategory
+ android:key="left"
+ android:title="@string/lockscreen_left">
+
+ <SwitchPreference
+ android:key="customize"
+ android:title="@string/lockscreen_customize" />
+
+ <Preference
+ android:key="shortcut"
+ android:title="@string/lockscreen_shortcut" />
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_keyguard_left_unlock"
+ android:title="@string/lockscreen_unlock"
+ sysui:defValue="true" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="right"
+ android:title="@string/lockscreen_right">
+
+ <SwitchPreference
+ android:key="customize"
+ android:title="@string/lockscreen_customize" />
+
+ <Preference
+ android:key="shortcut"
+ android:title="@string/lockscreen_shortcut" />
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_keyguard_right_unlock"
+ android:title="@string/lockscreen_unlock"
+ sysui:defValue="true" />
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/nav_bar_tuner.xml b/packages/SystemUI/res/xml/nav_bar_tuner.xml
new file mode 100644
index 000000000000..6fa8bec3a937
--- /dev/null
+++ b/packages/SystemUI/res/xml/nav_bar_tuner.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/nav_bar">
+
+ <ListPreference
+ android:key="layout"
+ android:title="@string/nav_bar_layout"
+ android:summary="%s"
+ android:persistent="false"
+ android:entries="@array/nav_bar_layouts"
+ android:entryValues="@array/nav_bar_layouts_values" />
+
+ <PreferenceCategory
+ android:key="left"
+ android:title="@string/nav_bar_left">
+
+ <DropDownPreference
+ android:key="type_left"
+ android:title="@string/nav_bar_button_type"
+ android:persistent="false"
+ android:summary="%s"
+ android:entries="@array/nav_bar_buttons"
+ android:entryValues="@array/nav_bar_button_values" />
+
+ <Preference
+ android:key="keycode_left"
+ android:persistent="false"
+ android:title="@string/keycode" />
+
+ <com.android.systemui.tuner.BetterListPreference
+ android:key="icon_left"
+ android:persistent="false"
+ android:summary="%s"
+ android:title="@string/icon" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="right"
+ android:title="@string/nav_bar_right">
+
+ <DropDownPreference
+ android:key="type_right"
+ android:title="@string/nav_bar_button_type"
+ android:summary="%s"
+ android:persistent="false"
+ android:entries="@array/nav_bar_buttons"
+ android:entryValues="@array/nav_bar_button_values" />
+
+ <Preference
+ android:key="keycode_right"
+ android:persistent="false"
+ android:title="@string/keycode" />
+
+ <com.android.systemui.tuner.BetterListPreference
+ android:key="icon_right"
+ android:persistent="false"
+ android:summary="%s"
+ android:title="@string/icon" />
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index 18cb9306b1b6..7719d5e03df0 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -23,10 +23,5 @@
android:key="power_notification_controls"
android:title="@string/tuner_full_importance_settings"
android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
-e
- <com.android.systemui.tuner.ThemePreference
- android:key="theme"
- android:title="@string/theme"
- android:summary="%s" />
</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 59a10dabe967..6198ab7a3b73 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -131,12 +131,6 @@
android:summary="@string/pip_drag_to_dismiss_summary"
sysui:defValue="false" />
- <com.android.systemui.tuner.TunerSwitch
- android:key="pip_allow_minimize"
- android:title="@string/pip_allow_minimize_title"
- android:summary="@string/pip_allow_minimize_summary"
- sysui:defValue="true" />
-
</PreferenceScreen>
<PreferenceScreen
@@ -150,12 +144,15 @@
</PreferenceScreen>
- <!--
<Preference
android:key="nav_bar"
android:title="@string/nav_bar"
android:fragment="com.android.systemui.tuner.NavBarTuner" />
- -->
+
+ <Preference
+ android:key="lockscreen"
+ android:title="@string/accessibility_desc_lock_screen"
+ android:fragment="com.android.systemui.tuner.LockscreenFragment" />
<Preference
android:key="other"
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 4ae81a7017c9..14c67fe8a9ad 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -19,7 +19,7 @@ import android.content.Intent;
/**
* Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
- * delegates to an actual implementation such as PhoneStatusBar, assuming it exists.
+ * delegates to an actual implementation such as StatusBar, assuming it exists.
*/
public class ActivityStarterDelegate implements ActivityStarter {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 5a6afca627ec..2bdb2f33a37e 100755..100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -16,193 +16,24 @@
package com.android.systemui;
-import android.animation.ArgbEvaluator;
-import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.database.ContentObserver;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
-
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.statusbar.policy.BatteryController;
-public class BatteryMeterDrawable extends Drawable implements
+public class BatteryMeterDrawable extends BatteryMeterDrawableBase implements
BatteryController.BatteryStateChangeCallback {
- private static final float ASPECT_RATIO = 9.5f / 14.5f;
- public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
- public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
-
- private static final boolean SINGLE_DIGIT_PERCENT = false;
-
- private static final int FULL = 96;
-
- private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
-
- private final int[] mColors;
- private final int mIntrinsicWidth;
- private final int mIntrinsicHeight;
-
- private boolean mShowPercent;
- private float mButtonHeightFraction;
- private float mSubpixelSmoothingLeft;
- private float mSubpixelSmoothingRight;
- private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
- mPlusPaint;
- private float mTextHeight, mWarningTextHeight;
- private int mIconTint = Color.WHITE;
- private float mOldDarkIntensity = 0f;
-
- private int mHeight;
- private int mWidth;
- private String mWarningString;
- private final int mCriticalLevel;
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
- private final float[] mPlusPoints;
- private final Path mPlusPath = new Path();
-
- private final RectF mFrame = new RectF();
- private final RectF mButtonFrame = new RectF();
- private final RectF mBoltFrame = new RectF();
- private final RectF mPlusFrame = new RectF();
-
- private final Path mShapePath = new Path();
- private final Path mClipPath = new Path();
- private final Path mTextPath = new Path();
-
private BatteryController mBatteryController;
- private boolean mPowerSaveEnabled;
-
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
-
- private final SettingObserver mSettingObserver;
-
- private final Context mContext;
-
- private int mLevel = -1;
- private boolean mPluggedIn;
- private boolean mListening;
+ private SettingObserver mSettingObserver;
public BatteryMeterDrawable(Context context, int frameColor) {
- mContext = context;
- mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
- final Resources res = context.getResources();
- TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
- TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
-
- final int N = levels.length();
- mColors = new int[2*N];
- for (int i=0; i<N; i++) {
- mColors[2*i] = levels.getInt(i, 0);
- mColors[2*i+1] = colors.getColor(i, 0);
- }
- levels.recycle();
- colors.recycle();
- updateShowPercent();
- mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
- mCriticalLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_criticalBatteryWarningLevel);
- mButtonHeightFraction = context.getResources().getFraction(
- R.fraction.battery_button_height_fraction, 1, 1);
- mSubpixelSmoothingLeft = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_left, 1, 1);
- mSubpixelSmoothingRight = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_right, 1, 1);
-
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(frameColor);
- mFramePaint.setDither(true);
- mFramePaint.setStrokeWidth(0);
- mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBatteryPaint.setDither(true);
- mBatteryPaint.setStrokeWidth(0);
- mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mWarningTextPaint.setColor(mColors[1]);
- font = Typeface.create("sans-serif", Typeface.BOLD);
- mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
-
- mPlusPaint = new Paint(mBoltPaint);
- mPlusPoints = loadPlusPoints(res);
-
- mDarkModeBackgroundColor =
- context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
- mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
- mLightModeBackgroundColor =
- context.getColor(R.color.light_mode_icon_color_dual_tone_background);
- mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
-
- mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
- mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mIntrinsicHeight;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mIntrinsicWidth;
- }
-
- public void startListening() {
- mListening = true;
- mContext.getContentResolver().registerContentObserver(
- Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
- updateShowPercent();
- mBatteryController.addCallback(this);
- }
-
- public void stopListening() {
- mListening = false;
- mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
- mBatteryController.removeCallback(this);
- }
+ super(context, frameColor);
- public void disableShowPercent() {
- mShowPercent = false;
- postInvalidate();
- }
-
- private void postInvalidate() {
- scheduleSelf(this::invalidateSelf, 0);
- }
-
- public void setBatteryController(BatteryController batteryController) {
- mBatteryController = batteryController;
- mPowerSaveEnabled = mBatteryController.isPowerSave();
+ mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
}
@Override
@@ -219,293 +50,27 @@ public class BatteryMeterDrawable extends Drawable implements
invalidateSelf();
}
- private static float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
+ public void startListening() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+ updateShowPercent();
+ mBatteryController.addCallback(this);
}
- private static float[] loadPlusPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
+ public void stopListening() {
+ mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+ mBatteryController.removeCallback(this);
}
@Override
- public void setBounds(int left, int top, int right, int bottom) {
- super.setBounds(left, top, right, bottom);
- mHeight = bottom - top;
- mWidth = right - left;
- mWarningTextPaint.setTextSize(mHeight * 0.75f);
- mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
- }
-
- private void updateShowPercent() {
+ protected void updateShowPercent() {
mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
SHOW_PERCENT_SETTING, 0);
}
- private int getColorForLevel(int percent) {
-
- // If we are in power save mode, always use the normal color.
- if (mPowerSaveEnabled) {
- return mColors[mColors.length-1];
- }
- int thresh, color = 0;
- for (int i=0; i<mColors.length; i+=2) {
- thresh = mColors[i];
- color = mColors[i+1];
- if (percent <= thresh) {
-
- // Respect tinting for "normal" level
- if (i == mColors.length-2) {
- return mIconTint;
- } else {
- return color;
- }
- }
- }
- return color;
- }
-
- public void setDarkIntensity(float darkIntensity) {
- if (darkIntensity == mOldDarkIntensity) {
- return;
- }
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- setColors(fillColor, backgroundColor);
- mOldDarkIntensity = darkIntensity;
- }
-
- public void setColors(int fillColor, int backgroundColor) {
- mIconTint = fillColor;
- mFramePaint.setColor(backgroundColor);
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
- invalidateSelf();
- }
-
- private int getBackgroundColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
- }
-
- private int getFillColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeFillColor, mDarkModeFillColor);
- }
-
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
- @Override
- public void draw(Canvas c) {
- final int level = mLevel;
-
- if (level == -1) return;
-
- float drawFrac = (float) level / 100f;
- final int height = mHeight;
- final int width = (int) (ASPECT_RATIO * mHeight);
- int px = (mWidth - width) / 2;
-
- final int buttonHeight = (int) (height * mButtonHeightFraction);
-
- mFrame.set(0, 0, width, height);
- mFrame.offset(px, 0);
-
- // button-frame: area above the battery body
- mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
- mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
- mFrame.top + buttonHeight);
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
-
- // frame: battery body area
- mFrame.top += buttonHeight;
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
-
- // set the battery charging color
- mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
-
- if (level >= FULL) {
- drawFrac = 1f;
- } else if (level <= mCriticalLevel) {
- drawFrac = 0f;
- }
-
- final float levelTop = drawFrac == 1f ? mButtonFrame.top
- : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
- // define the battery shape
- mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
- if (mPluggedIn) {
- // define the bolt shape
- final float bl = mFrame.left + mFrame.width() / 4f;
- final float bt = mFrame.top + mFrame.height() / 6f;
- final float br = mFrame.right - mFrame.width() / 4f;
- final float bb = mFrame.bottom - mFrame.height() / 10f;
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
- }
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- }
-
- float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mBoltPath, mBoltPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
- }
- } else if (mPowerSaveEnabled) {
- // define the plus shape
- final float pw = mFrame.width() * 2 / 3;
- final float pl = mFrame.left + (mFrame.width() - pw) / 2;
- final float pt = mFrame.top + (mFrame.height() - pw) / 2;
- final float pr = mFrame.right - (mFrame.width() - pw) / 2;
- final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
- if (mPlusFrame.left != pl || mPlusFrame.top != pt
- || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
- mPlusFrame.set(pl, pt, pr, pb);
- mPlusPath.reset();
- mPlusPath.moveTo(
- mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
- for (int i = 2; i < mPlusPoints.length; i += 2) {
- mPlusPath.lineTo(
- mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
- }
- mPlusPath.lineTo(
- mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
- }
-
- float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mPlusPath, mPlusPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
- }
- }
-
- // compute percentage text
- boolean pctOpaque = false;
- float pctX = 0, pctY = 0;
- String pctText = null;
- if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
- mTextPaint.setColor(getColorForLevel(level));
- mTextPaint.setTextSize(height *
- (SINGLE_DIGIT_PERCENT ? 0.75f
- : (mLevel == 100 ? 0.38f : 0.5f)));
- mTextHeight = -mTextPaint.getFontMetrics().ascent;
- pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- pctX = mWidth * 0.5f;
- pctY = (mHeight + mTextHeight) * 0.47f;
- pctOpaque = levelTop > pctY;
- if (!pctOpaque) {
- mTextPath.reset();
- mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
- // cut the percentage text out of the overall shape
- mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
- }
- }
-
- // draw the battery shape background
- c.drawPath(mShapePath, mFramePaint);
-
- // draw the battery shape, clipped to charging level
- mFrame.top = levelTop;
- mClipPath.reset();
- mClipPath.addRect(mFrame, Path.Direction.CCW);
- mShapePath.op(mClipPath, Path.Op.INTERSECT);
- c.drawPath(mShapePath, mBatteryPaint);
-
- if (!mPluggedIn && !mPowerSaveEnabled) {
- if (level <= mCriticalLevel) {
- // draw the warning text
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (pctOpaque) {
- // draw the percentage text
- c.drawText(pctText, pctX, pctY, mTextPaint);
- }
- }
- }
-
- // Some stuff required by Drawable.
- @Override
- public void setAlpha(int alpha) {
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- mFramePaint.setColorFilter(colorFilter);
- mBatteryPaint.setColorFilter(colorFilter);
- mWarningTextPaint.setColorFilter(colorFilter);
- mTextPaint.setColorFilter(colorFilter);
- mBoltPaint.setColorFilter(colorFilter);
- mPlusPaint.setColorFilter(colorFilter);
- }
-
- @Override
- public int getOpacity() {
- return 0;
+ public void setBatteryController(BatteryController batteryController) {
+ mBatteryController = batteryController;
+ mPowerSaveEnabled = mBatteryController.isPowerSave();
}
private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index b30b5968cd10..29a8da0d421c 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -76,7 +76,7 @@ public class BatteryMeterView extends ImageView implements
mDrawable.setBatteryController(mBatteryController);
mBatteryController.addCallback(this);
mDrawable.startListening();
- TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
}
@Override
@@ -84,7 +84,7 @@ public class BatteryMeterView extends ImageView implements
super.onDetachedFromWindow();
mBatteryController.removeCallback(this);
mDrawable.stopListening();
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 135b12902a25..e1f3176d808e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -14,6 +14,7 @@
package com.android.systemui;
+import android.content.Context;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.HandlerThread;
@@ -23,6 +24,7 @@ import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -56,9 +58,11 @@ import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
+import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.HashMap;
/**
* Class to handle ugly dependencies throughout sysui until we determine the
@@ -167,12 +171,18 @@ public class Dependency extends SystemUI {
mProviders.put(DeviceProvisionedController.class.getName(), () ->
new DeviceProvisionedControllerImpl(mContext));
+ mProviders.put(PluginManager.class.getName(), () ->
+ new PluginManager(mContext));
+
mProviders.put(AssistManager.class.getName(), () ->
new AssistManager(getDependency(DeviceProvisionedController.class), mContext));
mProviders.put(SecurityController.class.getName(), () ->
new SecurityControllerImpl(mContext));
+ mProviders.put(TunerService.class.getName(), () ->
+ new TunerService(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
@@ -220,6 +230,17 @@ public class Dependency extends SystemUI {
T createDependency();
}
+ /**
+ * Used in separate processes (like tuner settings) to init the dependencies.
+ */
+ public static void initDependencies(Context context) {
+ if (sDependency != null) return;
+ Dependency d = new Dependency();
+ d.mContext = context.getApplicationContext();
+ d.mComponents = new HashMap<>();
+ d.start();
+ }
+
public static <T> T get(Class<T> cls) {
return sDependency.getDependency(cls.getName());
}
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
index 9238928de9e2..def3c4072d2e 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
@@ -16,30 +16,46 @@
package com.android.systemui;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
/**
* Constants to be passed as sysui_* eventlog parameters.
*/
public class EventLogConstants {
/** The user swiped up on the lockscreen, unlocking the device. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1;
/** The user swiped down on the lockscreen, going to the full shade. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2;
/** The user tapped in an empty area, causing the unlock hint to be shown. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3;
/** The user swiped inward on the camera icon, launching the camera. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4;
/** The user swiped inward on the dialer icon, launching the dialer. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5;
/** The user tapped the lock, locking the device. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6;
/** The user tapped a notification, needs to tap again to launch. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7;
/** The user swiped down to open quick settings, from keyguard. */
- public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8;
+ private static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8;
/** The user swiped down to open quick settings, from shade. */
- public static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9;
+ private static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9;
/** The user tapped on the status bar to open quick settings, from shade. */
- public static final int SYSUI_TAP_TO_OPEN_QS = 10;
+ private static final int SYSUI_TAP_TO_OPEN_QS = 10;
+
+ public static final int[] METRICS_GESTURE_TYPE_MAP = {
+ MetricsEvent.VIEW_UNKNOWN, // there is no type 0
+ MetricsEvent.ACTION_LS_UNLOCK, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK
+ MetricsEvent.ACTION_LS_SHADE, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE
+ MetricsEvent.ACTION_LS_HINT, // SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT
+ MetricsEvent.ACTION_LS_CAMERA, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA
+ MetricsEvent.ACTION_LS_DIALER, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER
+ MetricsEvent.ACTION_LS_LOCK, // SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK
+ MetricsEvent.ACTION_LS_NOTE, // SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE
+ MetricsEvent.ACTION_LS_QS, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS
+ MetricsEvent.ACTION_SHADE_QS_PULL, // SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS
+ MetricsEvent.ACTION_SHADE_QS_TAP // SYSUI_TAP_TO_OPEN_QS
+ };
/** Secondary user tries binding to the system sysui service */
public static final int SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index c14b17fed60c..1d55ee5ac0d6 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -27,7 +27,7 @@ import android.os.SystemClock;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.LatencyTracker;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
/**
* Class that only runs on debuggable builds that listens to broadcasts that simulate actions in the
@@ -72,7 +72,7 @@ public class LatencyTester extends SystemUI {
}
private void fakeWakeAndUnlock() {
- FingerprintUnlockController fingerprintUnlockController = getComponent(PhoneStatusBar.class)
+ FingerprintUnlockController fingerprintUnlockController = getComponent(StatusBar.class)
.getFingerprintUnlockController();
fingerprintUnlockController.onFingerprintAcquired();
fingerprintUnlockController.onFingerprintAuthenticated(
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index efddf206878e..9cc66138cfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -76,7 +76,7 @@ public class PluginInflateContainer extends AutoReinflateContainer
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mAction != null) {
- PluginManager.getInstance(getContext()).addPluginListener(mAction, this, mVersion);
+ Dependency.get(PluginManager.class).addPluginListener(mAction, this, mVersion);
}
}
@@ -84,7 +84,7 @@ public class PluginInflateContainer extends AutoReinflateContainer
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAction != null) {
- PluginManager.getInstance(getContext()).removePluginListener(this);
+ Dependency.get(PluginManager.class).removePluginListener(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 94b2fdbf5ff8..9b74cd62d06b 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -21,11 +21,10 @@ import android.view.Display;
import android.view.View;
public interface RecentsComponent {
- void showRecents(boolean triggeredFromAltTab, boolean fromHome);
- void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+ void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
+ void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents(Display display);
void preloadRecents();
- void cancelPreloadingRecents();
void showNextAffiliatedTask();
void showPrevAffiliatedTask();
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 5c50b5ce47d9..a95713fb017e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -32,7 +32,9 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.NotificationMenuRow;
import java.util.HashMap;
@@ -85,10 +87,12 @@ public class SwipeHelper implements Gefingerpoken {
private int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
+ private Context mContext;
private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
public SwipeHelper(int swipeDirection, Callback callback, Context context) {
+ mContext = context;
mCallback = callback;
mHandler = new Handler();
mSwipeDirection = swipeDirection;
@@ -249,6 +253,7 @@ public class SwipeHelper implements Gefingerpoken {
}
}
+ @Override
public boolean onInterceptTouchEvent(final MotionEvent ev) {
final int action = ev.getAction();
@@ -280,7 +285,8 @@ public class SwipeHelper implements Gefingerpoken {
mCurrView.getLocationOnScreen(mTmpPos);
final int x = (int) ev.getRawX() - mTmpPos[0];
final int y = (int) ev.getRawY() - mTmpPos[1];
- mLongPressListener.onLongPress(mCurrView, x, y);
+ mLongPressListener.onLongPress(mCurrView, x, y,
+ NotificationMenuRow.getLongpressMenuItem(mContext));
}
}
};
@@ -379,6 +385,7 @@ public class SwipeHelper implements Gefingerpoken {
animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
public void onAnimationUpdate(ValueAnimator animation) {
onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
}
@@ -401,10 +408,12 @@ public class SwipeHelper implements Gefingerpoken {
anim.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
+ @Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
+ @Override
public void onAnimationEnd(Animator animation) {
updateSwipeProgressFromOffset(animView, canBeDismissed);
mDismissPendingMap.remove(animView);
@@ -435,6 +444,7 @@ public class SwipeHelper implements Gefingerpoken {
public void snapChild(final View animView, final float targetLeft, float velocity) {
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
public void onAnimationUpdate(ValueAnimator animation) {
onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
}
@@ -447,6 +457,7 @@ public class SwipeHelper implements Gefingerpoken {
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
+ @Override
public void onAnimationEnd(Animator animator) {
mSnappingChild = false;
updateSwipeProgressFromOffset(animView, canBeDismissed);
@@ -522,6 +533,7 @@ public class SwipeHelper implements Gefingerpoken {
}
}
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
if (mLongPressSent) {
return true;
@@ -690,6 +702,6 @@ public class SwipeHelper implements Gefingerpoken {
* Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
* @return whether the longpress was handled
*/
- boolean onLongPress(View v, int x, int y);
+ boolean onLongPress(View v, int x, int y, MenuItem item);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/SystemBars.java
index 275fd7042715..6623cabe4bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemBars.java
@@ -1,20 +1,18 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under 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.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui;
import android.content.res.Configuration;
import android.provider.Settings;
@@ -36,7 +34,7 @@ public class SystemBars extends SystemUI {
private static final int WAIT_FOR_BARS_TO_DIE = 500;
// in-process fallback implementation, per the product config
- private BaseStatusBar mStatusBar;
+ private SystemUI mStatusBar;
@Override
public void start() {
@@ -71,7 +69,7 @@ public class SystemBars extends SystemUI {
throw andLog("Error loading status bar component: " + clsName, t);
}
try {
- mStatusBar = (BaseStatusBar) cls.newInstance();
+ mStatusBar = (SystemUI) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index f2aaec1dcfad..27070edc73e5 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,10 +42,10 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.SystemBars;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.usb.StorageNotification;
+import com.android.systemui.util.NotificationChannels;
import com.android.systemui.volume.VolumeUI;
import java.util.HashMap;
@@ -65,7 +65,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
private final Class<?>[] SERVICES = new Class[] {
Dependency.class,
FragmentService.class,
- TunerService.class,
+ NotificationChannels.class,
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class,
Recents.class,
@@ -87,6 +87,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
* above.
*/
private final Class<?>[] SERVICES_PER_USER = new Class[] {
+ Dependency.class,
Recents.class,
PipUI.class
};
@@ -204,14 +205,14 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
mServices[i].onBootCompleted();
}
}
- PluginManager.getInstance(this).addPluginListener(OverlayPlugin.ACTION,
+ Dependency.get(PluginManager.class).addPluginListener(OverlayPlugin.ACTION,
new PluginListener<OverlayPlugin>() {
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
- PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
- if (phoneStatusBar != null) {
- plugin.setup(phoneStatusBar.getStatusBarWindow(),
- phoneStatusBar.getNavigationBarView());
+ StatusBar statusBar = getComponent(StatusBar.class);
+ if (statusBar != null) {
+ plugin.setup(statusBar.getStatusBarWindow(),
+ statusBar.getNavigationBarView());
}
}
}, OverlayPlugin.VERSION, true /* Allow multiple plugins */);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 228996a707f1..1ff07010731d 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -26,35 +26,19 @@ import android.view.ViewGroup;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency.DependencyProvider;
-import com.android.systemui.R;
-import com.android.systemui.assist.AssistManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarWindowManager;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.VolumeDialogController;
/**
@@ -111,11 +95,16 @@ public class SystemUIFactory {
}
public NotificationIconAreaController createNotificationIconAreaController(Context context,
- PhoneStatusBar phoneStatusBar) {
- return new NotificationIconAreaController(context, phoneStatusBar);
+ StatusBar statusBar) {
+ return new NotificationIconAreaController(context, statusBar);
}
- public QSTileHost createQSTileHost(Context context, PhoneStatusBar statusBar,
+ public KeyguardIndicationController createKeyguardIndicationController(Context context,
+ ViewGroup indicationArea, LockIcon lockIcon) {
+ return new KeyguardIndicationController(context, indicationArea, lockIcon);
+ }
+
+ public QSTileHost createQSTileHost(Context context, StatusBar statusBar,
StatusBarIconController iconController) {
return new QSTileHost(context, statusBar, iconController);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index aa226181d713..7c15096a5f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui.doze;
+import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
@@ -25,10 +26,7 @@ import android.os.PowerManager;
import android.os.SystemClock;
import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.doze.DozeProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -45,6 +43,7 @@ public class DozeFactory {
Context context = dozeService;
SensorManager sensorManager = context.getSystemService(SensorManager.class);
PowerManager powerManager = context.getSystemService(PowerManager.class);
+ AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
DozeHost host = getHost(dozeService);
AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
@@ -57,7 +56,7 @@ public class DozeFactory {
machine.setParts(new DozeMachine.Part[]{
createDozeTriggers(context, sensorManager, host, config, params, handler, wakeLock,
machine),
- createDozeUi(context, host, wakeLock, machine),
+ createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
});
return machine;
@@ -72,7 +71,7 @@ public class DozeFactory {
}
private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
- DozeMachine machine) {
+ DozeMachine machine, Handler handler, AlarmManager alarmManager) {
if (mDozePlugin != null) {
DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context,
pluginMachine(context, machine, host),
@@ -82,7 +81,7 @@ public class DozeFactory {
pluginState(newState));
};
} else {
- return new DozeUi(context, machine, wakeLock, host);
+ return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 00d229887004..f3fb1efb7dec 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -30,15 +30,12 @@ public interface DozeHost {
void stopDozing();
void dozeTimeTick();
boolean isPowerSaveActive();
- boolean isNotificationLightOn();
boolean isPulsingBlocked();
void startPendingIntentDismissingKeyguard(PendingIntent intent);
interface Callback {
- default void onNewNotifications() {}
default void onNotificationHeadsUp() {}
- default void onNotificationLight(boolean on) {}
default void onPowerSaveChanged(boolean active) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 828728f0ae9e..94dc9a344a34 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -19,6 +19,7 @@ package com.android.systemui.doze;
import android.service.dreams.DreamService;
import android.util.Log;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.doze.DozeProvider;
@@ -47,7 +48,7 @@ public class DozeService extends DreamService implements DozeMachine.Service {
return;
}
- DozeProvider provider = PluginManager.getInstance(this)
+ DozeProvider provider = Dependency.get(PluginManager.class)
.getOneShotPlugin(DozeProvider.ACTION, DozeProvider.VERSION);
mDozeMachine = new DozeFactory(provider).assembleMachine(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 95e49cea62f2..76e0283b0456 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -16,7 +16,13 @@
package com.android.systemui.doze;
+import android.app.AlarmManager;
import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
/**
* The policy controlling doze.
@@ -24,16 +30,25 @@ import android.content.Context;
public class DozeUi implements DozeMachine.Part {
private final Context mContext;
+ private final AlarmManager mAlarmManager;
private final DozeHost mHost;
- private DozeFactory.WakeLock mWakeLock;
- private DozeMachine mMachine;
+ private final Handler mHandler;
+ private final DozeFactory.WakeLock mWakeLock;
+ private final DozeMachine mMachine;
+ private final AlarmManager.OnAlarmListener mTimeTick;
+
+ private boolean mTimeTickScheduled = false;
- public DozeUi(Context context, DozeMachine machine, DozeFactory.WakeLock wakeLock,
- DozeHost host) {
+ public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
+ DozeFactory.WakeLock wakeLock, DozeHost host, Handler handler) {
mContext = context;
+ mAlarmManager = alarmManager;
mMachine = machine;
mWakeLock = wakeLock;
mHost = host;
+ mHandler = handler;
+
+ mTimeTick = this::onTimeTick;
}
private void pulseWhileDozing(int reason) {
@@ -54,6 +69,12 @@ public class DozeUi implements DozeMachine.Part {
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
+ case DOZE_AOD:
+ scheduleTimeTick();
+ break;
+ case DOZE:
+ unscheduleTimeTick();
+ break;
case DOZE_REQUEST_PULSE:
pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */);
break;
@@ -62,7 +83,52 @@ public class DozeUi implements DozeMachine.Part {
break;
case FINISH:
mHost.stopDozing();
+ unscheduleTimeTick();
break;
}
}
+
+ private void scheduleTimeTick() {
+ if (mTimeTickScheduled) {
+ return;
+ }
+
+ long delta = roundToNextMinute(System.currentTimeMillis()) - System.currentTimeMillis();
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler);
+
+ mTimeTickScheduled = true;
+ }
+
+ private void unscheduleTimeTick() {
+ if (!mTimeTickScheduled) {
+ return;
+ }
+ mAlarmManager.cancel(mTimeTick);
+ }
+
+ private long roundToNextMinute(long timeInMillis) {
+ Calendar calendar = GregorianCalendar.getInstance();
+ calendar.setTimeInMillis(timeInMillis);
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.add(Calendar.MINUTE, 1);
+
+ return calendar.getTimeInMillis();
+ }
+
+ private void onTimeTick() {
+ if (!mTimeTickScheduled) {
+ // Alarm was canceled, but we still got the callback. Ignore.
+ return;
+ }
+
+ mHost.dozeTimeTick();
+
+ // Keep wakelock until a frame has been pushed.
+ mHandler.post(mWakeLock.wrap(() -> {}));
+
+ mTimeTickScheduled = false;
+ scheduleTimeTick();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
index 2e6de4ac9e35..1eaca6ffd9db 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -19,6 +19,7 @@ import android.content.Context;
import android.util.Log;
import android.view.View;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.FragmentBase;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
@@ -38,7 +39,7 @@ public class PluginFragmentListener implements PluginListener<Plugin> {
Class<? extends FragmentBase> expectedInterface) {
mTag = tag;
mFragmentHostManager = FragmentHostManager.get(view);
- mPluginManager = PluginManager.getInstance(view.getContext());
+ mPluginManager = Dependency.get(PluginManager.class);
mExpectedInterface = expectedInterface;
mDefaultClass = defaultFragment;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ce89aab30911..99c8c6bacc62 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -80,7 +80,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
@@ -1955,11 +1955,11 @@ public class KeyguardViewMediator extends SystemUI {
Trace.endSection();
}
- public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
+ public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController) {
- mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
+ mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
statusBarWindowManager, scrimController, fingerprintUnlockController,
mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index c7514a90dce3..23eaed9007ac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard;
import static android.app.ActivityManager.TaskDescription;
+import static android.app.ActivityManager.StackId;
import android.annotation.ColorInt;
import android.annotation.UserIdInt;
@@ -31,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -160,9 +162,23 @@ public class WorkLockActivity extends Activity {
credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
try {
- ActivityManager.getService().startConfirmDeviceCredentialIntent(credential);
+ ActivityManager.getService().startConfirmDeviceCredentialIntent(credential,
+ getChallengeOptions().toBundle());
} catch (RemoteException e) {
Log.e(TAG, "Failed to start confirm credential intent", e);
}
}
+
+ private ActivityOptions getChallengeOptions() {
+ // If we are taking up the whole screen, just use the default animation of clipping the
+ // credentials activity into the entire foreground.
+ if (!isInMultiWindowMode()) {
+ return ActivityOptions.makeBasic();
+ }
+
+ // Otherwise, animate the transition from this part of the screen to fullscreen
+ // using our own decor as the starting position.
+ final View view = getWindow().getDecorView();
+ return ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.getWidth(), view.getHeight());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 2c41a0886445..e6483f6332ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -42,9 +42,8 @@ public class WorkLockActivityController {
Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)
.setComponent(new ComponentName(mContext, WorkLockActivity.class))
.putExtra(Intent.EXTRA_USER_ID, userId)
- .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
- | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchTaskId(taskId);
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 978890301f44..5cd7e41167f1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -41,7 +41,7 @@ import java.util.LinkedList;
public class NotificationPlayer implements OnCompletionListener, OnErrorListener {
private static final int PLAY = 1;
private static final int STOP = 2;
- private static final boolean mDebug = false;
+ private static final boolean DEBUG = false;
private static final class Command {
int code;
@@ -97,17 +97,18 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
if (!audioManager.isMusicActiveRemotely()) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus == null) {
- if (mDebug) Log.d(mTag, "requesting AudioFocus");
+ if (DEBUG) Log.d(mTag, "requesting AudioFocus");
+ int focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
if (mCmd.looping) {
- audioManager.requestAudioFocus(null, mCmd.attributes,
- AudioManager.AUDIOFOCUS_GAIN, 0);
- } else {
- audioManager.requestAudioFocus(null, mCmd.attributes,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
+ focusGain = AudioManager.AUDIOFOCUS_GAIN;
}
+ mNotificationRampTimeMs = audioManager.getFocusRampTimeMs(
+ focusGain, mCmd.attributes);
+ audioManager.requestAudioFocus(null, mCmd.attributes,
+ focusGain, 0);
mAudioManagerWithAudioFocus = audioManager;
} else {
- if (mDebug) Log.d(mTag, "AudioFocus was previously requested");
+ if (DEBUG) Log.d(mTag, "AudioFocus was previously requested");
}
}
}
@@ -119,6 +120,9 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
// command are issued, and on which it receives the completion callbacks.
player.setOnCompletionListener(NotificationPlayer.this);
player.setOnErrorListener(NotificationPlayer.this);
+ if (DEBUG) { Log.d(mTag, "notification will be delayed by "
+ + mNotificationRampTimeMs + "ms"); }
+ player.setStartDelayMs(mNotificationRampTimeMs);
player.start();
if (mPlayer != null) {
mPlayer.release();
@@ -139,7 +143,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
// is playing, let it continue until we're done, so there
// is less of a glitch.
try {
- if (mDebug) Log.d(mTag, "Starting playback");
+ if (DEBUG) Log.d(mTag, "Starting playback");
//-----------------------------------
// This is were we deviate from the AsyncPlayer implementation and create the
// MediaPlayer in a new thread with which we're synchronized
@@ -179,17 +183,17 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
Command cmd = null;
synchronized (mCmdQueue) {
- if (mDebug) Log.d(mTag, "RemoveFirst");
+ if (DEBUG) Log.d(mTag, "RemoveFirst");
cmd = mCmdQueue.removeFirst();
}
switch (cmd.code) {
case PLAY:
- if (mDebug) Log.d(mTag, "PLAY");
+ if (DEBUG) Log.d(mTag, "PLAY");
startSound(cmd);
break;
case STOP:
- if (mDebug) Log.d(mTag, "STOP");
+ if (DEBUG) Log.d(mTag, "STOP");
if (mPlayer != null) {
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) {
@@ -232,11 +236,11 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
public void onCompletion(MediaPlayer mp) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
- if (mDebug) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
} else {
- if (mDebug) Log.d(mTag, "onCompletion() no need to abandon AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() no need to abandon AudioFocus");
}
}
// if there are no more sounds to play, end the Looper to listen for media completion
@@ -267,6 +271,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
private PowerManager.WakeLock mWakeLock;
private final Object mQueueAudioFocusLock = new Object();
private AudioManager mAudioManagerWithAudioFocus; // synchronized on mQueueAudioFocusLock
+ private int mNotificationRampTimeMs = 0;
// The current state according to the caller. Reality lags behind
// because of the asynchronous nature of this class.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
index a7ac719149f9..beec13740442 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
@@ -18,12 +18,15 @@ package com.android.systemui.pip.phone;
import android.content.Context;
import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.WindowManager;
+import android.widget.FrameLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -35,12 +38,22 @@ public class PipDismissViewController {
private static final int SHOW_TARGET_DELAY = 100;
private static final int SHOW_TARGET_DURATION = 200;
+ private static final float DISMISS_TEXT_MAX_SCALE = 2f;
+ private static final float DISMISS_GRADIENT_MIN_HEIGHT_PERCENT = 0.33f;
+ private static final float DISMISS_GRADIENT_MAX_HEIGHT_PERCENT = 0.5f;
+ private static final float DISMISS_THRESHOLD = 0.55f;
+
private Context mContext;
private WindowManager mWindowManager;
private View mDismissView;
private Rect mDismissTargetScreenBounds = new Rect();
+ private View mDismissContainer;
+ private View mGradientView;
+ private float mMinHeight;
+ private float mMaxHeight;
+
public PipDismissViewController(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -51,25 +64,37 @@ public class PipDismissViewController {
*/
public void createDismissTarget() {
if (mDismissView == null) {
+ // Determine sizes for the gradient
+ Point windowSize = new Point();
+ mWindowManager.getDefaultDisplay().getSize(windowSize);
+ mMinHeight = windowSize.y * DISMISS_GRADIENT_MIN_HEIGHT_PERCENT;
+ mMaxHeight = windowSize.y * DISMISS_GRADIENT_MAX_HEIGHT_PERCENT;
+
// Create a new view for the dismiss target
- int dismissTargetSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.pip_dismiss_target_size);
LayoutInflater inflater = LayoutInflater.from(mContext);
mDismissView = inflater.inflate(R.layout.pip_dismiss_view, null);
- mDismissView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ mGradientView = mDismissView.findViewById(R.id.gradient_view);
+ FrameLayout.LayoutParams glp = (android.widget.FrameLayout.LayoutParams) mGradientView
+ .getLayoutParams();
+ glp.height = (int) mMaxHeight;
+ mGradientView.setLayoutParams(glp);
+ mGradientView.setPivotY(windowSize.y);
+ mGradientView.setScaleY(mMaxHeight / mMinHeight); // Set to min height via scaling
+ mDismissContainer = mDismissView.findViewById(R.id.pip_dismiss_container);
+ mDismissContainer.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) {
- if (mDismissView != null) {
- mDismissView.getBoundsOnScreen(mDismissTargetScreenBounds);
+ if (mDismissContainer != null) {
+ mDismissContainer.getBoundsOnScreen(mDismissTargetScreenBounds);
}
}
});
// Add the target to the window
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- dismissTargetSize,
- dismissTargetSize,
+ windowSize.x,
+ (int) mMaxHeight,
WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
@@ -84,7 +109,8 @@ public class PipDismissViewController {
/**
* Shows the dismiss target.
*/
- public void showDismissTarget() {
+ public void showDismissTarget(Rect pinnedStack) {
+ updateDismissTarget(pinnedStack);
mDismissView.animate()
.alpha(1f)
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
@@ -115,10 +141,46 @@ public class PipDismissViewController {
}
/**
+ * Updates the appearance of the dismiss target based on how close the PIP is.
+ */
+ public void updateDismissTarget(Rect pinnedStack) {
+ // As PIP moves over / away from delete target it grows / shrinks
+ final float scalePercent = calculateDistancePercent(pinnedStack);
+ final float newScale = 1 + (DISMISS_TEXT_MAX_SCALE - 1) * scalePercent;
+ final float minGradientScale = mMinHeight / mMaxHeight;
+ final float newHeight = Math.max(minGradientScale, scalePercent);
+ mGradientView.setScaleY(newHeight);
+ mDismissContainer.setScaleX(newScale);
+ mDismissContainer.setScaleY(newScale);
+ }
+
+ /**
+ * @return the percentage of distance the PIP is away from the dismiss target point.
+ */
+ private float calculateDistancePercent(Rect pinnedStack) {
+ final int distance = mDismissTargetScreenBounds.height();
+ final int textX = mDismissTargetScreenBounds.centerX();
+ final int textY = mDismissTargetScreenBounds.bottom;
+ final float pipCurrX = pinnedStack.centerX();
+ final float pipCurrY = pinnedStack.bottom;
+ final float currentDistance = PointF.length(pipCurrX - textX, pipCurrY - textY);
+ if (currentDistance <= distance) {
+ return 1 - (currentDistance / distance);
+ }
+ return 0;
+ }
+
+ /**
* @return the dismiss target screen bounds.
*/
public Rect getDismissBounds() {
return mDismissTargetScreenBounds;
}
+ /**
+ * @return whether the PIP is positioned on the dismiss target enough to be dismissed.
+ */
+ public boolean shouldDismiss(Rect pinnedStack) {
+ return calculateDistancePercent(pinnedStack) >= DISMISS_THRESHOLD;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 3df557d6227c..f59b2a4e25de 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,20 +16,16 @@
package com.android.systemui.pip.phone;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
-import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Log;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
@@ -94,7 +90,7 @@ public class PipManager {
}
}
if (expandPipToFullscreen) {
- mTouchHandler.expandPinnedStackToFullscreen();
+ mTouchHandler.getMotionHelper().expandPip();
} else {
Log.w(TAG, "Can not expand PiP to fullscreen via intent from the same package.");
}
@@ -114,28 +110,31 @@ public class PipManager {
}
@Override
- public void onBoundsChanged(boolean adjustedForIme) {
- // Do nothing
+ public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+ mHandler.post(() -> {
+ mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ });
}
@Override
- public void onActionsChanged(ParceledListSlice actions) {
+ public void onMinimizedStateChanged(boolean isMinimized) {
mHandler.post(() -> {
- mMenuController.setAppActions(actions);
+ mTouchHandler.setMinimizedState(isMinimized, true /* fromController */);
});
}
@Override
- public void onMinimizedStateChanged(boolean isMinimized) {
+ public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+ boolean fromImeAdjustement) {
mHandler.post(() -> {
- mTouchHandler.onMinimizedStateChanged(isMinimized);
+ mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, fromImeAdjustement);
});
}
@Override
- public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
+ public void onActionsChanged(ParceledListSlice actions) {
mHandler.post(() -> {
- mTouchHandler.onSnapToEdgeStateChanged(isSnapToEdge);
+ mMenuController.setAppActions(actions);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index d96baa6b3620..5a665a9770b7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -16,16 +16,22 @@
package com.android.systemui.pip.phone;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+
import android.app.IActivityManager;
+import android.app.PendingIntent;
import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.drawable.Icon;
import android.media.session.MediaController;
-import android.media.session.MediaController.TransportControls;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.os.UserHandle;
import com.android.systemui.R;
@@ -40,6 +46,9 @@ import java.util.List;
*/
public class PipMediaController {
+ private static final String ACTION_PLAY = "com.android.systemui.pip.phone.PLAY";
+ private static final String ACTION_PAUSE = "com.android.systemui.pip.phone.PAUSE";
+
/**
* A listener interface to receive notification on changes to the media actions.
*/
@@ -59,6 +68,18 @@ public class PipMediaController {
private RemoteAction mPauseAction;
private RemoteAction mPlayAction;
+ private BroadcastReceiver mPlayPauseActionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(ACTION_PLAY)) {
+ mMediaController.getTransportControls().play();
+ } else if (action.equals(ACTION_PAUSE)) {
+ mMediaController.getTransportControls().pause();
+ }
+ }
+ };
+
private MediaController.Callback mPlaybackChangedListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -73,6 +94,10 @@ public class PipMediaController {
public PipMediaController(Context context, IActivityManager activityManager) {
mContext = context;
mActivityManager = activityManager;
+ IntentFilter mediaControlFilter = new IntentFilter();
+ mediaControlFilter.addAction(ACTION_PLAY);
+ mediaControlFilter.addAction(ACTION_PAUSE);
+ mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
createMediaActions();
mMediaSessionManager =
@@ -135,12 +160,14 @@ public class PipMediaController {
String pauseDescription = mContext.getString(R.string.pip_pause);
mPauseAction = new RemoteAction(Icon.createWithResource(mContext,
R.drawable.ic_pause_white_24dp), pauseDescription, pauseDescription,
- action -> mMediaController.getTransportControls().pause());
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
+ FLAG_UPDATE_CURRENT));
String playDescription = mContext.getString(R.string.pip_play);
mPlayAction = new RemoteAction(Icon.createWithResource(mContext,
R.drawable.ic_play_arrow_white_24dp), playDescription, playDescription,
- action -> mMediaController.getTransportControls().play());
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
+ FLAG_UPDATE_CURRENT));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 438b8ddfc47a..90669772bcd1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -22,6 +22,7 @@ import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.PendingIntent.CanceledException;
import android.app.RemoteAction;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
@@ -258,7 +259,11 @@ public class PipMenuActivity extends Activity {
}, mHandler);
actionView.setContentDescription(action.getContentDescription());
actionView.setOnClickListener(v -> {
- action.sendActionInvoked();
+ try {
+ action.getActionIntent().send();
+ } catch (CanceledException e) {
+ Log.w(TAG, "Failed to send action", e);
+ }
});
actionsGroup.addView(actionView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 6ef30c0258c6..f3dc339f12d6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -77,7 +77,7 @@ public class PipMenuActivityController {
void onPipMinimize();
/**
- * Called when the PIP requested to be expanded.
+ * Called when the PIP requested to be dismissed.
*/
void onPipDismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
new file mode 100644
index 000000000000..fb3ed446212b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone;
+
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
+import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
+import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.ActivityManager.StackInfo;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.animation.Interpolator;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+
+/**
+ * A helper to animate and manipulate the PiP.
+ */
+public class PipMotionHelper {
+
+ private static final String TAG = "PipMotionHelper";
+
+ private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+ private static final int DEFAULT_MOVE_STACK_DURATION = 225;
+ private static final int SNAP_STACK_DURATION = 225;
+ private static final int DISMISS_STACK_DURATION = 375;
+ private static final int SHRINK_STACK_FROM_MENU_DURATION = 175;
+ private static final int EXPAND_STACK_TO_MENU_DURATION = 175;
+ private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 225;
+ private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+
+ // The fraction of the stack width that the user has to drag offscreen to minimize the PiP
+ private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.2f;
+
+ private Context mContext;
+ private IActivityManager mActivityManager;
+ private Handler mHandler;
+
+ private PipSnapAlgorithm mSnapAlgorithm;
+ private FlingAnimationUtils mFlingAnimationUtils;
+
+ private final Rect mBounds = new Rect();
+ private final Rect mStableInsets = new Rect();
+
+ private ValueAnimator mBoundsAnimator = null;
+ private ValueAnimator.AnimatorUpdateListener mUpdateBoundsListener =
+ new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mBounds.set((Rect) animation.getAnimatedValue());
+ }
+ };
+
+ public PipMotionHelper(Context context, IActivityManager activityManager,
+ PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) {
+ mContext = context;
+ mHandler = BackgroundThread.getHandler();
+ mActivityManager = activityManager;
+ mSnapAlgorithm = snapAlgorithm;
+ mFlingAnimationUtils = flingAnimationUtils;
+ onConfigurationChanged();
+ }
+
+ /**
+ * Updates whenever the configuration changes.
+ */
+ void onConfigurationChanged() {
+ mSnapAlgorithm.onConfigurationChanged();
+ SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+ }
+
+ /**
+ * Synchronizes the current bounds with the pinned stack.
+ */
+ void synchronizePinnedStackBounds() {
+ cancelAnimations();
+ try {
+ StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo != null) {
+ mBounds.set(stackInfo.bounds);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get pinned stack bounds");
+ }
+ }
+
+ /**
+ * Tries to the move the pinned stack to the given {@param bounds}.
+ */
+ void movePip(Rect toBounds) {
+ cancelAnimations();
+ resizePipUnchecked(toBounds);
+ mBounds.set(toBounds);
+ }
+
+ /**
+ * Resizes the pinned stack back to fullscreen.
+ */
+ void expandPip() {
+ cancelAnimations();
+ mHandler.post(() -> {
+ try {
+ mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
+ true /* allowResizeInDockedMode */, true /* preserveWindows */,
+ true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error showing PiP menu activity", e);
+ }
+ });
+ }
+
+ /**
+ * Dismisses the pinned stack.
+ */
+ void dismissPip() {
+ cancelAnimations();
+ mHandler.post(() -> {
+ try {
+ mActivityManager.removeStack(PINNED_STACK_ID);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove PiP", e);
+ }
+ });
+ }
+
+ /**
+ * @return the PiP bounds.
+ */
+ Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * @return the closest minimized PiP bounds.
+ */
+ Rect getClosestMinimizedBounds(Rect stackBounds, Rect movementBounds) {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, stackBounds);
+ mSnapAlgorithm.applyMinimizedOffset(toBounds, movementBounds, displaySize, mStableInsets);
+ return toBounds;
+ }
+
+ /**
+ * @return whether the PiP at the current bounds should be minimized.
+ */
+ boolean shouldMinimizePip() {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ if (mBounds.left < 0) {
+ float offscreenFraction = (float) -mBounds.left / mBounds.width();
+ return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+ } else if (mBounds.right > displaySize.x) {
+ float offscreenFraction = (float) (mBounds.right - displaySize.x) /
+ mBounds.width();
+ return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Flings the minimized PiP to the closest minimized snap target.
+ */
+ Rect flingToMinimizedState(float velocityY, Rect movementBounds) {
+ cancelAnimations();
+ // We currently only allow flinging the minimized stack up and down, so just lock the
+ // movement bounds to the current stack bounds horizontally
+ movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
+ movementBounds.bottom);
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
+ 0 /* velocityX */, velocityY);
+ if (!mBounds.equals(toBounds)) {
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
+ mUpdateBoundsListener);
+ mFlingAnimationUtils.apply(mBoundsAnimator, 0,
+ distanceBetweenRectOffsets(mBounds, toBounds),
+ velocityY);
+ mBoundsAnimator.start();
+ }
+ return toBounds;
+ }
+
+ /**
+ * Animates the PiP to the minimized state, slightly offscreen.
+ */
+ Rect animateToClosestMinimizedState(Rect movementBounds,
+ final PipMenuActivityController menuController) {
+ cancelAnimations();
+ Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
+ if (!mBounds.equals(toBounds)) {
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
+ MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener);
+ mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ menuController.hideMenu();
+ }
+ });
+ mBoundsAnimator.start();
+ }
+ return toBounds;
+ }
+
+ /**
+ * Flings the PiP to the closest snap target.
+ */
+ Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds) {
+ cancelAnimations();
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
+ velocityX, velocityY);
+ if (!mBounds.equals(toBounds)) {
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
+ mUpdateBoundsListener);
+ mFlingAnimationUtils.apply(mBoundsAnimator, 0,
+ distanceBetweenRectOffsets(mBounds, toBounds),
+ velocity);
+ mBoundsAnimator.start();
+ }
+ return toBounds;
+ }
+
+ /**
+ * Animates the PiP to the closest snap target.
+ */
+ Rect animateToClosestSnapTarget(Rect movementBounds) {
+ cancelAnimations();
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
+ if (!mBounds.equals(toBounds)) {
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
+ FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+ mBoundsAnimator.start();
+ }
+ return toBounds;
+ }
+
+ /**
+ * Animates the PiP to the expanded state to show the menu.
+ */
+ float animateToExpandedState(Rect expandedBounds, Rect movementBounds,
+ Rect expandedMovementBounds) {
+ float savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), movementBounds);
+ mSnapAlgorithm.applySnapFraction(expandedBounds, expandedMovementBounds, savedSnapFraction);
+ mBoundsAnimator = createAnimationToBounds(mBounds, expandedBounds,
+ EXPAND_STACK_TO_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+ mBoundsAnimator.start();
+ return savedSnapFraction;
+ }
+
+ /**
+ * Animates the PiP from the expanded state to the normal state after the menu is hidden.
+ */
+ void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction,
+ Rect normalMovementBounds) {
+ if (savedSnapFraction >= 0f) {
+ mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
+ mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds,
+ SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+ mBoundsAnimator.start();
+ } else {
+ animateToClosestSnapTarget(normalMovementBounds);
+ }
+ }
+
+ /**
+ * Animates the dismissal of the PiP over the dismiss target bounds.
+ */
+ Rect animateDismissFromDrag(Rect dismissBounds) {
+ cancelAnimations();
+ Rect toBounds = new Rect(dismissBounds.centerX(),
+ dismissBounds.centerY(),
+ dismissBounds.centerX() + 1,
+ dismissBounds.centerY() + 1);
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DISMISS_STACK_DURATION,
+ FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+ mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dismissPip();
+ }
+ });
+ mBoundsAnimator.start();
+ return toBounds;
+ }
+
+ /**
+ * Animates the PiP to some given bounds.
+ */
+ void animateToBounds(Rect toBounds) {
+ cancelAnimations();
+ if (!mBounds.equals(toBounds)) {
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
+ DEFAULT_MOVE_STACK_DURATION, FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+ mBoundsAnimator.start();
+ }
+ }
+
+ /**
+ * Cancels all existing animations.
+ */
+ void cancelAnimations() {
+ if (mBoundsAnimator != null) {
+ mBoundsAnimator.cancel();
+ mBoundsAnimator = null;
+ }
+ }
+
+ /**
+ * Creates an animation to move the PiP to give given {@param toBounds}.
+ */
+ private ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
+ Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
+ ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
+ anim.setDuration(duration);
+ anim.setInterpolator(interpolator);
+ anim.addUpdateListener((ValueAnimator animation) -> {
+ resizePipUnchecked((Rect) animation.getAnimatedValue());
+ });
+ if (updateListener != null) {
+ anim.addUpdateListener(updateListener);
+ }
+ return anim;
+ }
+
+ /**
+ * Directly resizes the PiP to the given {@param bounds}.
+ */
+ private void resizePipUnchecked(Rect toBounds) {
+ if (!toBounds.equals(mBounds)) {
+ mHandler.post(() -> {
+ try {
+ mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e);
+ }
+ });
+ }
+ }
+
+ /**
+ * @return the distance between points {@param p1} and {@param p2}.
+ */
+ private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
+ return PointF.length(r1.left - r2.left, r1.top - r2.top);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 12fda14b3ce2..b3adee0344bb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,23 +16,13 @@
package com.android.systemui.pip.phone;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
-import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.ActivityManager.StackInfo;
import android.app.IActivityManager;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -44,9 +34,10 @@ import android.view.InputEventReceiver;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.policy.PipMotionHelper;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.Dependency;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.tuner.TunerService;
@@ -56,18 +47,14 @@ import com.android.systemui.tuner.TunerService;
*/
public class PipTouchHandler implements TunerService.Tunable {
private static final String TAG = "PipTouchHandler";
- private static final boolean DEBUG_ALLOW_OUT_OF_BOUNDS_STACK = false;
- private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
- private static final String TUNER_KEY_ALLOW_MINIMIZE = "pip_allow_minimize";
+ // These values are used for metrics and should never change
+ private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
+ private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
- private static final int SNAP_STACK_DURATION = 225;
- private static final int DISMISS_STACK_DURATION = 375;
- private static final int EXPAND_STACK_DURATION = 225;
- private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+ private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
- // The fraction of the stack width that the user has to drag offscreen to minimize the PIP
- private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f;
+ private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200;
private final Context mContext;
private final IActivityManager mActivityManager;
@@ -77,38 +64,47 @@ public class PipTouchHandler implements TunerService.Tunable {
private IPinnedStackController mPinnedStackController;
private PipInputEventReceiver mInputEventReceiver;
- private PipMenuActivityController mMenuController;
- private PipDismissViewController mDismissViewController;
+ private final PipMenuActivityController mMenuController;
+ private final PipDismissViewController mDismissViewController;
private final PipSnapAlgorithm mSnapAlgorithm;
- private PipMotionHelper mMotionHelper;
// Allow dragging the PIP to a location to close it
private boolean mEnableDragToDismiss = false;
- // Allow the PIP to be "docked" slightly offscreen
- private boolean mEnableMinimizing = true;
-
- private final Rect mStableInsets = new Rect();
- private final Rect mPinnedStackBounds = new Rect();
- private final Rect mBoundedPinnedStackBounds = new Rect();
- private ValueAnimator mPinnedStackBoundsAnimator = null;
- private ValueAnimator.AnimatorUpdateListener mUpdatePinnedStackBoundsListener =
- new AnimatorUpdateListener() {
+
+ // The current movement bounds
+ private Rect mMovementBounds = new Rect();
+
+ // The reference bounds used to calculate the normal/expanded target bounds
+ private Rect mNormalBounds = new Rect();
+ private Rect mNormalMovementBounds = new Rect();
+ private Rect mExpandedBounds = new Rect();
+ private Rect mExpandedMovementBounds = new Rect();
+
+ private Handler mHandler = new Handler();
+ private Runnable mShowDismissAffordance = new Runnable() {
@Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mPinnedStackBounds.set((Rect) animation.getAnimatedValue());
+ public void run() {
+ if (mEnableDragToDismiss) {
+ mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
+ }
}
};
// Behaviour states
private boolean mIsTappingThrough;
private boolean mIsMinimized;
+ private boolean mIsMenuVisible;
+ private boolean mIsImeShowing;
+ private int mImeHeight;
+ private float mSavedSnapFraction = -1f;
// Touch state
private final PipTouchState mTouchState;
private final FlingAnimationUtils mFlingAnimationUtils;
private final PipTouchGesture[] mGestures;
+ private final PipMotionHelper mMotionHelper;
- // Temporary vars
+ // Temp vars
private final Rect mTmpBounds = new Rect();
/**
@@ -141,30 +137,27 @@ public class PipTouchHandler implements TunerService.Tunable {
private class PipMenuListener implements PipMenuActivityController.Listener {
@Override
public void onPipMenuVisibilityChanged(boolean visible) {
- if (!visible) {
- mIsTappingThrough = false;
- registerInputConsumer();
- } else {
- unregisterInputConsumer();
- }
+ setMenuVisibilityState(visible);
}
@Override
public void onPipExpand() {
if (!mIsMinimized) {
- expandPinnedStackToFullscreen();
+ mMotionHelper.expandPip();
}
}
@Override
public void onPipMinimize() {
- setMinimizedState(true);
- animateToClosestMinimizedTarget();
+ setMinimizedStateInternal(true);
+ mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
}
@Override
public void onPipDismiss() {
- BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
+ mMotionHelper.dismissPip();
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
+ METRIC_VALUE_DISMISSED_BY_TAP);
}
}
@@ -183,15 +176,14 @@ public class PipTouchHandler implements TunerService.Tunable {
mTouchState = new PipTouchState(mViewConfig);
mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
mGestures = new PipTouchGesture[] {
- mDragToDismissGesture, mTapThroughGesture, mMinimizeGesture, mDefaultMovementGesture
+ mDefaultMovementGesture
};
- mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler());
+ mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
+ mFlingAnimationUtils);
registerInputConsumer();
- setSnapToEdge(true);
// Register any tuner settings changes
- TunerService.get(context).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS,
- TUNER_KEY_ALLOW_MINIMIZE);
+ Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS);
}
@Override
@@ -199,17 +191,12 @@ public class PipTouchHandler implements TunerService.Tunable {
if (newValue == null) {
// Reset back to default
mEnableDragToDismiss = false;
- mEnableMinimizing = true;
- setMinimizedState(false);
return;
}
switch (key) {
case TUNER_KEY_DRAG_TO_DISMISS:
mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
break;
- case TUNER_KEY_ALLOW_MINIMIZE:
- mEnableMinimizing = Integer.parseInt(newValue) != 0;
- break;
}
}
@@ -220,21 +207,70 @@ public class PipTouchHandler implements TunerService.Tunable {
registerInputConsumer();
}
if (mIsMinimized) {
- setMinimizedState(false);
+ setMinimizedStateInternal(false);
}
}
public void onConfigurationChanged() {
- mSnapAlgorithm.onConfigurationChanged();
- updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
+ mMotionHelper.onConfigurationChanged();
+ mMotionHelper.synchronizePinnedStackBounds();
}
- public void onMinimizedStateChanged(boolean isMinimized) {
- mIsMinimized = isMinimized;
+ public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+ mIsImeShowing = imeVisible;
+ mImeHeight = imeHeight;
}
- public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
- mSnapAlgorithm.setSnapToEdge(isSnapToEdge);
+ public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+ boolean fromImeAdjustement) {
+ // Re-calculate the expanded bounds
+ mNormalBounds = normalBounds;
+ Rect normalMovementBounds = new Rect();
+ mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
+ mIsImeShowing ? mImeHeight : 0);
+ // TODO: Figure out the expanded size policy
+ mExpandedBounds = new Rect(normalBounds);
+ Rect expandedMovementBounds = new Rect();
+ mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
+ mIsImeShowing ? mImeHeight : 0);
+
+
+ // If this is from an IME adjustment, then we should move the PiP so that it is not occluded
+ // by the IME
+ if (fromImeAdjustement) {
+ if (mTouchState.isUserInteracting()) {
+ // Defer the update of the current movement bounds until after the user finishes
+ // touching the screen
+ } else {
+ final Rect bounds = new Rect(mMotionHelper.getBounds());
+ final Rect toMovementBounds = mIsMenuVisible
+ ? expandedMovementBounds
+ : normalMovementBounds;
+ if (mIsImeShowing) {
+ // IME visible
+ if (bounds.top == mMovementBounds.bottom) {
+ // If the PIP is currently resting on top of the IME, then adjust it with
+ // the hiding IME
+ bounds.offsetTo(bounds.left, toMovementBounds.bottom);
+ } else {
+ bounds.offset(0, Math.min(0, toMovementBounds.bottom - bounds.top));
+ }
+ } else {
+ // IME hidden
+ if (bounds.top == mMovementBounds.bottom) {
+ // If the PIP is resting on top of the IME, then adjust it with the hiding IME
+ bounds.offsetTo(bounds.left, toMovementBounds.bottom);
+ }
+ }
+ mMotionHelper.animateToBounds(bounds);
+ }
+ }
+
+ // Update the movement bounds after doing the calculations based on the old movement bounds
+ // above
+ mNormalMovementBounds = normalMovementBounds;
+ mExpandedMovementBounds = expandedMovementBounds;
+ updateMovementBounds();
}
private boolean handleTouchEvent(MotionEvent ev) {
@@ -248,20 +284,11 @@ public class PipTouchHandler implements TunerService.Tunable {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
- // Cancel any existing animations on the pinned stack
- if (mPinnedStackBoundsAnimator != null) {
- mPinnedStackBoundsAnimator.cancel();
- }
+ mMotionHelper.synchronizePinnedStackBounds();
- updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */);
for (PipTouchGesture gesture : mGestures) {
gesture.onDown(mTouchState);
}
- try {
- mPinnedStackController.setInInteractiveMode(true);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not set dragging state", e);
- }
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -275,7 +302,7 @@ public class PipTouchHandler implements TunerService.Tunable {
case MotionEvent.ACTION_UP: {
// Update the movement bounds again if the state has changed since the user started
// dragging (ie. when the IME shows)
- updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
+ updateMovementBounds();
for (PipTouchGesture gesture : mGestures) {
if (gesture.onUp(mTouchState)) {
@@ -286,11 +313,6 @@ public class PipTouchHandler implements TunerService.Tunable {
// Fall through to clean up
}
case MotionEvent.ACTION_CANCEL: {
- try {
- mPinnedStackController.setInInteractiveMode(false);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not set dragging state", e);
- }
break;
}
}
@@ -298,17 +320,6 @@ public class PipTouchHandler implements TunerService.Tunable {
}
/**
- * @return whether the current touch state is a horizontal drag offscreen.
- */
- private boolean isDraggingOffscreen(PipTouchState touchState) {
- PointF lastDelta = touchState.getLastTouchDelta();
- PointF downDelta = touchState.getDownTouchDelta();
- float left = mPinnedStackBounds.left + lastDelta.x;
- return !(mBoundedPinnedStackBounds.left <= left && left <= mBoundedPinnedStackBounds.right)
- && Math.abs(downDelta.x) > Math.abs(downDelta.y);
- }
-
- /**
* Registers the input consumer.
*/
private void registerInputConsumer() {
@@ -347,27 +358,30 @@ public class PipTouchHandler implements TunerService.Tunable {
}
/**
- * Sets the snap-to-edge state and notifies the controller.
+ * Sets the minimized state.
*/
- private void setSnapToEdge(boolean snapToEdge) {
- onSnapToEdgeStateChanged(snapToEdge);
-
- if (mPinnedStackController != null) {
- try {
- mPinnedStackController.setSnapToEdge(snapToEdge);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not set snap mode to edge", e);
- }
- }
+ void setMinimizedStateInternal(boolean isMinimized) {
+ setMinimizedState(isMinimized, false /* fromController */);
}
/**
- * Sets the minimized state and notifies the controller.
+ * Sets the minimized state.
*/
- private void setMinimizedState(boolean isMinimized) {
- onMinimizedStateChanged(isMinimized);
+ void setMinimizedState(boolean isMinimized, boolean fromController) {
+ if (mIsMinimized != isMinimized) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
+ isMinimized);
+ }
+ mIsMinimized = isMinimized;
+ mSnapAlgorithm.setMinimized(isMinimized);
- if (mPinnedStackController != null) {
+ if (fromController) {
+ if (isMinimized) {
+ // Move the PiP to the new bounds immediately if minimized
+ mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds,
+ mMovementBounds));
+ }
+ } else if (mPinnedStackController != null) {
try {
mPinnedStackController.setIsMinimized(isMinimized);
} catch (RemoteException e) {
@@ -377,350 +391,179 @@ public class PipTouchHandler implements TunerService.Tunable {
}
/**
- * @return whether the given {@param pinnedStackBounds} indicates the PIP should be minimized.
+ * Sets the menu visibility.
*/
- private boolean shouldMinimizedPinnedStack() {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- if (mPinnedStackBounds.left < 0) {
- float offscreenFraction = (float) -mPinnedStackBounds.left / mPinnedStackBounds.width();
- return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
- } else if (mPinnedStackBounds.right > displaySize.x) {
- float offscreenFraction = (float) (mPinnedStackBounds.right - displaySize.x) /
- mPinnedStackBounds.width();
- return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+ void setMenuVisibilityState(boolean isMenuVisible) {
+ if (!isMenuVisible) {
+ mIsTappingThrough = false;
+ registerInputConsumer();
} else {
- return false;
- }
- }
-
- /**
- * Flings the minimized PIP to the closest minimized snap target.
- */
- private void flingToMinimizedSnapTarget(float velocityY) {
- // We currently only allow flinging the minimized stack up and down, so just lock the
- // movement bounds to the current stack bounds horizontally
- Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top,
- mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom);
- Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds,
- 0 /* velocityX */, velocityY);
- if (!mPinnedStackBounds.equals(toBounds)) {
- mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
- toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
- mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
- distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
- velocityY);
- mPinnedStackBoundsAnimator.start();
- }
- }
-
- /**
- * Animates the PIP to the minimized state, slightly offscreen.
- */
- private void animateToClosestMinimizedTarget() {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
- mPinnedStackBounds);
- mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize,
- mStableInsets);
- mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
- toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
- mUpdatePinnedStackBoundsListener);
- mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mMenuController.hideMenu();
- }
- });
- mPinnedStackBoundsAnimator.start();
- }
-
- /**
- * Flings the PIP to the closest snap target.
- */
- private void flingToSnapTarget(float velocity, float velocityX, float velocityY) {
- Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
- mPinnedStackBounds, velocityX, velocityY);
- if (!mPinnedStackBounds.equals(toBounds)) {
- mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
- toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
- mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
- distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
- velocity);
- mPinnedStackBoundsAnimator.start();
- }
- }
-
- /**
- * Animates the PIP to the closest snap target.
- */
- private void animateToClosestSnapTarget() {
- Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
- mPinnedStackBounds);
- if (!mPinnedStackBounds.equals(toBounds)) {
- mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
- toBounds, SNAP_STACK_DURATION, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
- mPinnedStackBoundsAnimator.start();
- }
- }
-
- /**
- * Animates the dismissal of the PIP over the dismiss target bounds.
- */
- private void animateDismissPinnedStack(Rect dismissBounds) {
- Rect toBounds = new Rect(dismissBounds.centerX(),
- dismissBounds.centerY(),
- dismissBounds.centerX() + 1,
- dismissBounds.centerY() + 1);
- mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
- toBounds, DISMISS_STACK_DURATION, FAST_OUT_LINEAR_IN, mUpdatePinnedStackBoundsListener);
- mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
- }
- });
- mPinnedStackBoundsAnimator.start();
- }
-
- /**
- * Resizes the pinned stack back to fullscreen.
- */
- void expandPinnedStackToFullscreen() {
- BackgroundThread.getHandler().post(() -> {
- try {
- mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
- true /* allowResizeInDockedMode */, true /* preserveWindows */,
- true /* animate */, EXPAND_STACK_DURATION);
- } catch (RemoteException e) {
- Log.e(TAG, "Error showing PIP menu activity", e);
+ unregisterInputConsumer();
+ }
+ MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
+ isMenuVisible);
+
+ if (isMenuVisible != mIsMenuVisible) {
+ if (isMenuVisible) {
+ // Save the current snap fraction and if we do not drag or move the PiP, then
+ // we store back to this snap fraction. Otherwise, we'll reset the snap
+ // fraction and snap to the closest edge
+ Rect expandedBounds = new Rect(mExpandedBounds);
+ mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
+ mMovementBounds, mExpandedMovementBounds);
+ } else {
+ // Try and restore the PiP to the closest edge, using the saved snap fraction
+ // if possible
+ Rect normalBounds = new Rect(mNormalBounds);
+ mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
+ mNormalMovementBounds);
}
- });
- }
-
- /**
- * Tries to the move the pinned stack to the given {@param bounds}.
- */
- private void movePinnedStack(Rect bounds) {
- if (!bounds.equals(mPinnedStackBounds)) {
- mPinnedStackBounds.set(bounds);
- mMotionHelper.resizeToBounds(mPinnedStackBounds);
+ mIsMenuVisible = isMenuVisible;
+ updateMovementBounds();
}
}
/**
- * Dismisses the pinned stack.
+ * @return the motion helper.
*/
- private void dismissPinnedStack() {
- try {
- mActivityManager.removeStack(PINNED_STACK_ID);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PIP", e);
- }
+ public PipMotionHelper getMotionHelper() {
+ return mMotionHelper;
}
/**
- * Updates the movement bounds of the pinned stack.
- */
- private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) {
- try {
- StackInfo info = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (info != null) {
- if (updatePinnedStackBounds) {
- mPinnedStackBounds.set(info.bounds);
- }
- mWindowManager.getStableInsets(info.displayId, mStableInsets);
- mBoundedPinnedStackBounds.set(mWindowManager.getPictureInPictureMovementBounds(
- info.displayId));
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not fetch PIP movement bounds.", e);
- }
- }
-
- /**
- * @return the distance between points {@param p1} and {@param p2}.
+ * Gesture controlling normal movement of the PIP.
*/
- private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
- return PointF.length(r1.left - r2.left, r1.top - r2.top);
- }
+ private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
- /**
- * Gesture controlling dragging over a target to dismiss the PIP.
- */
- private PipTouchGesture mDragToDismissGesture = new PipTouchGesture() {
@Override
public void onDown(PipTouchState touchState) {
if (mEnableDragToDismiss) {
- // TODO: Consider setting a timer such at after X time, we show the dismiss
- // target if the user hasn't already dragged some distance
mDismissViewController.createDismissTarget();
+ mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
}
}
@Override
boolean onMove(PipTouchState touchState) {
- if (mEnableDragToDismiss && touchState.startedDragging()) {
- mDismissViewController.showDismissTarget();
+ if (touchState.startedDragging()) {
+ mSavedSnapFraction = -1f;
}
- return false;
- }
- @Override
- public boolean onUp(PipTouchState touchState) {
- if (mEnableDragToDismiss) {
- try {
- if (touchState.isDragging()) {
- Rect dismissBounds = mDismissViewController.getDismissBounds();
- PointF lastTouch = touchState.getLastTouchPosition();
- if (dismissBounds.contains((int) lastTouch.x, (int) lastTouch.y)) {
- animateDismissPinnedStack(dismissBounds);
- return true;
- }
- }
- } finally {
- mDismissViewController.destroyDismissTarget();
- }
+ if (touchState.startedDragging() && mEnableDragToDismiss) {
+ mHandler.removeCallbacks(mShowDismissAffordance);
+ mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
}
- return false;
- }
- };
- /**** Gestures ****/
-
- /**
- * Gesture controlling dragging the PIP slightly offscreen to minimize it.
- */
- private PipTouchGesture mMinimizeGesture = new PipTouchGesture() {
- @Override
- boolean onMove(PipTouchState touchState) {
- if (mEnableMinimizing) {
- boolean isDraggingOffscreen = isDraggingOffscreen(touchState);
- if (touchState.startedDragging() && isDraggingOffscreen) {
- // Reset the minimized state once we drag horizontally
- setMinimizedState(false);
+ if (touchState.isDragging()) {
+ // Move the pinned stack freely
+ mTmpBounds.set(mMotionHelper.getBounds());
+ final PointF lastDelta = touchState.getLastTouchDelta();
+ float left = mTmpBounds.left + lastDelta.x;
+ float top = mTmpBounds.top + lastDelta.y;
+ if (!touchState.allowDraggingOffscreen()) {
+ left = Math.max(mMovementBounds.left, Math.min(mMovementBounds.right, left));
}
+ top = Math.max(mMovementBounds.top, Math.min(mMovementBounds.bottom, top));
+ mTmpBounds.offsetTo((int) left, (int) top);
+ mMotionHelper.movePip(mTmpBounds);
- if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) {
- // Move the pinned stack, but ignore the vertical movement
- float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
- mTmpBounds.set(mPinnedStackBounds);
- mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
- if (!mTmpBounds.equals(mPinnedStackBounds)) {
- mPinnedStackBounds.set(mTmpBounds);
- mMotionHelper.resizeToBounds(mPinnedStackBounds);
- }
- return true;
- } else if (mIsMinimized && touchState.isDragging()) {
- // Move the pinned stack, but ignore the horizontal movement
- PointF lastDelta = touchState.getLastTouchDelta();
- float top = mPinnedStackBounds.top + lastDelta.y;
- top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
- mBoundedPinnedStackBounds.bottom, top));
- mTmpBounds.set(mPinnedStackBounds);
- mTmpBounds.offsetTo(mPinnedStackBounds.left, (int) top);
- movePinnedStack(mTmpBounds);
- return true;
+ if (mEnableDragToDismiss) {
+ mDismissViewController.updateDismissTarget(mTmpBounds);
}
+ return true;
}
return false;
}
@Override
public boolean onUp(PipTouchState touchState) {
- if (mEnableMinimizing) {
- if (touchState.isDragging()) {
- if (isDraggingOffscreen(touchState)) {
- if (shouldMinimizedPinnedStack()) {
- setMinimizedState(true);
- animateToClosestMinimizedTarget();
+ try {
+ if (mEnableDragToDismiss) {
+ mHandler.removeCallbacks(mShowDismissAffordance);
+ PointF vel = mTouchState.getVelocity();
+ final float velocity = PointF.length(vel.x, vel.y);
+ if (touchState.isDragging()
+ && velocity < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+ if (mDismissViewController.shouldDismiss(mMotionHelper.getBounds())) {
+ Rect dismissBounds = mDismissViewController.getDismissBounds();
+ mMotionHelper.animateDismissFromDrag(dismissBounds);
+ MetricsLogger.action(mContext,
+ MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
+ METRIC_VALUE_DISMISSED_BY_DRAG);
return true;
}
- } else if (mIsMinimized) {
- PointF vel = touchState.getVelocity();
- if (vel.length() > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- flingToMinimizedSnapTarget(vel.y);
- } else {
- animateToClosestMinimizedTarget();
- }
- return true;
}
- } else if (mIsMinimized) {
- setMinimizedState(false);
- animateToClosestSnapTarget();
- return true;
}
+ } finally {
+ mDismissViewController.destroyDismissTarget();
}
- return false;
- }
- };
-
- /**
- * Gesture controlling tapping on the PIP to show an overlay.
- */
- private PipTouchGesture mTapThroughGesture = new PipTouchGesture() {
- @Override
- boolean onMove(PipTouchState touchState) {
- return false;
- }
+ if (touchState.isDragging()) {
+ PointF vel = mTouchState.getVelocity();
+ if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
+ || isHorizontalFlingTowardsCurrentEdge(vel))) {
+ // Pip should be minimized
+ setMinimizedStateInternal(true);
+ mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
+ return true;
+ }
+ if (mIsMinimized) {
+ // If we're dragging and it wasn't a minimize gesture
+ // then we shouldn't be minimized.
+ setMinimizedStateInternal(false);
+ }
- @Override
- public boolean onUp(PipTouchState touchState) {
- if (!touchState.isDragging() && !mIsMinimized && !mIsTappingThrough) {
+ final float velocity = PointF.length(vel.x, vel.y);
+ if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+ mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds);
+ } else {
+ mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
+ }
+ } else if (mIsMinimized) {
+ // This was a tap, so no longer minimized
+ mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
+ setMinimizedStateInternal(false);
+ } else if (!mIsTappingThrough) {
mMenuController.showMenu();
mIsTappingThrough = true;
- return true;
+ } else {
+ mMotionHelper.expandPip();
}
- return false;
+ return true;
}
};
/**
- * Gesture controlling normal movement of the PIP.
+ * @return whether the gesture ending in the {@param vel} is fast enough to be a fling towards
+ * the same edge the PIP is on. Used to identify a minimize gesture.
*/
- private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
- @Override
- boolean onMove(PipTouchState touchState) {
- if (touchState.startedDragging()) {
- // For now, once the user has started a drag that the other gestures have not
- // intercepted, disallow those gestures from intercepting again to drag offscreen
- touchState.setDisallowDraggingOffscreen();
- }
+ private boolean isHorizontalFlingTowardsCurrentEdge(PointF vel) {
+ final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
+ final boolean isFling = PointF.length(vel.x, vel.y) > mFlingAnimationUtils
+ .getMinVelocityPxPerSecond();
+ final boolean towardsCurrentEdge = isOverEdge(true /* left */) && vel.x < 0
+ || isOverEdge(false /* right */) && vel.x > 0;
+ return towardsCurrentEdge && isHorizontal && isFling;
+ }
- if (touchState.isDragging()) {
- // Move the pinned stack freely
- PointF lastDelta = touchState.getLastTouchDelta();
- float left = mPinnedStackBounds.left + lastDelta.x;
- float top = mPinnedStackBounds.top + lastDelta.y;
- if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) {
- left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
- mBoundedPinnedStackBounds.right, left));
- top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
- mBoundedPinnedStackBounds.bottom, top));
- }
- mTmpBounds.set(mPinnedStackBounds);
- mTmpBounds.offsetTo((int) left, (int) top);
- movePinnedStack(mTmpBounds);
- return true;
- }
- return false;
+ /**
+ * @return whether the given bounds are on the left or right edge (depending on
+ * {@param checkLeft})
+ */
+ private boolean isOverEdge(boolean checkLeft) {
+ final Rect bounds = mMotionHelper.getBounds();
+ if (checkLeft) {
+ return bounds.left <= mMovementBounds.left;
+ } else {
+ return bounds.right >= mMovementBounds.right + bounds.width();
}
+ }
- @Override
- public boolean onUp(PipTouchState touchState) {
- if (touchState.isDragging()) {
- PointF vel = mTouchState.getVelocity();
- float velocity = PointF.length(vel.x, vel.y);
- if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- flingToSnapTarget(velocity, vel.x, vel.y);
- } else {
- animateToClosestSnapTarget();
- }
- } else {
- expandPinnedStackToFullscreen();
- }
- return true;
- }
- };
+ /**
+ * Updates the current movement bounds based on whether the menu is currently visible.
+ */
+ private void updateMovementBounds() {
+ mMovementBounds = mIsMenuVisible
+ ? mExpandedMovementBounds
+ : mNormalMovementBounds;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index 2e84ceda8ae0..868b34b773d0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -34,6 +34,7 @@ public class PipTouchState {
private final PointF mLastTouch = new PointF();
private final PointF mLastDelta = new PointF();
private final PointF mVelocity = new PointF();
+ private boolean mIsUserInteracting = false;
private boolean mIsDragging = false;
private boolean mStartedDragging = false;
private boolean mAllowDraggingOffscreen = false;
@@ -57,6 +58,7 @@ public class PipTouchState {
mIsDragging = false;
mStartedDragging = false;
mAllowDraggingOffscreen = true;
+ mIsUserInteracting = true;
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -107,6 +109,7 @@ public class PipTouchState {
// Fall through to clean up
}
case MotionEvent.ACTION_CANCEL: {
+ mIsUserInteracting = false;
recycleVelocityTracker();
break;
}
@@ -151,6 +154,13 @@ public class PipTouchState {
}
/**
+ * @return whether the user is currently interacting with the PiP.
+ */
+ public boolean isUserInteracting() {
+ return mIsUserInteracting;
+ }
+
+ /**
* @return whether the user has started dragging just in the last handled touch event.
*/
public boolean startedDragging() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 56947e5b6231..e3db16a069c5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Rect;
import android.media.session.MediaController;
@@ -39,6 +40,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.Display;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -51,6 +54,8 @@ import java.util.ArrayList;
import java.util.List;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.systemui.Prefs.Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN;
/**
@@ -146,7 +151,7 @@ public class PipManager {
private List<MediaListener> mMediaListeners = new ArrayList<>();
private Rect mCurrentPipBounds;
private Rect mPipBounds;
- private Rect mDefaultPipBounds;
+ private Rect mDefaultPipBounds = new Rect();
private Rect mSettingsPipBounds;
private Rect mMenuModePipBounds;
private Rect mRecentsPipBounds;
@@ -159,6 +164,8 @@ public class PipManager {
private boolean mOnboardingShown;
private String[] mLastPackagesResourceGranted;
+ private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
+
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
@@ -196,6 +203,32 @@ public class PipManager {
}
};
+ /**
+ * Handler for messages from the PIP controller.
+ */
+ private class PinnedStackListener extends IPinnedStackListener.Stub {
+
+ @Override
+ public void onListenerRegistered(IPinnedStackController controller) {}
+
+ @Override
+ public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
+
+ @Override
+ public void onMinimizedStateChanged(boolean isMinimized) {}
+
+ @Override
+ public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+ boolean fromImeAdjustement) {
+ mHandler.post(() -> {
+ mDefaultPipBounds.set(normalBounds);
+ });
+ }
+
+ @Override
+ public void onActionsChanged(ParceledListSlice actions) {}
+ }
+
private PipManager() { }
/**
@@ -221,16 +254,16 @@ public class PipManager {
mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
mMediaSessionManager =
(MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
- }
- private void loadConfigurationsAndApply() {
- Resources res = mContext.getResources();
try {
- mDefaultPipBounds = mWindowManager.getPictureInPictureDefaultBounds(
- Display.DEFAULT_DISPLAY);
+ mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to get default PIP bounds", e);
+ Log.e(TAG, "Failed to register pinned stack listener", e);
}
+ }
+
+ private void loadConfigurationsAndApply() {
+ Resources res = mContext.getResources();
mSettingsPipBounds = Rect.unflattenFromString(res.getString(
R.string.pip_settings_bounds));
mMenuModePipBounds = Rect.unflattenFromString(res.getString(
@@ -377,16 +410,18 @@ public class PipManager {
mCurrentPipBounds = mPipBounds;
break;
}
- try {
- int animationDurationMs = -1;
- if (wasRecentsShown
- && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
- animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+ if (mCurrentPipBounds != null) {
+ try {
+ int animationDurationMs = -1;
+ if (wasRecentsShown
+ && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+ animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+ }
+ mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+ true, true, true, animationDurationMs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "resizeStack failed", e);
}
- mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
- true, true, true, animationDurationMs);
- } catch (RemoteException e) {
- Log.e(TAG, "resizeStack failed", e);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 71dda2dfb010..09ce2ada11e0 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -41,8 +41,9 @@ import android.util.Slog;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.util.NotificationChannels;
import java.io.PrintWriter;
import java.text.NumberFormat;
@@ -97,7 +98,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private SystemUIDialog mHighTempDialog;
public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
- PhoneStatusBar phoneStatusBar) {
+ StatusBar statusBar) {
mContext = context;
mNoMan = notificationManager;
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -144,17 +145,16 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
}
private void showInvalidChargerNotification() {
- final Notification.Builder nb = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_power_low)
- .setWhen(0)
- .setShowWhen(false)
- .setOngoing(true)
- .setContentTitle(mContext.getString(R.string.invalid_charger_title))
- .setContentText(mContext.getString(R.string.invalid_charger_text))
- .setPriority(Notification.PRIORITY_MAX)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ final Notification.Builder nb =
+ new Notification.Builder(mContext, NotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.ic_power_low)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setOngoing(true)
+ .setContentTitle(mContext.getString(R.string.invalid_charger_title))
+ .setContentText(mContext.getString(R.string.invalid_charger_text))
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
@@ -164,19 +164,19 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private void showWarningNotification() {
final int textRes = R.string.battery_low_percent_format;
final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
- final Notification.Builder nb = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_power_low)
- // Bump the notification when the bucket dropped.
- .setWhen(mBucketDroppedNegativeTimeMs)
- .setShowWhen(false)
- .setContentTitle(mContext.getString(R.string.battery_low_title))
- .setContentText(mContext.getString(textRes, percentage))
- .setOnlyAlertOnce(true)
- .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
- .setPriority(Notification.PRIORITY_MAX)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(
- com.android.internal.R.color.battery_saver_mode_color));
+ final Notification.Builder nb =
+ new Notification.Builder(mContext, NotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.ic_power_low)
+ // Bump the notification when the bucket dropped.
+ .setWhen(mBucketDroppedNegativeTimeMs)
+ .setShowWhen(false)
+ .setContentTitle(mContext.getString(R.string.battery_low_title))
+ .setContentText(mContext.getString(textRes, percentage))
+ .setOnlyAlertOnce(true)
+ .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.battery_saver_mode_color));
if (hasBatterySettings()) {
nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
}
@@ -217,8 +217,16 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
return;
}
mTempWarning = false;
- mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP,
- UserHandle.ALL);
+ dismissTemperatureWarningInternal();
+ }
+
+ /**
+ * Internal only version of {@link #dismissTemperatureWarning()} that simply dismisses
+ * the notification. As such, the notification will not show again until
+ * {@link #dismissTemperatureWarning()} is called.
+ */
+ private void dismissTemperatureWarningInternal() {
+ mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, UserHandle.ALL);
}
@Override
@@ -227,18 +235,18 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
return;
}
mTempWarning = true;
- final Notification.Builder nb = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_device_thermostat_24)
- .setWhen(0)
- .setShowWhen(false)
- .setContentTitle(mContext.getString(R.string.high_temp_title))
- .setContentText(mContext.getString(R.string.high_temp_notif_message))
- .setPriority(Notification.PRIORITY_HIGH)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
- .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
- .setColor(mContext.getColor(
- com.android.internal.R.color.battery_saver_mode_color));
+ final Notification.Builder nb =
+ new Notification.Builder(mContext, NotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.ic_device_thermostat_24)
+ .setWhen(0)
+ .setShowWhen(false)
+ .setContentTitle(mContext.getString(R.string.high_temp_title))
+ .setContentText(mContext.getString(R.string.high_temp_notif_message))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
+ .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.battery_saver_mode_color));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
@@ -390,10 +398,10 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
} else if (action.equals(ACTION_DISMISSED_WARNING)) {
dismissLowBatteryWarning();
} else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
- dismissTemperatureWarning();
+ dismissTemperatureWarningInternal();
showTemperatureDialog();
} else if (ACTION_DISMISSED_TEMP_WARNING.equals(action)) {
- dismissTemperatureWarning();
+ dismissTemperatureWarningInternal();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1d4a5c71c2b4..3d3686896bba 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -36,7 +36,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -72,7 +72,7 @@ public class PowerUI extends SystemUI {
mWarnings = new PowerNotificationWarnings(
mContext,
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE),
- getComponent(PhoneStatusBar.class));
+ getComponent(StatusBar.class));
ContentObserver obs = new ContentObserver(mHandler) {
@Override
@@ -250,8 +250,8 @@ public class PowerUI extends SystemUI {
}
private void updateTemperatureWarning() {
- PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
- if (phoneStatusBar != null && phoneStatusBar.isDeviceInVrMode()) {
+ StatusBar statusBar = getComponent(StatusBar.class);
+ if (statusBar != null && statusBar.isDeviceInVrMode()) {
// ensure the warning isn't showing, since VR shows its own warning
mWarnings.dismissTemperatureWarning();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 409943d46926..c85f83ba3588 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -20,6 +20,7 @@ import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnLayoutChangeListener;
import android.widget.TextView;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.PagedTileLayout.PageListener;
import com.android.systemui.qs.QSPanel.QSTileLayout;
@@ -105,7 +106,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onViewAttachedToWindow(View v) {
- TunerService.get(mQs.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+ Dependency.get(TunerService.class).addTunable(this, ALLOW_FANCY_ANIMATION,
MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
}
@@ -114,7 +115,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mHost != null) {
mHost.removeCallback(this);
}
- TunerService.get(mQs.getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
}
@Override
@@ -193,9 +194,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
translationXBuilder.addFloat(label, "translationX", -xDiff, 0);
translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
- mTopFiveQs.add(tileIcon);
- mTopFiveQs.add(tileView.getBgCicle());
- mAllViews.add(tileIcon);
+ mTopFiveQs.add(tileView.getIcon());
+ 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.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 0bf3f15a5889..1835afd937c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -60,7 +60,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
private AlertDialog mDialog;
private QSTileHost mHost;
- protected Handler mHandler;
+ protected H mHandler;
private boolean mIsVisible;
private boolean mIsIconVisible;
@@ -83,7 +83,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
mMainHandler = new Handler(Looper.getMainLooper());
mActivityStarter = Dependency.get(ActivityStarter.class);
mSecurityController = Dependency.get(SecurityController.class);
- mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
+ mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
}
public void setHostEnvironment(QSTileHost host) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index c8f167063add..95e0301f81c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -74,8 +74,14 @@ public class QSFragment extends Fragment implements QS {
mContainer = (QSContainerImpl) view;
mQSDetail.setQsPanel(mQSPanel, mHeader);
- mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
- mQSPanel);
+
+ // If the quick settings row is not shown, then there is no need for the animation from
+ // the row to the full QS panel.
+ if (getResources().getBoolean(R.bool.config_showQuickSettingsRow)) {
+ mQSAnimator = new QSAnimator(this,
+ (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
+ }
+
mQSCustomizer = (QSCustomizer) view.findViewById(R.id.qs_customize);
mQSCustomizer.setQs(this);
}
@@ -89,7 +95,10 @@ public class QSFragment extends Fragment implements QS {
super.onConfigurationChanged(newConfig);
if (newConfig.getLayoutDirection() != mLayoutDirection) {
mLayoutDirection = newConfig.getLayoutDirection();
- mQSAnimator.onRtlChanged();
+
+ if (mQSAnimator != null) {
+ mQSAnimator.onRtlChanged();
+ }
}
}
@@ -108,7 +117,10 @@ public class QSFragment extends Fragment implements QS {
mQSPanel.setHost(qsh, mQSCustomizer);
mHeader.setQSPanel(mQSPanel);
mQSDetail.setHost(qsh);
- mQSAnimator.setHost(qsh);
+
+ if (mQSAnimator != null) {
+ mQSAnimator.setHost(qsh);
+ }
}
private void updateQsState() {
@@ -155,7 +167,11 @@ public class QSFragment extends Fragment implements QS {
public void setKeyguardShowing(boolean keyguardShowing) {
if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
mKeyguardShowing = keyguardShowing;
- mQSAnimator.setOnKeyguard(keyguardShowing);
+
+ if (mQSAnimator != null) {
+ mQSAnimator.setOnKeyguard(keyguardShowing);
+ }
+
updateQsState();
}
@@ -187,7 +203,10 @@ public class QSFragment extends Fragment implements QS {
mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
mQSDetail.setFullyExpanded(expansion == 1);
- mQSAnimator.setPosition(expansion);
+
+ if (mQSAnimator != null) {
+ mQSAnimator.setPosition(expansion);
+ }
// Set bounds on the QS panel so it doesn't run over the header.
mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index e0048284f669..504678c7f1c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -29,6 +29,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
@@ -126,7 +127,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS);
+ Dependency.get(TunerService.class).addTunable(this, QS_SHOW_BRIGHTNESS);
if (mHost != null) {
setTiles(mHost.getTiles());
}
@@ -134,8 +135,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
@Override
protected void onDetachedFromWindow() {
- TunerService.get(mContext).removeTunable(this);
- mHost.removeCallback(this);
+ Dependency.get(TunerService.class).removeTunable(this);
+ if (mHost != null) {
+ mHost.removeCallback(this);
+ }
for (TileRecord record : mRecords) {
record.tile.removeCallbacks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index e18654e7253a..0829ae5f597c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -323,9 +323,10 @@ public abstract class QSTile<TState extends State> {
return Utils.getDisabled(context,
Utils.getColorAttr(context, android.R.attr.textColorTertiary));
case Tile.STATE_INACTIVE:
- return Utils.getColorAttr(context, android.R.attr.textColorSecondary);
+ return Utils.getDisabled(context,
+ Utils.getColorAttr(context, android.R.attr.colorForeground));
case Tile.STATE_ACTIVE:
- return Utils.getColorAttr(context, android.R.attr.colorPrimary);
+ return Utils.getColorAttr(context, android.R.attr.colorForeground);
default:
Log.e("QSTile", "Invalid state " + state);
return 0;
@@ -548,6 +549,7 @@ public abstract class QSTile<TState extends State> {
public CharSequence minimalContentDescription;
public boolean autoMirrorDrawable = true;
public boolean disabledByPolicy;
+ public boolean dualTarget = false;
public EnforcedAdmin enforcedAdmin;
public String minimalAccessibilityClassName;
public String expandedAccessibilityClassName;
@@ -569,7 +571,8 @@ public abstract class QSTile<TState extends State> {
expandedAccessibilityClassName)
|| !Objects.equals(other.disabledByPolicy, disabledByPolicy)
|| !Objects.equals(other.state, state)
- || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
+ || !Objects.equals(other.enforcedAdmin, enforcedAdmin)
+ || !Objects.equals(other.dualTarget, dualTarget);
other.icon = icon;
other.label = label;
other.contentDescription = contentDescription;
@@ -580,6 +583,7 @@ public abstract class QSTile<TState extends State> {
other.autoMirrorDrawable = autoMirrorDrawable;
other.disabledByPolicy = disabledByPolicy;
other.state = state;
+ other.dualTarget = dualTarget;
if (enforcedAdmin == null) {
other.enforcedAdmin = null;
} else if (other.enforcedAdmin == null) {
@@ -607,6 +611,7 @@ public abstract class QSTile<TState extends State> {
sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
sb.append(",disabledByPolicy=").append(disabledByPolicy);
sb.append(",enforcedAdmin=").append(enforcedAdmin);
+ sb.append(",dualTarget=").append(dualTarget);
sb.append(",state=").append(state);
return sb.append(']');
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index a177cc323486..0e04d0a0c825 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -47,17 +47,12 @@ public class QSTileBaseView extends LinearLayout {
private static final String TAG = "QSTileBaseView";
private final H mHandler = new H();
- private final ImageView mBg;
protected QSIconView mIcon;
protected RippleDrawable mRipple;
private Drawable mTileBackground;
private String mAccessibilityClass;
private boolean mTileState;
private boolean mCollapsedView;
- private final int mColorActive;
- private final int mColorInactive;
- private final int mColorDisabled;
- private int mCircleColor;
public QSTileBaseView(Context context, QSIconView icon) {
this(context, icon, false);
@@ -72,19 +67,11 @@ public class QSTileBaseView extends LinearLayout {
frame.setForegroundGravity(Gravity.CENTER);
int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
addView(frame, new LayoutParams(size, size));
- mBg = new ImageView(getContext());
- mBg.setScaleType(ScaleType.FIT_CENTER);
- mBg.setImageResource(R.drawable.ic_qs_circle);
- frame.addView(mBg);
mIcon = icon;
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, padding, 0, padding);
frame.addView(mIcon, params);
- mColorActive = Utils.getColorAttr(context, android.R.attr.textColorPrimary);
- mColorDisabled = Utils.getDisabled(context,
- Utils.getColorAttr(context, android.R.attr.textColorTertiary));
- mColorInactive = Utils.getColorAttr(context, android.R.attr.textColorSecondary);
mTileBackground = newTileBackground();
if (mTileBackground instanceof RippleDrawable) {
@@ -100,10 +87,6 @@ public class QSTileBaseView extends LinearLayout {
setFocusable(true);
}
- public View getBgCicle() {
- return mBg;
- }
-
protected Drawable newTileBackground() {
final int[] attrs = new int[]{android.R.attr.selectableItemBackgroundBorderless};
final TypedArray ta = getContext().obtainStyledAttributes(attrs);
@@ -167,16 +150,6 @@ public class QSTileBaseView extends LinearLayout {
}
protected void handleStateChanged(QSTile.State state) {
- int circleColor = getCircleColor(state.state);
- if (circleColor != mCircleColor) {
- if (mBg.isShown()) {
- QSIconView.animateGrayScale(mCircleColor, circleColor, mBg);
- } else {
- QSIconView.setTint(mBg, circleColor);
- }
- mCircleColor = circleColor;
- }
-
mIcon.setIcon(state);
if (mCollapsedView && !TextUtils.isEmpty(state.minimalContentDescription)) {
setContentDescription(state.minimalContentDescription);
@@ -193,19 +166,6 @@ public class QSTileBaseView extends LinearLayout {
}
}
- private int getCircleColor(int state) {
- switch (state) {
- case Tile.STATE_ACTIVE:
- return mColorActive;
- case Tile.STATE_INACTIVE:
- case Tile.STATE_UNAVAILABLE:
- return mColorDisabled;
- default:
- Log.e(TAG, "Invalid state " + state);
- return 0;
- }
- }
-
public QSIconView getIcon() {
return mIcon;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 7126f3c8057f..232941dc629b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -39,6 +39,7 @@ import libcore.util.Objects;
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
+ private final View mDivider;
protected TextView mLabel;
private ImageView mPadLock;
private int mState;
@@ -57,6 +58,8 @@ public class QSTileView extends QSTileBaseView {
setClickable(true);
setId(View.generateViewId());
+ mDivider = LayoutInflater.from(context).inflate(R.layout.divider, this, false);
+ addView(mDivider);
createLabel();
setOrientation(VERTICAL);
setGravity(Gravity.CENTER);
@@ -95,6 +98,7 @@ public class QSTileView extends QSTileBaseView {
mState = state.state;
mLabel.setText(state.label);
}
+ mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE);
mLabel.setEnabled(!state.disabledByPolicy);
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 16b351e5b701..d789b446c253 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -24,6 +24,7 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.Space;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.SignalState;
import com.android.systemui.qs.QSTile.State;
@@ -62,13 +63,13 @@ public class QuickQSPanel extends QSPanel {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
+ Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- TunerService.get(mContext).removeTunable(mNumTiles);
+ Dependency.get(TunerService.class).removeTunable(mNumTiles);
}
public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
@@ -141,7 +142,7 @@ public class QuickQSPanel extends QSPanel {
};
public int getNumQuickTiles(Context context) {
- return TunerService.get(context).getValue(NUM_QUICK_TILES, 6);
+ return Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, 6);
}
private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index a5a1eaaf6662..3b9e7bcfb9b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -99,8 +99,9 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
previousView = record.tileView.updateAccessibilityOrder(previousView);
}
- setMeasuredDimension(width,
- (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin));
+ int height = (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin);
+ if (height < 0) height = 0;
+ setMeasuredDimension(width, height);
}
private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 3afbc351582b..dea56aa11fde 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -237,6 +237,8 @@ public class CustomTile extends QSTile<QSTile.State> implements TileChangeListen
i.setPackage(mComponent.getPackageName());
i = resolveIntent(i);
if (i != null) {
+ i.putExtra(TileService.EXTRA_COMPONENT, mComponent);
+ i.putExtra(TileService.EXTRA_STATE, mTile.getState());
return i;
}
return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 5c23eb742270..ce7294204b48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -307,8 +307,10 @@ public class TileServices extends IQSService.Stub {
}
public void destroy() {
- mServices.values().forEach(service -> service.handleDestroy());
- mContext.unregisterReceiver(mRequestListeningReceiver);
+ synchronized (mServices) {
+ mServices.values().forEach(service -> service.handleDestroy());
+ mContext.unregisterReceiver(mRequestListeningReceiver);
+ }
}
private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 7e04b6754920..6f1f9774a9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,7 +19,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@@ -42,8 +41,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.qs.external.TileColorPicker;
import com.android.systemui.statusbar.policy.BatteryController;
import java.text.NumberFormat;
@@ -121,6 +118,7 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
int level = (arg != null) ? (Integer) arg : mLevel;
String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+ state.dualTarget = true;
state.state = mCharging ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 91e76cabbc01..4b56ecdfade7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -115,6 +115,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
final boolean enabled = mController.isBluetoothEnabled();
final boolean connected = mController.isBluetoothConnected();
final boolean connecting = mController.isBluetoothConnecting();
+ state.dualTarget = true;
state.value = enabled;
state.autoMirrorDrawable = false;
state.minimalContentDescription =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 7415765ff2cc..a4cd14d77926 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -123,6 +123,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ state.dualTarget = true;
state.label = mContext.getString(R.string.quick_settings_cast_title);
state.contentDescription = state.label;
state.value = false;
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 75c4a753992d..bae163fc1451 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -38,7 +38,7 @@ import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.SignalTileView;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTile<QSTile.SignalState> {
@@ -126,6 +126,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
} else {
state.icon = ResourceIcon.get(iconId);
}
+ state.dualTarget = true;
state.isOverlayIconWide = cb.isDataTypeIconWide;
state.autoMirrorDrawable = !cb.noSim;
state.filter = iconId != R.drawable.ic_qs_no_sim;
@@ -197,9 +198,10 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
String enabledDesc;
boolean noSim;
boolean isDataTypeIconWide;
+ boolean roaming;
}
- private final class CellSignalCallback extends SignalCallbackAdapter {
+ private final class CellSignalCallback implements SignalCallback {
private final CallbackInfo mInfo = new CallbackInfo();
@Override
public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
@@ -211,7 +213,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
+ String description, boolean isWide, int subId, boolean roaming) {
if (qsIcon == null) {
// Not data sim, don't display.
return;
@@ -225,6 +227,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
mInfo.activityOut = activityOut;
mInfo.enabledDesc = description;
mInfo.isDataTypeIconWide = qsType != 0 && isWide;
+ mInfo.roaming = roaming;
refreshState(mInfo);
}
@@ -294,6 +297,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
final DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
if (info == null) return v;
v.bind(info);
+ v.findViewById(R.id.roaming_text).setVisibility(mSignalCallback.mInfo.roaming
+ ? View.VISIBLE : View.INVISIBLE);
return v;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 3c1f50461b63..4072b4442377 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -159,6 +159,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != Global.ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
+ state.dualTarget = true;
state.value = newValue;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 70f81096bb79..dab5967e5e91 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,9 @@
package com.android.systemui.qs.tiles;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserManager;
@@ -37,6 +40,9 @@ import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
+ static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+ "com.android.settings", "com.android.settings.TetherSettings"));
+
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
R.drawable.ic_hotspot_disable);
@@ -94,7 +100,7 @@ public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
@Override
public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+ return new Intent(TETHER_SETTINGS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 54b41ac5e46d..90a9db6b189f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -43,7 +43,7 @@ import com.android.systemui.qs.SignalTileView;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.util.List;
@@ -150,6 +150,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
mDetailAdapter.setItemsVisible(cb.enabled);
fireToggleStateChanged(cb.enabled);
}
+ state.dualTarget = true;
state.value = cb.enabled;
state.connected = wifiConnected;
state.activityIn = cb.enabled && cb.activityIn;
@@ -256,7 +257,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
}
- protected final class WifiSignalCallback extends SignalCallbackAdapter {
+ protected final class WifiSignalCallback implements SignalCallback {
final CallbackInfo mInfo = new CallbackInfo();
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0265c9e40112..e635162807e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
+
import android.app.ActivityManager;
import android.app.UiModeManager;
import android.content.ComponentName;
@@ -38,6 +40,7 @@ import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
import android.view.Display;
+import android.view.WindowManager;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
@@ -59,6 +62,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.tv.RecentsTvImpl;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.CommandQueue;
import java.util.ArrayList;
import java.util.HashSet;
@@ -70,7 +74,7 @@ import java.util.Set;
* users.
*/
public class Recents extends SystemUI
- implements RecentsComponent {
+ implements RecentsComponent, CommandQueue.Callbacks {
private final static String TAG = "Recents";
private final static boolean DEBUG = false;
@@ -229,6 +233,7 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(processUser)) {
// For the system user, initialize an instance of the interface that we can pass to the
// secondary user
+ getComponent(CommandQueue.class).addCallbacks(this);
mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
} else {
// For the secondary user, bind to the primary user's service to get a persistent
@@ -247,7 +252,7 @@ public class Recents extends SystemUI
* Shows the Recents.
*/
@Override
- public void showRecents(boolean triggeredFromAltTab, boolean fromHome) {
+ public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
@@ -257,6 +262,10 @@ public class Recents extends SystemUI
if (proxyToOverridePackage(ACTION_SHOW_RECENTS)) {
return;
}
+ try {
+ ActivityManager.getService().closeSystemDialogs(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ } catch (RemoteException e) {
+ }
int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
@@ -287,7 +296,7 @@ public class Recents extends SystemUI
* Hides the Recents.
*/
@Override
- public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+ public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
@@ -318,6 +327,11 @@ public class Recents extends SystemUI
}
}
+ @Override
+ public void toggleRecentApps() {
+ toggleRecents(mContext.getSystemService(WindowManager.class).getDefaultDisplay());
+ }
+
/**
* Toggles the Recents activity.
*/
@@ -387,7 +401,7 @@ public class Recents extends SystemUI
}
@Override
- public void cancelPreloadingRecents() {
+ public void cancelPreloadRecentApps() {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
@@ -438,7 +452,7 @@ public class Recents extends SystemUI
ActivityManager.StackId.isHomeOrRecentsStack(runningTask.stackId);
if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
- if (runningTask.isDockable) {
+ if (runningTask.supportsSplitScreenMultiWindow) {
if (metricsDockAction != -1) {
MetricsLogger.action(mContext, metricsDockAction,
runningTask.topActivity.flattenToShortString());
@@ -486,7 +500,6 @@ public class Recents extends SystemUI
case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE:
return COUNTER_WINDOW_UNSUPPORTED;
case ActivityInfo.RESIZE_MODE_RESIZEABLE:
- case ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
case ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION:
return COUNTER_WINDOW_SUPPORTED;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 06fadd1b08ae..a6fe0ea2ea73 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -88,7 +88,7 @@ import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
-import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -283,7 +283,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
overrideAnimation));
Recents.getSystemServices().sendCloseSystemWindows(
- BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
EventBus.getDefault().send(dismissEvent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index cf6357b7d59f..55491b24e20d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -18,7 +18,6 @@ package com.android.systemui.recents;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.app.ActivityManager.StackId.isHomeOrRecentsStack;
import static android.view.View.MeasureSpec;
@@ -54,6 +53,7 @@ import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchMostRecentTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
@@ -76,10 +76,10 @@ import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskStackViewScroller;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
@@ -229,7 +229,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
*/
public void onStartScreenPinning(Context context, int taskId) {
SystemUIApplication app = (SystemUIApplication) context;
- PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
+ StatusBar statusBar = app.getComponent(StatusBar.class);
if (statusBar != null) {
statusBar.showScreenPinningRequest(taskId, false);
}
@@ -313,15 +313,23 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!launchState.launchedWithAltTab) {
- // If the user taps quickly
- if (!debugFlags.isPagingEnabled() ||
- (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
- elapsedTime < ViewConfiguration.getDoubleTapTimeout())) {
- // Launch the next focused task
- EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
+ // Has the user tapped quickly?
+ boolean isQuickTap = ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
+ elapsedTime < ViewConfiguration.getDoubleTapTimeout();
+ if (Recents.getConfiguration().isGridEnabled) {
+ if (isQuickTap) {
+ EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
+ } else {
+ EventBus.getDefault().post(new LaunchMostRecentTaskRequestEvent());
+ }
} else {
- // Notify recents to move onto the next task
- EventBus.getDefault().post(new IterateRecentsEvent());
+ if (!debugFlags.isPagingEnabled() || isQuickTap) {
+ // Launch the next focused task
+ EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
+ } else {
+ // Notify recents to move onto the next task
+ EventBus.getDefault().post(new IterateRecentsEvent());
+ }
}
} else {
// If the user has toggled it too quickly, then just eat up the event here (it's
@@ -351,7 +359,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
growTarget);
// Only close the other system windows if we are actually showing recents
- ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
+ ssp.sendCloseSystemWindows(StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
mLastToggleTime = SystemClock.elapsedRealtime();
}
} catch (ActivityNotFoundException e) {
@@ -630,13 +638,28 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
+ // Get the width of a task view so that we know how wide to draw the header bar.
+ int taskViewWidth = 0;
+ if (mDummyStackView.useGridLayout()) {
+ TaskGridLayoutAlgorithm gridLayout = mDummyStackView.getGridAlgorithm();
+ gridLayout.initialize(windowRect);
+ taskViewWidth = (int) gridLayout.getTransform(0 /* taskIndex */,
+ stack.getTaskCount(), new TaskViewTransform(), stackLayout).rect.width();
+ } else {
+ Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
+ if (!taskViewBounds.isEmpty()) {
+ taskViewWidth = taskViewBounds.width();
+ }
+ }
- Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
- if (!taskViewBounds.isEmpty()) {
- int taskViewWidth = taskViewBounds.width();
+ if (taskViewWidth > 0) {
synchronized (mHeaderBarLock) {
if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
+ if (mDummyStackView.useGridLayout()) {
+ mHeaderBar.setShouldDarkenBackgroundColor(true);
+ mHeaderBar.setNoUserInteractionState();
+ }
mHeaderBar.forceLayout();
mHeaderBar.measure(
MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
@@ -745,11 +768,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
Task toTask = new Task();
TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
windowOverrideRect);
- // When using a grid layout, the header is already visible on screen at the target
- // location, making it unnecessary to draw it in the transition thumbnail.
- Bitmap thumbnail = stackView.useGridLayout()
- ? mThumbTransitionBitmapCache.createAshmemBitmap()
- : drawThumbnailTransitionBitmap(toTask, toTransform,
+ Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
mThumbTransitionBitmapCache);
if (thumbnail != null) {
RectF toTaskRect = toTransform.rect;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java
new file mode 100644
index 000000000000..24913a4c2ca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java
@@ -0,0 +1,26 @@
+/*
+ * 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.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This event is sent to request that the most recent task is launched.
+ */
+public class LaunchMostRecentTaskRequestEvent extends EventBus.Event {
+ // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 5c7496d437f4..11b598478bfb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -197,7 +197,7 @@ public class RecentsTaskLoadPlan {
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
- t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity,
+ t.supportsSplitScreenMultiWindow, t.bounds, t.taskDescription, t.resizeMode, t.topActivity,
isLocked);
allTasks.add(task);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index a2a819988ff3..a691a424e779 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -30,6 +30,8 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout.LayoutParams;
import com.android.systemui.R;
+import com.android.systemui.pip.tv.PipManager;
+import com.android.systemui.pip.tv.PipRecentsOverlayManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
@@ -57,9 +59,7 @@ import com.android.systemui.recents.tv.views.RecentsTvView;
import com.android.systemui.recents.tv.views.TaskCardView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.pip.tv.PipManager;
-import com.android.systemui.pip.tv.PipRecentsOverlayManager;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
import java.util.Collections;
@@ -258,7 +258,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
@Override
public void run() {
Recents.getSystemServices().sendCloseSystemWindows(
- BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
}
};
DismissRecentsToHomeAnimationStarted dismissEvent =
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 2bd651b7decd..6a66fca79f76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -51,7 +51,7 @@ import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
import java.util.Collections;
@@ -170,7 +170,7 @@ public class RecentsTransitionHelper {
}
}
Recents.getSystemServices().sendCloseSystemWindows(
- BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
}
public IRemoteCallback wrapStartedListener(final OnAnimationStartedListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index a2ee4c565ff8..f1314aba1b46 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -619,7 +619,7 @@ public class TaskStackAnimationHelper {
postAnimationTrigger.addLastDecrementRunnable(() -> {
mStackView.getTouchHandler().onChildDismissed(deleteTaskView);
});
- deleteTaskView.animate().setDuration(300).scaleX(0).scaleY(0).alpha(0).setListener(
+ deleteTaskView.animate().setDuration(300).scaleX(0.9f).scaleY(0.9f).alpha(0).setListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 8ae7a838e7f3..0160eb75773e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -64,6 +64,7 @@ import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationC
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchMostRecentTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
@@ -95,6 +96,7 @@ import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.grid.GridTaskView;
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -446,6 +448,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return mLayoutAlgorithm;
}
+ /** Returns the grid algorithm for this task stack. */
+ public TaskGridLayoutAlgorithm getGridAlgorithm() {
+ return mLayoutAlgorithm.mTaskGridLayoutAlgorithm;
+ }
+
/**
* Returns the touch handler for this task stack.
*/
@@ -1733,6 +1740,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mUIDozeTrigger.stopDozing();
}
+ public final void onBusEvent(LaunchMostRecentTaskRequestEvent event) {
+ if (mStack.getTaskCount() > 0) {
+ Task mostRecentTask = mStack.getStackFrontMostTask(true /* includeFreefromTasks */);
+ launchTask(mostRecentTask);
+ }
+ }
+
public final void onBusEvent(LaunchNextTaskRequestEvent event) {
if (mAwaitingFirstLayout) {
mLaunchNextAfterFirstMeasure = true;
@@ -1741,29 +1755,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
final Task launchTask = mStack.getNextLaunchTarget();
if (launchTask != null) {
- // Stop all animations
- cancelAllTaskViewAnimations();
-
- float curScroll = mStackScroller.getStackScroll();
- float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
- float absScrollDiff = Math.abs(targetScroll - curScroll);
- if (getChildViewForTask(launchTask) == null || absScrollDiff > 0.35f) {
- int duration = (int) (LAUNCH_NEXT_SCROLL_BASE_DURATION +
- absScrollDiff * LAUNCH_NEXT_SCROLL_INCR_DURATION);
- mStackScroller.animateScroll(targetScroll,
- duration, new Runnable() {
- @Override
- public void run() {
- EventBus.getDefault().send(new LaunchTaskEvent(
- getChildViewForTask(launchTask), launchTask, null,
- INVALID_STACK_ID, false /* screenPinningRequested */));
- }
- });
- } else {
- EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
- launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
- }
-
+ launchTask(launchTask);
MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
launchTask.key.getComponent().toString());
} else if (mStack.getTaskCount() == 0) {
@@ -2215,6 +2207,31 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return -1;
}
+ private void launchTask(Task task) {
+ // Stop all animations
+ cancelAllTaskViewAnimations();
+
+ float curScroll = mStackScroller.getStackScroll();
+ float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(task);
+ float absScrollDiff = Math.abs(targetScroll - curScroll);
+ if (getChildViewForTask(task) == null || absScrollDiff > 0.35f) {
+ int duration = (int) (LAUNCH_NEXT_SCROLL_BASE_DURATION +
+ absScrollDiff * LAUNCH_NEXT_SCROLL_INCR_DURATION);
+ mStackScroller.animateScroll(targetScroll,
+ duration, new Runnable() {
+ @Override
+ public void run() {
+ EventBus.getDefault().send(new LaunchTaskEvent(
+ getChildViewForTask(task), task, null,
+ INVALID_STACK_ID, false /* screenPinningRequested */));
+ }
+ });
+ } else {
+ EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task),
+ task, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+ }
+ }
+
/**
* Check whether we should use the grid layout.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index e941c3bacfcb..9a52a7b7d5c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -151,7 +151,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
protected TaskViewThumbnail mThumbnailView;
@ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
- TaskViewHeader mHeaderView;
+ protected TaskViewHeader mHeaderView;
private View mActionButtonView;
private View mIncompatibleAppToastView;
private TaskViewCallbacks mCb;
@@ -258,11 +258,6 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
@Override
- public void addChildrenForAccessibility(ArrayList<View> outChildren) {
- // Prevent any children from being focusable during talkback
- }
-
- @Override
public boolean hasOverlappingRendering() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
index 759daf1e0f12..2c3e78f8cb84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -18,7 +18,6 @@ package com.android.systemui.recents.views;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.util.SparseArray;
@@ -29,6 +28,7 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.Utilities;
@@ -39,8 +39,6 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
private final TaskView mTaskView;
- protected static final int OPEN = R.id.action_open;
- protected static final int DIMISS = R.id.action_dimiss;
protected static final int SPLIT_TASK_TOP = R.id.action_split_task_to_top;
protected static final int SPLIT_TASK_LEFT = R.id.action_split_task_to_left;
protected static final int SPLIT_TASK_RIGHT = R.id.action_split_task_to_right;
@@ -50,10 +48,6 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
public TaskViewAccessibilityDelegate(TaskView taskView) {
mTaskView = taskView;
Context context = taskView.getContext();
- mActions.put(OPEN, new AccessibilityAction(OPEN,
- context.getString(R.string.recents_accessibility_open)));
- mActions.put(DIMISS, new AccessibilityAction(DIMISS,
- context.getString(R.string.recents_accessibility_dismissed)));
mActions.put(SPLIT_TASK_TOP, new AccessibilityAction(SPLIT_TASK_TOP,
context.getString(R.string.recents_accessibility_split_screen_top)));
mActions.put(SPLIT_TASK_LEFT, new AccessibilityAction(SPLIT_TASK_LEFT,
@@ -65,8 +59,6 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- info.addAction(mActions.get(OPEN));
- info.addAction(mActions.get(DIMISS));
if (ActivityManager.supportsSplitScreenMultiWindow()
&& !Recents.getSystemServices().hasDockedTask()) {
TaskStack.DockState[] dockStates = Recents.getConfiguration()
@@ -85,11 +77,7 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == OPEN) {
- mTaskView.onClick(host);
- } else if (action == DIMISS) {
- mTaskView.dismissTask();
- } else if (action == SPLIT_TASK_TOP) {
+ if (action == SPLIT_TASK_TOP) {
simulateDragIntoMultiwindow(TaskStack.DockState.TOP);
} else if (action == SPLIT_TASK_LEFT) {
simulateDragIntoMultiwindow(TaskStack.DockState.LEFT);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 0777163293d9..dc666e90fbdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -91,6 +91,9 @@ public class TaskViewHeader extends FrameLayout
if (mColor != color || Float.compare(mDimAlpha, dimAlpha) != 0) {
mColor = color;
mDimAlpha = dimAlpha;
+ if (mShouldDarkenBackgroundColor) {
+ color = getSecondaryColor(color, false /* useLightOverlayColor */);
+ }
mBackgroundPaint.setColor(color);
ColorUtils.colorToHSL(color, mTmpHSL);
@@ -179,6 +182,10 @@ public class TaskViewHeader extends FrameLayout
// Header dim, which is only used when task view hardware layers are not used
private Paint mDimLayerPaint = new Paint();
+ // Whether the background color should be darkened to differentiate from the primary color.
+ // Used in grid layout.
+ private boolean mShouldDarkenBackgroundColor = false;
+
private CountDownTimer mFocusTimerCountDown;
public TaskViewHeader(Context context) {
@@ -443,6 +450,13 @@ public class TaskViewHeader extends FrameLayout
}
/**
+ * Sets whether the background color should be darkened to differentiate from the primary color.
+ */
+ public void setShouldDarkenBackgroundColor(boolean flag) {
+ mShouldDarkenBackgroundColor = flag;
+ }
+
+ /**
* Binds the bar view to the task.
*/
public void bindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
@@ -557,7 +571,7 @@ public class TaskViewHeader extends FrameLayout
* Mark this task view that the user does has not interacted with the stack after a certain
* time.
*/
- void setNoUserInteractionState() {
+ public void setNoUserInteractionState() {
mDismissButton.setVisibility(View.VISIBLE);
mDismissButton.animate().cancel();
mDismissButton.setAlpha(1f);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
index a86abf629109..8b4700c54b00 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -53,6 +53,7 @@ public class GridTaskView extends TaskView {
mThumbnailView.setOverlayHeaderOnThumbnailActionBar(false);
mThumbnailView.updateThumbnailMatrix();
mThumbnailView.setTranslationY(mHeaderHeight);
+ mHeaderView.setShouldDarkenBackgroundColor(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index 02d1cc14fc41..4f175368aceb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -74,11 +74,8 @@ public class TaskGridLayoutAlgorithm {
yOffsets = new int[taskCount];
int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount);
-
- tasksPerLine = layoutTaskCount < 2 ? 1 : (
- layoutTaskCount < 5 ? 2 : (
- layoutTaskCount < 7 ? 3 : 4));
- lines = layoutTaskCount < 3 ? 1 : 2;
+ tasksPerLine = getTasksPerLine(layoutTaskCount);
+ lines = layoutTaskCount < 4 ? 1 : 2;
// A couple of special cases.
boolean landscapeWindow = mWindowRect.width() > mWindowRect.height();
@@ -131,6 +128,27 @@ public class TaskGridLayoutAlgorithm {
emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex;
}
}
+
+ private int getTasksPerLine(int taskCount) {
+ switch(taskCount) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ case 4:
+ return 2;
+ case 3:
+ case 5:
+ case 6:
+ return 3;
+ case 7:
+ case 8:
+ return 4;
+ default:
+ throw new IllegalArgumentException("Unsupported task count " + taskCount);
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index db021ffee9b6..9a4b45a7b0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -62,6 +62,7 @@ import android.widget.ImageView;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.util.NotificationChannels;
import java.io.File;
import java.io.FileOutputStream;
@@ -177,18 +178,19 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
.bigPicture(picture.createAshmemBitmap());
// The public notification will show similar info but with the actual screenshot omitted
- mPublicNotificationBuilder = new Notification.Builder(context)
- .setContentTitle(r.getString(R.string.screenshot_saving_title))
- .setContentText(r.getString(R.string.screenshot_saving_text))
- .setSmallIcon(R.drawable.stat_notify_image)
- .setCategory(Notification.CATEGORY_PROGRESS)
- .setWhen(now)
- .setShowWhen(true)
- .setColor(r.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ mPublicNotificationBuilder =
+ new Notification.Builder(context, NotificationChannels.SCREENSHOTS)
+ .setContentTitle(r.getString(R.string.screenshot_saving_title))
+ .setContentText(r.getString(R.string.screenshot_saving_text))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setWhen(now)
+ .setShowWhen(true)
+ .setColor(r.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder);
- mNotificationBuilder = new Notification.Builder(context)
+ mNotificationBuilder = new Notification.Builder(context, NotificationChannels.SCREENSHOTS)
.setTicker(r.getString(R.string.screenshot_saving_ticker)
+ (mTickerAddSpace ? " " : ""))
.setContentTitle(r.getString(R.string.screenshot_saving_title))
@@ -853,7 +855,7 @@ class GlobalScreenshot {
String errorMsg = r.getString(msgResId);
// Repurpose the existing notification to notify the user of the error
- Notification.Builder b = new Notification.Builder(context)
+ Notification.Builder b = new Notification.Builder(context, NotificationChannels.ALERTS)
.setTicker(r.getString(R.string.screenshot_failed_title))
.setContentTitle(r.getString(R.string.screenshot_failed_title))
.setContentText(errorMsg)
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 19eefec2ad8b..7699bb90e611 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -107,7 +107,7 @@ public class ShortcutKeyDispatcher extends SystemUI
List<ActivityManager.RecentTaskInfo> taskList =
SystemServicesProxy.getInstance(mContext).getRecentTasks(1,
UserHandle.USER_CURRENT, false, new ArraySet<>());
- recents.showRecents(
+ recents.showRecentApps(
false /* triggeredFromAltTab */,
false /* fromHome */);
if (!taskList.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 3cd2a7a1011a..0b09accf2db1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -44,6 +44,7 @@ public class Divider extends SystemUI {
private boolean mVisible = false;
private boolean mMinimized = false;
private boolean mAdjustedForIme = false;
+ private boolean mHomeStackResizable = false;
private ForcedResizableInfoActivityController mForcedResizableController;
@Override
@@ -71,10 +72,15 @@ public class Divider extends SystemUI {
return mMinimized;
}
+ public boolean isHomeStackResizable() {
+ return mHomeStackResizable;
+ }
+
private void addDivider(Configuration configuration) {
mView = (DividerView)
LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
final int size = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
@@ -92,7 +98,7 @@ public class Divider extends SystemUI {
removeDivider();
addDivider(configuration);
if (mMinimized) {
- mView.setMinimizedDockStack(true);
+ mView.setMinimizedDockStack(true, mHomeStackResizable);
updateTouchable();
}
}
@@ -106,23 +112,25 @@ public class Divider extends SystemUI {
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
// Update state because animations won't finish.
- mView.setMinimizedDockStack(mMinimized);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
}
}
});
}
- private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) {
+ private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
+ final boolean isHomeStackResizable) {
mView.post(new Runnable() {
@Override
public void run() {
+ mHomeStackResizable = isHomeStackResizable;
if (mMinimized != minimized) {
mMinimized = minimized;
updateTouchable();
if (animDuration > 0) {
- mView.setMinimizedDockStack(minimized, animDuration);
+ mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
} else {
- mView.setMinimizedDockStack(minimized);
+ mView.setMinimizedDockStack(minimized, isHomeStackResizable);
}
}
}
@@ -139,7 +147,7 @@ public class Divider extends SystemUI {
}
private void updateTouchable() {
- mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme);
+ mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
}
@Override
@@ -162,9 +170,10 @@ public class Divider extends SystemUI {
}
@Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
- throws RemoteException {
- updateMinimizedDockedStack(minimized, animDuration);
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
+ boolean isHomeStackResizable) throws RemoteException {
+ mHomeStackResizable = isHomeStackResizable;
+ updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 47d2def0cf63..6f59fe2001a1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -64,6 +64,7 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
@@ -123,6 +124,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private boolean mMoving;
private int mTouchSlop;
private boolean mBackgroundLifted;
+ private boolean mIsInMinimizeInteraction;
+ private int mDividerPositionBeforeMinimized;
private int mDividerInsets;
private int mDisplayWidth;
@@ -145,6 +148,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
private DividerSnapAlgorithm mSnapAlgorithm;
+ private DividerSnapAlgorithm mMinimizedSnapAlgorithm;
private final Rect mStableInsets = new Rect();
private boolean mGrowRecents;
@@ -154,6 +158,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private int mExitStartPosition;
private GestureDetector mGestureDetector;
private boolean mDockedStackMinimized;
+ private boolean mHomeStackResizable;
private boolean mAdjustedForIme;
private DividerState mState;
@@ -350,8 +355,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|| mStableInsets.bottom != insets.getStableInsetBottom()) {
mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
insets.getStableInsetRight(), insets.getStableInsetBottom());
- if (mSnapAlgorithm != null) {
+ if (mSnapAlgorithm != null || mMinimizedSnapAlgorithm != null) {
mSnapAlgorithm = null;
+ mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}
}
@@ -446,11 +452,17 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
}
+ if (mMinimizedSnapAlgorithm == null) {
+ mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
+ mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
+ mStableInsets, mDockedStackMinimized && mHomeStackResizable);
+ }
}
public DividerSnapAlgorithm getSnapAlgorithm() {
initializeSnapAlgorithm();
- return mSnapAlgorithm;
+ return mDockedStackMinimized && mHomeStackResizable ? mMinimizedSnapAlgorithm :
+ mSnapAlgorithm;
}
public int getCurrentPosition() {
@@ -495,7 +507,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mMoving = true;
}
if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
- SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
+ SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
mStartPosition, 0 /* velocity */, false /* hardDismiss */);
resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget);
}
@@ -551,9 +563,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private void fling(int position, float velocity, boolean avoidDismissStart,
boolean logMetrics) {
- SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
- if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
- snapTarget = mSnapAlgorithm.getFirstSplitTarget();
+ DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
+ SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
+ if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
+ snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
}
if (logMetrics) {
logResizeEvent(snapTarget);
@@ -574,6 +587,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
final long endDelay) {
+ if (mCurrentAnimator != null) {
+ cancelFlingAnimation();
+ updateDockSide();
+ }
final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(),
@@ -590,6 +607,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mExitAnimationRunning = false;
EventBus.getDefault().send(new StoppedDragingEvent());
};
+ Runnable notCancelledEndAction = () -> {
+ // Reset minimized divider position after unminimized state animation finishes
+ if (!mDockedStackMinimized && mIsInMinimizeInteraction) {
+ mIsInMinimizeInteraction = false;
+ }
+ };
anim.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -612,8 +635,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
if (delay == 0) {
endAction.run();
+ if (!mCancelled) {
+ notCancelledEndAction.run();
+ }
} else {
mHandler.postDelayed(endAction, delay);
+ if (!mCancelled) {
+ mHandler.postDelayed(notCancelledEndAction, delay);
+ }
}
}
});
@@ -692,57 +721,92 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
- public void setMinimizedDockStack(boolean minimized) {
+ public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
+ mHomeStackResizable = isHomeStackResizable;
updateDockSide();
- mHandle.setAlpha(minimized ? 0f : 1f);
if (!minimized) {
resetBackground();
- } else if (mDockSide == WindowManager.DOCKED_TOP) {
- mBackground.setPivotY(0);
- mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
- } else if (mDockSide == WindowManager.DOCKED_LEFT
- || mDockSide == WindowManager.DOCKED_RIGHT) {
- mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
- ? 0
- : mBackground.getWidth());
- mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
+ } else if (!isHomeStackResizable) {
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
+ } else if (mDockSide == WindowManager.DOCKED_LEFT
+ || mDockSide == WindowManager.DOCKED_RIGHT) {
+ mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
+ ? 0
+ : mBackground.getWidth());
+ mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
+ }
}
mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
- mDockedStackMinimized = minimized;
+ if (!isHomeStackResizable) {
+ mHandle.setAlpha(minimized ? 0f : 1f);
+ mDockedStackMinimized = minimized;
+ } else if (mDockedStackMinimized != minimized) {
+ if (mStableInsets.isEmpty()) {
+ SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+ }
+ if (!mIsInMinimizeInteraction && minimized) {
+ mIsInMinimizeInteraction = true;
+ mDividerPositionBeforeMinimized = DockedDividerUtils.calculateMiddlePosition(
+ isHorizontalDivision(), mStableInsets, mDisplayWidth, mDisplayHeight,
+ mDividerSize);
+ }
+ mMinimizedSnapAlgorithm = null;
+ mDockedStackMinimized = minimized;
+ initializeSnapAlgorithm();
+ }
}
- public void setMinimizedDockStack(boolean minimized, long animDuration) {
+ public void setMinimizedDockStack(boolean minimized, long animDuration,
+ boolean isHomeStackResizable) {
+ mHomeStackResizable = isHomeStackResizable;
updateDockSide();
- mHandle.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(animDuration)
- .alpha(minimized ? 0f : 1f)
- .start();
- if (mDockSide == WindowManager.DOCKED_TOP) {
- mBackground.setPivotY(0);
- mBackground.animate()
- .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
- } else if (mDockSide == WindowManager.DOCKED_LEFT
- || mDockSide == WindowManager.DOCKED_RIGHT) {
- mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
- ? 0
- : mBackground.getWidth());
- mBackground.animate()
- .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ if (!isHomeStackResizable) {
+ mMinimizedShadow.animate()
+ .alpha(minimized ? 1f : 0f)
+ .setInterpolator(Interpolators.ALPHA_IN)
+ .setDuration(animDuration)
+ .start();
+ mHandle.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .alpha(minimized ? 0f : 1f)
+ .start();
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.animate()
+ .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ } else if (mDockSide == WindowManager.DOCKED_LEFT
+ || mDockSide == WindowManager.DOCKED_RIGHT) {
+ mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
+ ? 0
+ : mBackground.getWidth());
+ mBackground.animate()
+ .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ }
+ mDockedStackMinimized = minimized;
+ } else if (mDockedStackMinimized != minimized) {
+ mIsInMinimizeInteraction = true;
+ if (minimized) {
+ mDividerPositionBeforeMinimized = getCurrentPosition();
+ }
+ mMinimizedSnapAlgorithm = null;
+ mDockedStackMinimized = minimized;
+ initializeSnapAlgorithm();
+ stopDragging(getCurrentPosition(), minimized ?
+ mMinimizedSnapAlgorithm.getMiddleTarget() :
+ mSnapAlgorithm.calculateNonDismissingSnapTarget(
+ mDividerPositionBeforeMinimized),
+ animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
}
if (!minimized) {
mBackground.animate().withEndAction(mResetBackgroundRunnable);
}
- mMinimizedShadow.animate()
- .alpha(minimized ? 1f : 0f)
- .setInterpolator(Interpolators.ALPHA_IN)
- .setDuration(animDuration)
- .start();
mBackground.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.start();
- mDockedStackMinimized = minimized;
}
public void setAdjustedForIme(boolean adjustedForIme) {
@@ -809,6 +873,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
mSnapAlgorithm = null;
+ mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}
@@ -871,6 +936,15 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
mLastResizeRect.set(mDockedRect);
+ if (mHomeStackResizable && mIsInMinimizeInteraction) {
+ calculateBoundsForPosition(mDividerPositionBeforeMinimized, mDockSide, mDockedTaskRect);
+ calculateBoundsForPosition(mDividerPositionBeforeMinimized,
+ DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
+ mOtherTaskRect, null);
+ return;
+ }
+
if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
if (mCurrentAnimator != null) {
calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
@@ -922,7 +996,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
} else {
mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
}
- SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position);
+ SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
getStackIdForDismissTarget(closestDismissTarget),
@@ -943,7 +1017,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mEntranceAnimationRunning) {
return 0f;
}
- float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
+ float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
fraction = Math.max(0, Math.min(fraction, 1f));
fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
if (hasInsetsAtDismissTarget(dismissTarget)) {
@@ -959,13 +1033,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
*/
private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) {
if (isHorizontalDivision()) {
- if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
+ if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) {
return mStableInsets.top != 0;
} else {
return mStableInsets.bottom != 0;
}
} else {
- if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
+ if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) {
return mStableInsets.left != 0;
} else {
return mStableInsets.right != 0;
@@ -1135,6 +1209,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mStableInsets.isEmpty()) {
SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
mSnapAlgorithm = null;
+ mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}
@@ -1166,7 +1241,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
int dockSide = mWindowManagerProxy.getDockSide();
- if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
+ if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable
+ || !mDockedStackMinimized)) {
startDragging(false /* animate */, false /* touching */);
SnapTarget target = dockSideTopLeft(dockSide)
? mSnapAlgorithm.getDismissEndTarget()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index b9ed72522bdb..0bd649121321 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -38,7 +38,6 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -106,7 +105,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private boolean mDimmed;
private boolean mDark;
- private int mBgTint = NO_COLOR;
+ protected int mBgTint = NO_COLOR;
private float mBgAlpha = 1f;
/**
@@ -140,8 +139,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private ValueAnimator mBackgroundColorAnimator;
private float mAppearAnimationFraction = -1.0f;
private float mAppearAnimationTranslation;
- private boolean mShowingLegacyBackground;
- private final int mLegacyColor;
private final int mNormalColor;
private final int mLowPriorityColor;
private boolean mIsBelowSpeedBump;
@@ -192,7 +189,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
setClipChildren(false);
setClipToPadding(false);
- mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
mNormalColor = context.getColor(R.color.notification_material_background_color);
mLowPriorityColor = context.getColor(
R.color.notification_material_background_low_priority_color);
@@ -489,11 +485,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
updateOutlineAlpha();
}
- public void setShowingLegacyBackground(boolean showing) {
- mShowingLegacyBackground = showing;
- updateBackgroundTint();
- }
-
@Override
public void setBelowSpeedBump(boolean below) {
super.setBelowSpeedBump(below);
@@ -950,8 +941,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
if (withTint && mBgTint != NO_COLOR) {
return mBgTint;
- } else if (mShowingLegacyBackground) {
- return mLegacyColor;
} else if (mIsBelowSpeedBump) {
return mLowPriorityColor;
} else {
@@ -962,8 +951,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
protected int getRippleColor() {
if (mBgTint != 0) {
return mTintedRippleColor;
- } else if (mShowingLegacyBackground) {
- return mTintedRippleColor;
} else if (mIsBelowSpeedBump) {
return mLowPriorityRippleColor;
} else {
@@ -1009,7 +996,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
public void reset() {
setTintColor(0);
resetBackgroundAlpha();
- setShowingLegacyBackground(false);
setBelowSpeedBump(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
deleted file mode 100644
index d9298ed6be27..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ /dev/null
@@ -1,2552 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
-import android.app.ActivityOptions;
-import android.app.INotificationManager;
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
-import android.app.TaskStackBuilder;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.StatusBarNotification;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.RemoteViews;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.SystemUI;
-import com.android.systemui.assist.AssistManager;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.RemoteInputView;
-import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.Stack;
-
-public abstract class BaseStatusBar extends SystemUI implements
- CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
- ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
- ExpandableNotificationRow.OnExpandClickListener {
- public static final String TAG = "StatusBar";
- public static final boolean DEBUG = false;
- public static final boolean MULTIUSER_DEBUG = false;
-
- public static final boolean ENABLE_REMOTE_INPUT =
- SystemProperties.getBoolean("debug.enable_remote_input", true);
- public static final boolean ENABLE_CHILD_NOTIFICATIONS
- = SystemProperties.getBoolean("debug.child_notifs", true);
- public static final boolean FORCE_REMOTE_INPUT_HISTORY =
- SystemProperties.getBoolean("debug.force_remoteinput_history", false);
- private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
-
- protected static final int MSG_SHOW_RECENT_APPS = 1019;
- protected static final int MSG_HIDE_RECENT_APPS = 1020;
- protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
- protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
- protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
- protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
- protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
- protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
- protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
-
- protected static final boolean ENABLE_HEADS_UP = true;
- protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
-
- private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-
- // Should match the values in PhoneWindowManager
- public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
- public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
-
- private static final String BANNER_ACTION_CANCEL =
- "com.android.systemui.statusbar.banner_action_cancel";
- private static final String BANNER_ACTION_SETUP =
- "com.android.systemui.statusbar.banner_action_setup";
- private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
- = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
-
- protected CommandQueue mCommandQueue;
- protected IStatusBarService mBarService;
- protected H mHandler = createHandler();
-
- // all notifications
- protected NotificationData mNotificationData;
- protected NotificationStackScrollLayout mStackScroller;
-
- protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
-
- protected RemoteInputController mRemoteInputController;
-
- // for heads up notifications
- protected HeadsUpManager mHeadsUpManager;
-
- // handling reordering
- protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
-
- protected int mCurrentUserId = 0;
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
-
- protected int mLayoutDirection = -1; // invalid
- protected AccessibilityManager mAccessibilityManager;
-
- protected boolean mDeviceInteractive;
-
- protected boolean mVisible;
- protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
- protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
-
- /**
- * Notifications with keys in this set are not actually around anymore. We kept them around
- * when they were canceled in response to a remote input interaction. This allows us to show
- * what you replied and allows you to continue typing into it.
- */
- protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
-
- // mScreenOnFromKeyguard && mVisible.
- private boolean mVisibleToUser;
-
- private Locale mLocale;
- private float mFontScale;
-
- protected boolean mUseHeadsUp = false;
- protected boolean mHeadsUpTicker = false;
- protected boolean mDisableNotificationAlerts = false;
-
- protected DevicePolicyManager mDevicePolicyManager;
- protected IDreamManager mDreamManager;
- protected PowerManager mPowerManager;
- protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-
- // public mode, private notifications, etc
- private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
-
- private UserManager mUserManager;
- private int mDensity;
-
- protected KeyguardManager mKeyguardManager;
- private LockPatternUtils mLockPatternUtils;
- private DeviceProvisionedController mDeviceProvisionedController;
-
- // UI-specific methods
-
- /**
- * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
- * and add them to the window manager.
- */
- protected abstract void createAndAddWindows();
-
- protected WindowManager mWindowManager;
- protected IWindowManager mWindowManagerService;
-
- protected Display mDisplay;
-
- protected RecentsComponent mRecents;
-
- protected int mZenMode;
-
- // which notification is currently being longpress-examined by the user
- private NotificationGuts mNotificationGutsExposed;
-
- private KeyboardShortcuts mKeyboardShortcuts;
-
- /**
- * The {@link StatusBarState} of the status bar.
- */
- protected int mState;
- protected boolean mBouncerShowing;
- protected boolean mShowLockscreenNotifications;
- protected boolean mAllowLockscreenRemoteInput;
-
- protected NotificationShelf mNotificationShelf;
- protected DismissView mDismissView;
- protected EmptyShadeView mEmptyShadeView;
-
- private NotificationClicker mNotificationClicker = new NotificationClicker();
-
- protected AssistManager mAssistManager;
-
- protected boolean mVrMode;
-
- private Set<String> mNonBlockablePkgs;
-
- @Override // NotificationData.Environment
- public boolean isDeviceProvisioned() {
- return mDeviceProvisionedController.isDeviceProvisioned();
- }
-
- private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
- @Override
- public void onVrStateChanged(boolean enabled) {
- mVrMode = enabled;
- }
- };
-
- public boolean isDeviceInVrMode() {
- return mVrMode;
- }
-
- private final DeviceProvisionedListener mDeviceProvisionedListener =
- new DeviceProvisionedListener() {
- @Override
- public void onDeviceProvisionedChanged() {
- updateNotifications();
- }
- };
-
- protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final int mode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- setZenMode(mode);
-
- updateLockscreenNotificationSetting();
- }
- };
-
- private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
- // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
- mUsersAllowingPrivateNotifications.clear();
- mUsersAllowingNotifications.clear();
- // ... and refresh all the notifications
- updateLockscreenNotificationSetting();
- updateNotifications();
- }
- };
-
- private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
- private final int[] mTmpInt2 = new int[2];
-
- @Override
- public boolean onClickHandler(
- final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
- view.getLocationInWindow(mTmpInt2);
- wakeUpIfDozing(SystemClock.uptimeMillis(), new PointF(
- mTmpInt2[0] + view.getWidth() / 2, mTmpInt2[1] + view.getHeight() / 2));
-
-
- if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
- return true;
- }
-
- if (DEBUG) {
- Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
- }
- logActionClick(view);
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- final boolean isActivity = pendingIntent.isActivity();
- if (isActivity) {
- final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
- final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, pendingIntent.getIntent(), mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
-
- // close the shade if it was open
- if (handled) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */);
- visibilityChanged(false);
- mAssistManager.hideAssist();
- }
-
- // Wait for activity start.
- return handled;
- }
- }, afterKeyguardGone);
- return true;
- } else {
- return superOnClickHandler(view, pendingIntent, fillInIntent);
- }
- }
-
- private void logActionClick(View view) {
- ViewParent parent = view.getParent();
- String key = getNotificationKeyForParent(parent);
- if (key == null) {
- Log.w(TAG, "Couldn't determine notification for click.");
- return;
- }
- int index = -1;
- // If this is a default template, determine the index of the button.
- if (view.getId() == com.android.internal.R.id.action0 &&
- parent != null && parent instanceof ViewGroup) {
- ViewGroup actionGroup = (ViewGroup) parent;
- index = actionGroup.indexOfChild(view);
- }
- try {
- mBarService.onNotificationActionClick(key, index);
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
- private String getNotificationKeyForParent(ViewParent parent) {
- while (parent != null) {
- if (parent instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
- }
- parent = parent.getParent();
- }
- return null;
- }
-
- private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
- Intent fillInIntent) {
- return super.onClickHandler(view, pendingIntent, fillInIntent,
- StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- }
-
- private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
- Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
- RemoteInput[] inputs = null;
- if (tag instanceof RemoteInput[]) {
- inputs = (RemoteInput[]) tag;
- }
-
- if (inputs == null) {
- return false;
- }
-
- RemoteInput input = null;
-
- for (RemoteInput i : inputs) {
- if (i.getAllowFreeFormInput()) {
- input = i;
- }
- }
-
- if (input == null) {
- return false;
- }
-
- ViewParent p = view.getParent();
- RemoteInputView riv = null;
- while (p != null) {
- if (p instanceof View) {
- View pv = (View) p;
- if (pv.isRootNamespace()) {
- riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
- break;
- }
- }
- p = p.getParent();
- }
- ExpandableNotificationRow row = null;
- while (p != null) {
- if (p instanceof ExpandableNotificationRow) {
- row = (ExpandableNotificationRow) p;
- break;
- }
- p = p.getParent();
- }
-
- if (riv == null || row == null) {
- return false;
- }
-
- row.setUserExpanded(true);
-
- if (!mAllowLockscreenRemoteInput) {
- final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
- if (isLockscreenPublicMode(userId)) {
- onLockedRemoteInput(row, view);
- return true;
- }
- if (mUserManager.getUserInfo(userId).isManagedProfile()
- && mKeyguardManager.isDeviceLocked(userId)) {
- onLockedWorkRemoteInput(userId, row, view);
- return true;
- }
- }
-
- int width = view.getWidth();
- if (view instanceof TextView) {
- // Center the reveal on the text which might be off-center from the TextView
- TextView tv = (TextView) view;
- if (tv.getLayout() != null) {
- int innerWidth = (int) tv.getLayout().getLineWidth(0);
- innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
- width = Math.min(width, innerWidth);
- }
- }
- int cx = view.getLeft() + width / 2;
- int cy = view.getTop() + view.getHeight() / 2;
- int w = riv.getWidth();
- int h = riv.getHeight();
- int r = Math.max(
- Math.max(cx + cy, cx + (h - cy)),
- Math.max((w - cx) + cy, (w - cx) + (h - cy)));
-
- riv.setRevealParameters(cx, cy, r);
- riv.setPendingIntent(pendingIntent);
- riv.setRemoteInput(inputs, input);
- riv.focusAnimated();
-
- return true;
- }
-
- };
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
- updateLockscreenNotificationSetting();
-
- userSwitched(mCurrentUserId);
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- List<ActivityManager.RecentTaskInfo> recentTask = null;
- try {
- recentTask = ActivityManager.getService().getRecentTasks(1,
- ActivityManager.RECENT_WITH_EXCLUDED
- | ActivityManager.RECENT_INCLUDE_PROFILES,
- mCurrentUserId).getList();
- } catch (RemoteException e) {
- // Abandon hope activity manager not running.
- }
- if (recentTask != null && recentTask.size() > 0) {
- UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
- if (user != null && user.isManagedProfile()) {
- Toast toast = Toast.makeText(mContext,
- R.string.managed_profile_foreground_toast,
- Toast.LENGTH_SHORT);
- TextView text = (TextView) toast.getView().findViewById(
- android.R.id.message);
- text.setCompoundDrawablesRelativeWithIntrinsicBounds(
- R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
- int paddingPx = mContext.getResources().getDimensionPixelSize(
- R.dimen.managed_profile_toast_padding);
- text.setCompoundDrawablePadding(paddingPx);
- toast.show();
- }
- }
- } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
- NotificationManager noMan = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
-
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
- if (BANNER_ACTION_SETUP.equals(action)) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */);
- mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-
- );
- }
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
- if (notificationKey != null) {
- try {
- mBarService.onNotificationClick(notificationKey);
- } catch (RemoteException e) {
- /* ignore */
- }
- }
- }
- }
- };
-
- private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-
- if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
- isCurrentProfile(getSendingUserId())) {
- mUsersAllowingPrivateNotifications.clear();
- updateLockscreenNotificationSetting();
- updateNotifications();
- } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
- if (userId != mCurrentUserId && isCurrentProfile(userId)) {
- onWorkChallengeChanged();
- }
- }
- }
- };
-
- private final NotificationListenerService mNotificationListener =
- new NotificationListenerService() {
- @Override
- public void onListenerConnected() {
- if (DEBUG) Log.d(TAG, "onListenerConnected");
- final StatusBarNotification[] notifications = getActiveNotifications();
- if (notifications == null) {
- Log.w(TAG, "onListenerConnected unable to get active notifications.");
- return;
- }
- final RankingMap currentRanking = getCurrentRanking();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (StatusBarNotification sbn : notifications) {
- addNotification(sbn, currentRanking, null /* oldEntry */);
- }
- }
- });
- }
-
- @Override
- public void onNotificationPosted(final StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
- if (sbn != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- processForRemoteInput(sbn.getNotification());
- String key = sbn.getKey();
- mKeysKeptForRemoteInput.remove(key);
- boolean isUpdate = mNotificationData.get(key) != null;
- // In case we don't allow child notifications, we ignore children of
- // notifications that have a summary, since we're not going to show them
- // anyway. This is true also when the summary is canceled,
- // because children are automatically canceled by NoMan in that case.
- if (!ENABLE_CHILD_NOTIFICATIONS
- && mGroupManager.isChildInGroupWithSummary(sbn)) {
- if (DEBUG) {
- Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
- }
-
- // Remove existing notification to avoid stale data.
- if (isUpdate) {
- removeNotification(key, rankingMap);
- } else {
- mNotificationData.updateRanking(rankingMap);
- }
- return;
- }
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap, null /* oldEntry */);
- }
- }
- });
- }
- }
-
- @Override
- public void onNotificationRemoved(StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
- if (sbn != null) {
- final String key = sbn.getKey();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- removeNotification(key, rankingMap);
- }
- });
- }
- }
-
- @Override
- public void onNotificationRankingUpdate(final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onRankingUpdate");
- if (rankingMap != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- updateNotificationRanking(rankingMap);
- }
- });
- } }
-
- };
-
- private void updateCurrentProfilesCache() {
- synchronized (mCurrentProfiles) {
- mCurrentProfiles.clear();
- if (mUserManager != null) {
- for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
- mCurrentProfiles.put(user.id, user);
- }
- }
- }
- }
-
- public void start() {
- mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
- mDisplay = mWindowManager.getDefaultDisplay();
- mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
-
- mNotificationData = new NotificationData(this);
-
- mAccessibilityManager = (AccessibilityManager)
- mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE));
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-
- mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
- mSettingsObserver);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
- false,
- mSettingsObserver,
- UserHandle.USER_ALL);
- }
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
-
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-
- mRecents = getComponent(Recents.class);
-
- final Configuration currentConfig = mContext.getResources().getConfiguration();
- mLocale = currentConfig.locale;
- mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
- mFontScale = currentConfig.fontScale;
- mDensity = currentConfig.densityDpi;
-
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mLockPatternUtils = new LockPatternUtils(mContext);
-
- // Connect in to the status bar manager service
- mCommandQueue = getComponent(CommandQueue.class);
- mCommandQueue.addCallbacks(this);
-
- int[] switches = new int[9];
- ArrayList<IBinder> binders = new ArrayList<IBinder>();
- ArrayList<String> iconSlots = new ArrayList<>();
- ArrayList<StatusBarIcon> icons = new ArrayList<>();
- Rect fullscreenStackBounds = new Rect();
- Rect dockedStackBounds = new Rect();
- try {
- mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
- fullscreenStackBounds, dockedStackBounds);
- } catch (RemoteException ex) {
- // If the system process isn't there we're doomed anyway.
- }
-
- createAndAddWindows();
-
- mSettingsObserver.onChange(false); // set up
- disable(switches[0], switches[6], false /* animate */);
- setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
- fullscreenStackBounds, dockedStackBounds);
- topAppWindowChanged(switches[2] != 0);
- // StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
-
- // Set up the initial icon state
- int N = iconSlots.size();
- int viewIndex = 0;
- for (int i=0; i < N; i++) {
- setIcon(iconSlots.get(i), icons.get(i));
- }
-
- // Set up the initial notification state.
- try {
- mNotificationListener.registerAsSystemService(mContext,
- new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
- UserHandle.USER_ALL);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to register notification listener", e);
- }
-
-
- if (DEBUG) {
- Log.d(TAG, String.format(
- "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
- icons.size(),
- switches[0],
- switches[1],
- switches[2],
- switches[3]
- ));
- }
-
- mCurrentUserId = ActivityManager.getCurrentUser();
- setHeadsUpUser(mCurrentUserId);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
- IntentFilter internalFilter = new IntentFilter();
- internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
- internalFilter.addAction(BANNER_ACTION_CANCEL);
- internalFilter.addAction(BANNER_ACTION_SETUP);
- mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
-
- IntentFilter allUsersFilter = new IntentFilter();
- allUsersFilter.addAction(
- DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
- mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
- null, null);
- updateCurrentProfilesCache();
-
- IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
- try {
- vrManager.registerListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register VR mode state listener: " + e);
- }
-
- mNonBlockablePkgs = new HashSet<String>();
- Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
- com.android.internal.R.array.config_nonBlockableNotificationPackages));
- }
-
- protected void notifyUserAboutHiddenNotifications() {
- if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
- Log.d(TAG, "user hasn't seen notification about hidden notifications");
- if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- Log.d(TAG, "insecure lockscreen, skipping notification");
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
- return;
- }
- Log.d(TAG, "disabling lockecreen notifications and alerting the user");
- // disable lockscreen notifications until user acts on the banner.
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
-
- final String packageName = mContext.getPackageName();
- PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
- PendingIntent.FLAG_CANCEL_CURRENT);
- PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
- PendingIntent.FLAG_CANCEL_CURRENT);
-
- final int colorRes = com.android.internal.R.color.system_notification_accent_color;
- Notification.Builder note = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_android)
- .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
- .setContentText(mContext.getString(R.string.hidden_notifications_text))
- .setPriority(Notification.PRIORITY_HIGH)
- .setOngoing(true)
- .setColor(mContext.getColor(colorRes))
- .setContentIntent(setupIntent)
- .addAction(R.drawable.ic_close,
- mContext.getString(R.string.hidden_notifications_cancel),
- cancelIntent)
- .addAction(R.drawable.ic_settings,
- mContext.getString(R.string.hidden_notifications_setup),
- setupIntent);
- overrideNotificationAppName(mContext, note);
-
- NotificationManager noMan =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
- }
- }
-
- public void userSwitched(int newUserId) {
- setHeadsUpUser(newUserId);
- }
-
- protected abstract void setHeadsUpUser(int newUserId);
-
- @Override // NotificationData.Environment
- public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
- final int thisUserId = mCurrentUserId;
- final int notificationUserId = n.getUserId();
- if (DEBUG && MULTIUSER_DEBUG) {
- Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
- n, thisUserId, notificationUserId));
- }
- return isCurrentProfile(notificationUserId);
- }
-
- protected void setNotificationShown(StatusBarNotification n) {
- setNotificationsShown(new String[]{n.getKey()});
- }
-
- protected void setNotificationsShown(String[] keys) {
- try {
- mNotificationListener.setNotificationsShown(keys);
- } catch (RuntimeException e) {
- Log.d(TAG, "failed setNotificationsShown: ", e);
- }
- }
-
- protected boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
- }
- }
-
- @Override
- public String getCurrentMediaNotificationKey() {
- return null;
- }
-
- @Override
- public NotificationGroupManager getGroupManager() {
- return mGroupManager;
- }
-
- /**
- * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
- * @param action A dismiss action that is called if it's safe to start the activity.
- * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
- */
- protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
- action.onDismiss();
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- final float fontScale = newConfig.fontScale;
- final int density = newConfig.densityDpi;
- if (density != mDensity || mFontScale != fontScale) {
- onDensityOrFontScaleChanged();
- mDensity = density;
- mFontScale = fontScale;
- }
- }
-
- protected void onDensityOrFontScaleChanged() {
- ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
- for (int i = 0; i < activeNotifications.size(); i++) {
- Entry entry = activeNotifications.get(i);
- boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
- entry.row.reInflateViews();
- if (exposedGuts) {
- mNotificationGutsExposed = entry.row.getGuts();
- bindGuts(entry.row);
- }
- inflateViews(entry, mStackScroller);
- }
- }
-
- protected void bindDismissRunnable(final ExpandableNotificationRow row) {
- row.setOnDismissRunnable(() -> performRemoveNotification(row.getStatusBarNotification()));
- }
-
- protected void performRemoveNotification(StatusBarNotification n) {
- final String pkg = n.getPackageName();
- final String tag = n.getTag();
- final int id = n.getId();
- final int userId = n.getUserId();
- try {
- mBarService.onNotificationClear(pkg, tag, id, userId);
- if (FORCE_REMOTE_INPUT_HISTORY
- && mKeysKeptForRemoteInput.contains(n.getKey())) {
- mKeysKeptForRemoteInput.remove(n.getKey());
- }
- removeNotification(n.getKey(), null);
-
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- }
-
-
- protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
- NotificationData.Entry entry) {
-
- if (entry.getContentView().getId()
- != com.android.internal.R.id.status_bar_latest_event_content) {
- // Using custom RemoteViews
- if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
- && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
- entry.row.setShowingLegacyBackground(true);
- entry.legacy = true;
- }
- }
-
- entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
- }
-
- public boolean isMediaNotification(NotificationData.Entry entry) {
- // TODO: confirm that there's a valid media key
- return entry.getExpandedContentView() != null &&
- entry.getExpandedContentView()
- .findViewById(com.android.internal.R.id.media_actions) != null;
- }
-
- // The (i) button in the guts that links to the system notification settings for that app
- private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
- final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
- intent.putExtra(Settings.EXTRA_APP_UID, appUid);
- startNotificationGutsIntent(intent, appUid);
- }
-
- private void startNotificationGutsIntent(final Intent intent, final int appUid) {
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- AsyncTask.execute(new Runnable() {
- public void run() {
- TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(),
- new UserHandle(UserHandle.getUserId(appUid)));
- }
- });
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- return true;
- }
- }, false /* afterKeyguardGone */);
- }
-
- private void bindGuts(final ExpandableNotificationRow row) {
- row.inflateGuts();
- final StatusBarNotification sbn = row.getStatusBarNotification();
- final NotificationChannel channel = row.getEntry().channel;
- PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
- row.setTag(sbn.getPackageName());
- final NotificationGuts guts = row.getGuts();
- guts.setClosedListener((NotificationGuts g) -> {
- if (!row.isRemoved()) {
- mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
- }
- mNotificationGutsExposed = null;
- });
-
- final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-
- final String pkg = sbn.getPackageName();
- final NotificationGuts.OnSettingsClickListener onSettingsClick =
- (View v, int appUid) -> {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
- guts.resetFalsingCheck();
- startAppNotificationSettingsActivity(pkg, appUid);
- };
- final View.OnClickListener onDoneClick =
- (View v) -> {
- // If the user has security enabled, show challenge if the setting is changed.
- if (guts.hasImportanceChanged()
- && isLockscreenPublicMode(sbn.getUser().getIdentifier())
- && (mState == StatusBarState.KEYGUARD
- || mState == StatusBarState.SHADE_LOCKED)) {
- OnDismissAction dismissAction = new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- closeControls(row, guts, v);
- return true;
- }
- };
- onLockedNotificationImportanceChange(dismissAction);
- } else {
- closeControls(row, guts, v);
- }
- };
- guts.bindNotification(pmUser, iNotificationManager, sbn, channel,
- onSettingsClick, onDoneClick, mNonBlockablePkgs);
- }
-
- private void closeControls(
- ExpandableNotificationRow row, NotificationGuts guts, View done) {
- guts.resetFalsingCheck();
-
- int[] rowLocation = new int[2];
- int[] doneLocation = new int[2];
- row.getLocationOnScreen(rowLocation);
- done.getLocationOnScreen(doneLocation);
-
- final int centerX = done.getWidth() / 2;
- final int centerY = done.getHeight() / 2;
- final int x = doneLocation[0] - rowLocation[0] + centerX;
- final int y = doneLocation[1] - rowLocation[1] + centerY;
- dismissPopups(x, y);
- }
-
- protected SwipeHelper.LongPressListener getNotificationLongClicker() {
- return new SwipeHelper.LongPressListener() {
- @Override
- public boolean onLongPress(View v, final int x, final int y) {
- if (!(v instanceof ExpandableNotificationRow)) {
- return false;
- }
- if (v.getWindowToken() == null) {
- Log.e(TAG, "Trying to show notification guts, but not attached to window");
- return false;
- }
-
- final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- bindGuts(row);
-
- // Assume we are a status_bar_notification_row
- final NotificationGuts guts = row.getGuts();
- if (guts == null) {
- // This view has no guts. Examples are the more card or the dismiss all view
- return false;
- }
-
- // Already showing?
- if (guts.getVisibility() == View.VISIBLE) {
- dismissPopups(x, y);
- return false;
- }
-
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
-
- // ensure that it's laid but not visible until actually laid out
- guts.setVisibility(View.INVISIBLE);
- // Post to ensure the the guts are properly laid out.
- guts.post(new Runnable() {
- public void run() {
- if (row.getWindowToken() == null) {
- Log.e(TAG, "Trying to show notification guts, but not attached to "
- + "window");
- return;
- }
- dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
- false /* animate */);
- guts.setVisibility(View.VISIBLE);
- final double horz = Math.max(guts.getWidth() - x, x);
- final double vert = Math.max(guts.getHeight() - y, y);
- final float r = (float) Math.hypot(horz, vert);
- final Animator a
- = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
- a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- a.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- // Move the notification view back over the gear
- row.resetTranslation();
- }
- });
- a.start();
- guts.setExposed(true /* exposed */,
- mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
- row.closeRemoteInput();
- mStackScroller.onHeightChanged(row, true /* needsAnimation */);
- mNotificationGutsExposed = guts;
- }
- });
- return true;
- }
- };
- }
-
- /**
- * Returns the exposed NotificationGuts or null if none are exposed.
- */
- public NotificationGuts getExposedGuts() {
- return mNotificationGutsExposed;
- }
-
- public void dismissPopups() {
- dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
- }
-
- private void dismissPopups(int x, int y) {
- dismissPopups(x, y, true /* resetGear */, false /* animate */);
- }
-
- public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
- if (mNotificationGutsExposed != null) {
- mNotificationGutsExposed.closeControls(x, y, true /* save */);
- }
- if (resetGear) {
- mStackScroller.resetExposedGearView(animate, true /* force */);
- }
- }
-
- @Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
- int msg = MSG_SHOW_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, fromHome ? 1 : 0).sendToTarget();
- }
-
- @Override
- public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- int msg = MSG_HIDE_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
- triggeredFromHomeKey ? 1 : 0).sendToTarget();
- }
-
- @Override
- public void toggleRecentApps() {
- toggleRecents();
- }
-
- @Override
- public void toggleSplitScreen() {
- toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
- }
-
- @Override
- public void preloadRecentApps() {
- int msg = MSG_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void cancelPreloadRecentApps() {
- int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void dismissKeyboardShortcutsMenu() {
- int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void toggleKeyboardShortcutsMenu(int deviceId) {
- int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
- }
-
- /** Jumps to the next affiliated task in the group. */
- public void showNextAffiliatedTask() {
- int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- /** Jumps to the previous affiliated task in the group. */
- public void showPreviousAffiliatedTask() {
- int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- protected H createHandler() {
- return new H();
- }
-
- protected void sendCloseSystemWindows(String reason) {
- try {
- ActivityManager.getService().closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- }
-
- protected abstract View getStatusBarView();
-
- /**
- * Toggle docking the app window
- *
- * @param metricsDockAction the action to log when docking is successful, or -1 to not log
- * anything on successful docking
- * @param metricsUndockAction the action to log when undocking, or -1 to not log anything when
- * undocking
- * @return true if toggle split screen was successful
- */
- protected abstract boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction);
-
- /** Proxy for RecentsComponent */
-
- protected void showRecents(boolean triggeredFromAltTab, boolean fromHome) {
- if (mRecents != null) {
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
- mRecents.showRecents(triggeredFromAltTab, fromHome);
- }
- }
-
- protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mRecents != null) {
- mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
- }
- }
-
- protected void toggleRecents() {
- if (mRecents != null) {
- mRecents.toggleRecents(mDisplay);
- }
- }
-
- protected void preloadRecents() {
- if (mRecents != null) {
- mRecents.preloadRecents();
- }
- }
-
- protected void toggleKeyboardShortcuts(int deviceId) {
- KeyboardShortcuts.toggle(mContext, deviceId);
- }
-
- protected void dismissKeyboardShortcuts() {
- KeyboardShortcuts.dismiss();
- }
-
- protected void cancelPreloadingRecents() {
- if (mRecents != null) {
- mRecents.cancelPreloadingRecents();
- }
- }
-
- protected void showRecentsNextAffiliatedTask() {
- if (mRecents != null) {
- mRecents.showNextAffiliatedTask();
- }
- }
-
- protected void showRecentsPreviousAffiliatedTask() {
- if (mRecents != null) {
- mRecents.showPrevAffiliatedTask();
- }
- }
-
- /**
- * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
- */
- public abstract void maybeEscalateHeadsUp();
-
- /**
- * Save the current "public" (locked and secure) state of the lockscreen.
- */
- public void setLockscreenPublicMode(boolean publicMode, int userId) {
- mLockscreenPublicMode.put(userId, publicMode);
- }
-
- public boolean isLockscreenPublicMode(int userId) {
- return mLockscreenPublicMode.get(userId, false);
- }
-
- protected void onWorkChallengeChanged() {}
-
- /**
- * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
- * "public" (secure & locked) mode?
- */
- public boolean userAllowsNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
-
- if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowed = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
- mUsersAllowingNotifications.append(userHandle, allowed);
- return allowed;
- }
-
- return mUsersAllowingNotifications.get(userHandle);
- }
-
- /**
- * Has the given user chosen to allow their private (full) notifications to be shown even
- * when the lockscreen is in "public" (secure & locked) mode?
- */
- public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
-
- if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
- final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
- final boolean allowed = allowedByUser && allowedByDpm;
- mUsersAllowingPrivateNotifications.append(userHandle, allowed);
- return allowed;
- }
-
- return mUsersAllowingPrivateNotifications.get(userHandle);
- }
-
- private boolean adminAllowsUnredactedNotifications(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
- userHandle);
- return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
- }
-
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
- * If so, notifications should be hidden.
- */
- @Override // NotificationData.Environment
- public boolean shouldHideNotifications(int userId) {
- return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
- || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
- }
-
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
- * package-specific override.
- */
- @Override // NotificationDate.Environment
- public boolean shouldHideNotifications(String key) {
- return isLockscreenPublicMode(mCurrentUserId)
- && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
- }
-
- /**
- * Returns true if we're on a secure lockscreen.
- */
- @Override // NotificationData.Environment
- public boolean isSecurelyLocked(int userId) {
- return isLockscreenPublicMode(userId);
- }
-
- public void onNotificationClear(StatusBarNotification notification) {
- try {
- mBarService.onNotificationClear(
- notification.getPackageName(),
- notification.getTag(),
- notification.getId(),
- notification.getUserId());
- } catch (android.os.RemoteException ex) {
- // oh well
- }
- }
-
- /**
- * Called when the notification panel layouts
- */
- public void onPanelLaidOut() {
- if (mState == StatusBarState.KEYGUARD) {
- // Since the number of notifications is determined based on the height of the view, we
- // need to update them.
- int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
- int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
- if (maxBefore != maxNotifications) {
- updateRowStates();
- }
- }
- }
-
- protected void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {}
-
- protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
-
- protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
- View clicked) {}
-
- @Override
- public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
- }
-
- protected class H extends Handler {
- public void handleMessage(Message m) {
- switch (m.what) {
- case MSG_SHOW_RECENT_APPS:
- showRecents(m.arg1 > 0, m.arg2 != 0);
- break;
- case MSG_HIDE_RECENT_APPS:
- hideRecents(m.arg1 > 0, m.arg2 > 0);
- break;
- case MSG_TOGGLE_RECENTS_APPS:
- toggleRecents();
- break;
- case MSG_PRELOAD_RECENT_APPS:
- preloadRecents();
- break;
- case MSG_CANCEL_PRELOAD_RECENT_APPS:
- cancelPreloadingRecents();
- break;
- case MSG_SHOW_NEXT_AFFILIATED_TASK:
- showRecentsNextAffiliatedTask();
- break;
- case MSG_SHOW_PREV_AFFILIATED_TASK:
- showRecentsPreviousAffiliatedTask();
- break;
- case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
- toggleKeyboardShortcuts(m.arg1);
- break;
- case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
- dismissKeyboardShortcuts();
- break;
- }
- }
- }
-
- protected void workAroundBadLayerDrawableOpacity(View v) {
- }
-
- protected boolean inflateViews(Entry entry, ViewGroup parent) {
- PackageManager pmUser = getPackageManagerForUser(mContext,
- entry.notification.getUser().getIdentifier());
-
- final StatusBarNotification sbn = entry.notification;
- try {
- entry.cacheContentViews(mContext, null);
- } catch (RuntimeException e) {
- Log.e(TAG, "Unable to get notification remote views", e);
- return false;
- }
-
- final RemoteViews contentView = entry.cachedContentView;
- final RemoteViews bigContentView = entry.cachedBigContentView;
- final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
- final RemoteViews publicContentView = entry.cachedPublicContentView;
- final RemoteViews ambientContentView = entry.cachedAmbientContentView;
-
- if (contentView == null) {
- Log.v(TAG, "no contentView for: " + sbn.getNotification());
- return false;
- }
-
- if (DEBUG) {
- Log.v(TAG, "publicContentView: " + publicContentView);
- }
-
- ExpandableNotificationRow row;
-
- // Stash away previous user expansion state so we can restore it at
- // the end.
- boolean hasUserChangedExpansion = false;
- boolean userExpanded = false;
- boolean userLocked = false;
-
- if (entry.row != null) {
- row = entry.row;
- hasUserChangedExpansion = row.hasUserChangedExpansion();
- userExpanded = row.isUserExpanded();
- userLocked = row.isUserLocked();
- entry.reset();
- if (hasUserChangedExpansion) {
- row.setUserExpanded(userExpanded);
- }
- } else {
- // create the row view
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
- parent, false);
- row.setExpansionLogger(this, entry.notification.getKey());
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setRemoteInputController(mRemoteInputController);
- row.setOnExpandClickListener(this);
-
- // Get the app name.
- // Note that Notification.Builder#bindHeaderAppName has similar logic
- // but since this field is used in the guts, it must be accurate.
- // Therefore we will only show the application label, or, failing that, the
- // package name. No substitutions.
- final String pkg = sbn.getPackageName();
- String appname = pkg;
- try {
- final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS);
- if (info != null) {
- appname = String.valueOf(pmUser.getApplicationLabel(info));
- }
- } catch (NameNotFoundException e) {
- // Do nothing
- }
- row.setAppName(appname);
- }
-
- workAroundBadLayerDrawableOpacity(row);
- bindDismissRunnable(row);
-
- // NB: the large icon is now handled entirely by the template
-
- // bind the click event to the content area
- NotificationContentView contentContainer = row.getPrivateLayout();
- NotificationContentView contentContainerPublic = row.getPublicLayout();
-
- row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- if (ENABLE_REMOTE_INPUT) {
- row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
- }
-
- mNotificationClicker.register(row, sbn);
-
- // set up the adaptive layout
- View contentViewLocal = null;
- View bigContentViewLocal = null;
- View headsUpContentViewLocal = null;
- View publicViewLocal = null;
- View ambientViewLocal = null;
- try {
- contentViewLocal = contentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- if (bigContentView != null) {
- bigContentViewLocal = bigContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- }
- if (headsUpContentView != null) {
- headsUpContentViewLocal = headsUpContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- }
- if (publicContentView != null) {
- publicViewLocal = publicContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainerPublic, mOnClickHandler);
- }
- if (ambientContentView != null) {
- ambientViewLocal = ambientContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer, mOnClickHandler);
- }
-
- if (contentViewLocal != null) {
- contentViewLocal.setIsRootNamespace(true);
- contentContainer.setContractedChild(contentViewLocal);
- }
- if (bigContentViewLocal != null) {
- bigContentViewLocal.setIsRootNamespace(true);
- contentContainer.setExpandedChild(bigContentViewLocal);
- }
- if (headsUpContentViewLocal != null) {
- headsUpContentViewLocal.setIsRootNamespace(true);
- contentContainer.setHeadsUpChild(headsUpContentViewLocal);
- }
- if (publicViewLocal != null) {
- publicViewLocal.setIsRootNamespace(true);
- contentContainerPublic.setContractedChild(publicViewLocal);
- }
-
- if (ambientViewLocal != null) {
- ambientViewLocal.setIsRootNamespace(true);
- contentContainer.setAmbientChild(ambientViewLocal);
- }
- }
- catch (RuntimeException e) {
- final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
- Log.e(TAG, "couldn't inflate view for notification " + ident, e);
- return false;
- }
-
- // Extract target SDK version.
- try {
- ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
- entry.targetSdk = info.targetSdkVersion;
- } catch (NameNotFoundException ex) {
- Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
- }
- entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
-
- entry.row = row;
- entry.row.setOnActivatedListener(this);
- entry.row.setExpandable(bigContentViewLocal != null);
-
- applyColorsAndBackgrounds(sbn, entry);
-
- // Restore previous flags.
- if (hasUserChangedExpansion) {
- // Note: setUserExpanded() conveniently ignores calls with
- // userExpanded=true if !isExpandable().
- row.setUserExpanded(userExpanded);
- }
- row.setUserLocked(userLocked);
- row.onNotificationUpdated(entry);
- return true;
- }
-
- /**
- * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
- * via first-class API.
- *
- * TODO: Remove once enough apps specify remote inputs on their own.
- */
- private void processForRemoteInput(Notification n) {
- if (!ENABLE_REMOTE_INPUT) return;
-
- if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
- (n.actions == null || n.actions.length == 0)) {
- Notification.Action viableAction = null;
- Notification.WearableExtender we = new Notification.WearableExtender(n);
-
- List<Notification.Action> actions = we.getActions();
- final int numActions = actions.size();
-
- for (int i = 0; i < numActions; i++) {
- Notification.Action action = actions.get(i);
- if (action == null) {
- continue;
- }
- RemoteInput[] remoteInputs = action.getRemoteInputs();
- if (remoteInputs == null) {
- continue;
- }
- for (RemoteInput ri : remoteInputs) {
- if (ri.getAllowFreeFormInput()) {
- viableAction = action;
- break;
- }
- }
- if (viableAction != null) {
- break;
- }
- }
-
- if (viableAction != null) {
- Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
- rebuilder.setActions(viableAction);
- rebuilder.build(); // will rewrite n
- }
- }
- }
-
- public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
- if (!isDeviceProvisioned()) return;
-
- final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
- final boolean afterKeyguardGone = intent.isActivity()
- && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
- mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- public boolean onDismiss() {
- new Thread() {
- @Override
- public void run() {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- try {
- intent.send(null, 0, null, null, null, null, getActivityOptions());
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here.
- // Just log the exception message.
- Log.w(TAG, "Sending intent failed: " + e);
-
- // TODO: Dismiss Keyguard.
- }
- if (intent.isActivity()) {
- mAssistManager.hideAssist();
- }
- }
- }.start();
-
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */, true /* delayed */);
- visibilityChanged(false);
-
- return true;
- }
- }, afterKeyguardGone);
- }
-
- public void addPostCollapseAction(Runnable r) {
- }
-
- public boolean isCollapsing() {
- return false;
- }
-
- public void wakeUpIfDozing(long time, PointF where) {
- }
-
- private final class NotificationClicker implements View.OnClickListener {
- private final int[] mTmpInt2 = new int[2];
-
- public void onClick(final View v) {
- if (!(v instanceof ExpandableNotificationRow)) {
- Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
- return;
- }
-
- v.getLocationInWindow(mTmpInt2);
- wakeUpIfDozing(SystemClock.uptimeMillis(),
- new PointF(mTmpInt2[0] + v.getWidth() / 2, mTmpInt2[1] + v.getHeight() / 2));
-
- final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- final StatusBarNotification sbn = row.getStatusBarNotification();
- if (sbn == null) {
- Log.e(TAG, "NotificationClicker called on an unclickable notification,");
- return;
- }
-
- // Check if the notification is displaying the gear, if so slide notification back
- if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
- row.animateTranslateNotification(0);
- return;
- }
-
- Notification notification = sbn.getNotification();
- final PendingIntent intent = notification.contentIntent != null
- ? notification.contentIntent
- : notification.fullScreenIntent;
- final String notificationKey = sbn.getKey();
-
- // Mark notification for one frame.
- row.setJustClicked(true);
- DejankUtils.postAfterTraversal(new Runnable() {
- @Override
- public void run() {
- row.setJustClicked(false);
- }
- });
-
- final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
- final boolean afterKeyguardGone = intent.isActivity()
- && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
- mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- public boolean onDismiss() {
- if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
- // Release the HUN notification to the shade.
-
- if (isPanelFullyCollapsed()) {
- HeadsUpManager.setIsClickedNotification(row, true);
- }
- //
- // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
- // become canceled shortly by NoMan, but we can't assume that.
- mHeadsUpManager.releaseImmediately(notificationKey);
- }
- StatusBarNotification parentToCancel = null;
- if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
- StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
- .getStatusBarNotification();
- if (shouldAutoCancel(summarySbn)) {
- parentToCancel = summarySbn;
- }
- }
- final StatusBarNotification parentToCancelFinal = parentToCancel;
- new Thread() {
- @Override
- public void run() {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- if (intent != null) {
- // If we are launching a work activity and require to launch
- // separate work challenge, we defer the activity action and cancel
- // notification until work challenge is unlocked.
- if (intent.isActivity()) {
- final int userId = intent.getCreatorUserHandle()
- .getIdentifier();
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
- && mKeyguardManager.isDeviceLocked(userId)) {
- boolean canBypass = false;
- try {
- canBypass = ActivityManager.getService()
- .canBypassWorkChallenge(intent);
- } catch (RemoteException e) {
- }
- // For direct-boot aware activities, they can be shown when
- // the device is still locked without triggering the work
- // challenge.
- if ((!canBypass) && startWorkChallengeIfNecessary(userId,
- intent.getIntentSender(), notificationKey)) {
- // Show work challenge, do not run PendingIntent and
- // remove notification
- return;
- }
- }
- }
- try {
- intent.send(null, 0, null, null, null, null,
- getActivityOptions());
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here.
- // Just log the exception message.
- Log.w(TAG, "Sending contentIntent failed: " + e);
-
- // TODO: Dismiss Keyguard.
- }
- if (intent.isActivity()) {
- mAssistManager.hideAssist();
- }
- }
-
- try {
- mBarService.onNotificationClick(notificationKey);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- if (parentToCancelFinal != null) {
- // We have to post it to the UI thread for synchronization
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Runnable removeRunnable = new Runnable() {
- @Override
- public void run() {
- performRemoveNotification(parentToCancelFinal);
- }
- };
- if (isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade was collapsed
- addPostCollapseAction(removeRunnable);
- } else {
- removeRunnable.run();
- }
- }
- });
- }
- }
- }.start();
-
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */, true /* delayed */);
- visibilityChanged(false);
-
- return true;
- }
- }, afterKeyguardGone);
- }
-
- private boolean shouldAutoCancel(StatusBarNotification sbn) {
- int flags = sbn.getNotification().flags;
- if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
- return false;
- }
- if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- return false;
- }
- return true;
- }
-
- public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
- Notification notification = sbn.getNotification();
- if (notification.contentIntent != null || notification.fullScreenIntent != null) {
- row.setOnClickListener(this);
- } else {
- row.setOnClickListener(null);
- }
- }
- }
-
- public void animateCollapsePanels(int flags, boolean force) {
- }
-
- public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
- }
-
- protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
- String notificationKey) {
- final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
- null, userId);
- if (newIntent == null) {
- return false;
- }
- final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
- callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
- callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
- callBackIntent.setPackage(mContext.getPackageName());
-
- PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
- mContext,
- 0,
- callBackIntent,
- PendingIntent.FLAG_CANCEL_CURRENT |
- PendingIntent.FLAG_ONE_SHOT |
- PendingIntent.FLAG_IMMUTABLE);
- newIntent.putExtra(
- Intent.EXTRA_INTENT,
- callBackPendingIntent.getIntentSender());
- try {
- ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent);
- } catch (RemoteException ex) {
- // ignore
- }
- return true;
- }
-
- protected Bundle getActivityOptions() {
- // Anything launched from the notification shade should always go into the
- // fullscreen stack.
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- return options.toBundle();
- }
-
- protected void visibilityChanged(boolean visible) {
- if (mVisible != visible) {
- mVisible = visible;
- if (!visible) {
- dismissPopups();
- }
- }
- updateVisibleToUser();
- }
-
- protected void updateVisibleToUser() {
- boolean oldVisibleToUser = mVisibleToUser;
- mVisibleToUser = mVisible && mDeviceInteractive;
-
- if (oldVisibleToUser != mVisibleToUser) {
- handleVisibleToUserChanged(mVisibleToUser);
- }
- }
-
- /**
- * The LEDs are turned off when the notification panel is shown, even just a little bit.
- * See also PhoneStatusBar.setPanelExpanded for another place where we attempt to do this.
- */
- protected void handleVisibleToUserChanged(boolean visibleToUser) {
- try {
- if (visibleToUser) {
- boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
- boolean clearNotificationEffects =
- !isPanelFullyCollapsed() &&
- (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
- int notificationLoad = mNotificationData.getActiveNotifications().size();
- if (pinnedHeadsUp && isPanelFullyCollapsed()) {
- notificationLoad = 1;
- } else {
- MetricsLogger.histogram(mContext, "note_load", notificationLoad);
- }
- mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
- } else {
- mBarService.onPanelHidden();
- }
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
- }
- }
-
- /**
- * Clear Buzz/Beep/Blink.
- */
- public void clearNotificationEffects() {
- try {
- mBarService.clearNotificationEffects();
- } catch (RemoteException e) {
- // Won't fail unless the world has ended.
- }
- }
-
- public abstract boolean isPanelFullyCollapsed();
-
- /**
- * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
- * about the failure.
- *
- * WARNING: this will call back into us. Don't hold any locks.
- */
- void handleNotificationError(StatusBarNotification n, String message) {
- removeNotification(n.getKey(), null);
- try {
- mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
- n.getInitialPid(), message, n.getUserId());
- } catch (RemoteException ex) {
- // The end is nigh.
- }
- }
-
- protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
- NotificationData.Entry entry = mNotificationData.remove(key, ranking);
- if (entry == null) {
- Log.w(TAG, "removeNotification for unknown key: " + key);
- return null;
- }
- updateNotifications();
- return entry.notification;
- }
-
- protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
- if (DEBUG) {
- Log.d(TAG, "createNotificationViews(notification=" + sbn);
- }
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
- try {
- entry.createIcons(mContext, sbn);
- } catch (NotificationData.IconException exception) {
- handleNotificationError(sbn, exception.getMessage());
- }
-
- // Construct the expanded view.
- if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
- return null;
- }
- return entry;
- }
-
- protected void addNotificationViews(Entry entry, RankingMap ranking) {
- if (entry == null) {
- return;
- }
- // Add the expanded view and icon.
- mNotificationData.add(entry, ranking);
- updateNotifications();
- }
-
- /**
- * @param recompute wheter the number should be recomputed
- * @return The number of notifications we show on Keyguard.
- */
- protected abstract int getMaxKeyguardNotifications(boolean recompute);
-
- /**
- * Updates expanded, dimmed and locked states of notification rows.
- */
- protected void updateRowStates() {
- final int N = mStackScroller.getChildCount();
-
- int visibleNotifications = 0;
- boolean onKeyguard = mState == StatusBarState.KEYGUARD;
- int maxNotifications = -1;
- if (onKeyguard) {
- maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
- }
- mStackScroller.setMaxDisplayedNotifications(maxNotifications);
- Stack<ExpandableNotificationRow> stack = new Stack<>();
- for (int i = N - 1; i >= 0; i--) {
- View child = mStackScroller.getChildAt(i);
- if (!(child instanceof ExpandableNotificationRow)) {
- continue;
- }
- stack.push((ExpandableNotificationRow) child);
- }
- while(!stack.isEmpty()) {
- ExpandableNotificationRow row = stack.pop();
- NotificationData.Entry entry = row.getEntry();
- boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
- if (onKeyguard) {
- row.setOnKeyguard(true);
- } else {
- row.setOnKeyguard(false);
- row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
- }
- entry.row.setShowAmbient(isDozing());
- int userId = entry.notification.getUserId();
- boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
- entry.notification) && !entry.row.isRemoved();
- boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
- if (suppressedSummary
- || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
- || (onKeyguard && !showOnKeyguard)) {
- entry.row.setVisibility(View.GONE);
- } else {
- boolean wasGone = entry.row.getVisibility() == View.GONE;
- if (wasGone) {
- entry.row.setVisibility(View.VISIBLE);
- }
- if (!childNotification && !entry.row.isRemoved()) {
- if (wasGone) {
- // notify the scroller of a child addition
- mStackScroller.generateAddAnimation(entry.row,
- !showOnKeyguard /* fromMoreCard */);
- }
- visibleNotifications++;
- }
- }
- if (row.isSummaryWithChildren()) {
- List<ExpandableNotificationRow> notificationChildren =
- row.getNotificationChildren();
- int size = notificationChildren.size();
- for (int i = size - 1; i >= 0; i--) {
- stack.push(notificationChildren.get(i));
- }
- }
- }
-
- mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
- mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
- mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
- }
-
- public boolean isDozing() {
- return false;
- }
-
- public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
- return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
- }
-
- protected void setZenMode(int mode) {
- if (!isDeviceProvisioned()) return;
- mZenMode = mode;
- updateNotifications();
- }
-
- // extended in PhoneStatusBar
- protected void setShowLockscreenNotifications(boolean show) {
- mShowLockscreenNotifications = show;
- }
-
- protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
- mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
- }
-
- private void updateLockscreenNotificationSetting() {
- final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- 1,
- mCurrentUserId) != 0;
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
- null /* admin */, mCurrentUserId);
- final boolean allowedByDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
-
- setShowLockscreenNotifications(show && allowedByDpm);
-
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
- 0,
- mCurrentUserId) != 0;
- final boolean remoteInputDpm =
- (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
-
- setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
- } else {
- setLockScreenAllowRemoteInput(false);
- }
- }
-
- protected abstract void setAreThereNotifications();
- protected abstract void updateNotifications();
-
- public abstract void addNotification(StatusBarNotification notification,
- RankingMap ranking, Entry oldEntry);
- protected abstract void updateNotificationRanking(RankingMap ranking);
- public abstract void removeNotification(String key, RankingMap ranking);
-
- public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
- if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
-
- final String key = notification.getKey();
- Entry entry = mNotificationData.get(key);
- if (entry == null) {
- return;
- } else {
- mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
- mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
- }
-
- Notification n = notification.getNotification();
- mNotificationData.updateRanking(ranking);
-
- boolean applyInPlace;
- try {
- applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
- } catch (RuntimeException e) {
- Log.e(TAG, "Unable to get notification remote views", e);
- applyInPlace = false;
- }
- boolean shouldPeek = shouldPeek(entry, notification);
- boolean alertAgain = alertAgain(entry, n);
- if (DEBUG) {
- Log.d(TAG, "applyInPlace=" + applyInPlace
- + " shouldPeek=" + shouldPeek
- + " alertAgain=" + alertAgain);
- }
-
- final StatusBarNotification oldNotification = entry.notification;
- entry.notification = notification;
- mGroupManager.onEntryUpdated(entry, oldNotification);
-
- boolean updateSuccessful = false;
- try {
- if (applyInPlace) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
- try {
- entry.updateIcons(mContext, n);
- updateNotificationViews(entry, notification);
- updateSuccessful = true;
- } catch (RuntimeException e) {
- // It failed to apply cleanly.
- Log.w(TAG, "Couldn't reapply views for package " +
- notification.getPackageName(), e);
- }
- }
- if (!updateSuccessful) {
- entry.updateIcons(mContext, n);
- if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(notification, "Couldn't update remote views for: "
- + notification);
- }
- }
- } catch (NotificationData.IconException e) {
- handleNotificationError(notification, e.getMessage());
- }
- updateHeadsUp(key, entry, shouldPeek, alertAgain);
- updateNotifications();
-
- if (!notification.isClearable()) {
- // The user may have performed a dismiss action on the notification, since it's
- // not clearable we should snap it back.
- mStackScroller.snapViewIfNeeded(entry.row);
- }
-
- if (DEBUG) {
- // Is this for you?
- boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
- Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
- }
-
- setAreThereNotifications();
- }
-
- protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
- boolean alertAgain);
-
- private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
- final RemoteViews contentView = entry.cachedContentView;
- final RemoteViews bigContentView = entry.cachedBigContentView;
- final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
- final RemoteViews publicContentView = entry.cachedPublicContentView;
-
- // Reapply the RemoteViews
- contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
- if (bigContentView != null && entry.getExpandedContentView() != null) {
- bigContentView.reapply(sbn.getPackageContext(mContext),
- entry.getExpandedContentView(),
- mOnClickHandler);
- }
- View headsUpChild = entry.getHeadsUpContentView();
- if (headsUpContentView != null && headsUpChild != null) {
- headsUpContentView.reapply(sbn.getPackageContext(mContext),
- headsUpChild, mOnClickHandler);
- }
- if (publicContentView != null && entry.getPublicContentView() != null) {
- publicContentView.reapply(sbn.getPackageContext(mContext),
- entry.getPublicContentView(), mOnClickHandler);
- }
- // update the contentIntent
- mNotificationClicker.register(entry.row, sbn);
-
- entry.row.onNotificationUpdated(entry);
- entry.row.resetHeight();
- }
-
- protected void updatePublicContentView(Entry entry,
- StatusBarNotification sbn) {
- final RemoteViews publicContentView = entry.cachedPublicContentView;
- View inflatedView = entry.getPublicContentView();
- if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
- final boolean disabledByPolicy =
- !adminAllowsUnredactedNotifications(entry.notification.getUserId());
- String notificationHiddenText = mContext.getString(disabledByPolicy
- ? com.android.internal.R.string.notification_hidden_by_policy_text
- : com.android.internal.R.string.notification_hidden_text);
- TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
- if (titleView != null
- && !titleView.getText().toString().equals(notificationHiddenText)) {
- publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
- publicContentView.reapply(sbn.getPackageContext(mContext),
- inflatedView, mOnClickHandler);
- entry.row.onNotificationUpdated(entry);
- }
- }
- }
-
- protected void notifyHeadsUpScreenOff() {
- maybeEscalateHeadsUp();
- }
-
- private boolean alertAgain(Entry oldEntry, Notification newNotification) {
- return oldEntry == null || !oldEntry.hasInterrupted()
- || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
- }
-
- protected boolean shouldPeek(Entry entry) {
- return shouldPeek(entry, entry.notification);
- }
-
- protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
- if (!mUseHeadsUp || isDeviceInVrMode()) {
- return false;
- }
-
- if (mNotificationData.shouldFilterOut(sbn)) {
- if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
- return false;
- }
-
- boolean inUse = mPowerManager.isScreenOn();
- try {
- inUse = inUse && !mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.d(TAG, "failed to query dream manager", e);
- }
-
- if (!inUse && !isDozing()) {
- if (DEBUG) {
- Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
- }
- return false;
- }
-
- if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
- return false;
- }
-
- if (entry.hasJustLaunchedFullScreenIntent()) {
- if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
- return false;
- }
-
- if (isSnoozedPackage(sbn)) {
- if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
- return false;
- }
-
- if (mNotificationData.getImportance(sbn.getKey()) < NotificationManager.IMPORTANCE_HIGH) {
- if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
- return false;
- }
-
- if (sbn.getNotification().fullScreenIntent != null) {
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
- return false;
- } else {
- // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
- return !mStatusBarKeyguardViewManager.isShowing()
- || mStatusBarKeyguardViewManager.isOccluded();
- }
- }
-
- return true;
- }
-
- protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
-
- public void setInteracting(int barWindow, boolean interacting) {
- // hook for subclasses
- }
-
- public void setBouncerShowing(boolean bouncerShowing) {
- mBouncerShowing = bouncerShowing;
- }
-
- /**
- * @return Whether the security bouncer from Keyguard is showing.
- */
- public boolean isBouncerShowing() {
- return mBouncerShowing;
- }
-
- public void destroy() {
- mContext.unregisterReceiver(mBroadcastReceiver);
- try {
- mNotificationListener.unregisterAsSystemService();
- } catch (RemoteException e) {
- // Ignore.
- }
- mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
- }
-
- /**
- * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
- * return PackageManager for mContext
- */
- public static PackageManager getPackageManagerForUser(Context context, int userId) {
- Context contextForUser = context;
- // UserHandle defines special userId as negative values, e.g. USER_ALL
- if (userId >= 0) {
- try {
- // Create a context for the correct user so if a package isn't installed
- // for user 0 we can still load information about the package.
- contextForUser =
- context.createPackageContextAsUser(context.getPackageName(),
- Context.CONTEXT_RESTRICTED,
- new UserHandle(userId));
- } catch (NameNotFoundException e) {
- // Shouldn't fail to find the package name for system ui.
- }
- }
- return contextForUser.getPackageManager();
- }
-
- @Override
- public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
- try {
- mBarService.onNotificationExpansionChanged(key, userAction, expanded);
- } catch (RemoteException e) {
- // Ignore.
- }
- }
-
- public boolean isKeyguardSecure() {
- if (mStatusBarKeyguardViewManager == null) {
- // startKeyguard() hasn't been called yet, so we don't know.
- // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
- // value onVisibilityChanged().
- Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
- new Throwable());
- return false;
- }
- return mStatusBarKeyguardViewManager.isSecure();
- }
-
- @Override
- public void showAssistDisclosure() {
- if (mAssistManager != null) {
- mAssistManager.showDisclosure();
- }
- }
-
- @Override
- public void startAssist(Bundle args) {
- if (mAssistManager != null) {
- mAssistManager.startAssist(args);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 477701cb64c0..9245df0ff5fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -63,9 +63,6 @@ public class CommandQueue extends IStatusBar.Stub {
private static final int MSG_SET_WINDOW_STATE = 12 << MSG_SHIFT;
private static final int MSG_SHOW_RECENT_APPS = 13 << MSG_SHIFT;
private static final int MSG_HIDE_RECENT_APPS = 14 << MSG_SHIFT;
- private static final int MSG_BUZZ_BEEP_BLINKED = 15 << MSG_SHIFT;
- private static final int MSG_NOTIFICATION_LIGHT_OFF = 16 << MSG_SHIFT;
- private static final int MSG_NOTIFICATION_LIGHT_PULSE = 17 << MSG_SHIFT;
private static final int MSG_SHOW_SCREEN_PIN_REQUEST = 18 << MSG_SHIFT;
private static final int MSG_APP_TRANSITION_PENDING = 19 << MSG_SHIFT;
private static final int MSG_APP_TRANSITION_CANCELLED = 20 << MSG_SHIFT;
@@ -121,9 +118,6 @@ public class CommandQueue extends IStatusBar.Stub {
default void toggleKeyboardShortcutsMenu(int deviceId) { }
default void cancelPreloadRecentApps() { }
default void setWindowState(int window, int state) { }
- default void buzzBeepBlinked() { }
- default void notificationLightOff() { }
- default void notificationLightPulse(int argb, int onMillis, int offMillis) { }
default void showScreenPinningRequest(int taskId) { }
default void appTransitionPending() { }
default void appTransitionCancelled() { }
@@ -313,26 +307,6 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void buzzBeepBlinked() {
- synchronized (mLock) {
- mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
- mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
- }
- }
-
- public void notificationLightOff() {
- synchronized (mLock) {
- mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF);
- }
- }
-
- public void notificationLightPulse(int argb, int onMillis, int offMillis) {
- synchronized (mLock) {
- mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb)
- .sendToTarget();
- }
- }
-
public void showScreenPinningRequest(int taskId) {
synchronized (mLock) {
mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null)
@@ -524,21 +498,6 @@ public class CommandQueue extends IStatusBar.Stub {
mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2);
}
break;
- case MSG_BUZZ_BEEP_BLINKED:
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).buzzBeepBlinked();
- }
- break;
- case MSG_NOTIFICATION_LIGHT_OFF:
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).notificationLightOff();
- }
- break;
- case MSG_NOTIFICATION_LIGHT_PULSE:
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
- }
- break;
case MSG_SHOW_SCREEN_PIN_REQUEST:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showScreenPinningRequest(msg.arg1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 93c48f86cec9..2e9c7fd85e42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -22,6 +22,7 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -50,9 +51,12 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ExpandableViewState;
@@ -73,6 +77,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mMaxHeadsUpHeightLegacy;
private int mMaxHeadsUpHeight;
private int mNotificationMinHeight;
+ private int mNotificationMinHeightLarge;
private int mNotificationMaxHeight;
private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
@@ -118,7 +123,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mNotificationColor;
private ExpansionLogger mLogger;
private String mLoggingKey;
- private NotificationSettingsIconRow mSettingsIconRow;
+ private NotificationMenuRow mMenuRow;
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
@@ -130,7 +135,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mChildrenExpanded;
private boolean mIsSummaryWithChildren;
private NotificationChildrenContainer mChildrenContainer;
- private ViewStub mSettingsIconRowStub;
+ private ViewStub mMenuRowStub;
private ViewStub mGutsStub;
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
@@ -201,7 +206,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mShowAmbient;
private boolean mIsLastChild;
private Runnable mOnDismissRunnable;
+ private boolean mIsLowPriority;
+ private boolean mIsColorized;
+ private boolean mUseIncreasedCollapsedHeight;
+ @Override
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
return mNotificationParent.isGroupExpansionChanging();
@@ -292,6 +301,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(entry);
}
+ mIsColorized = mStatusBarNotification.getNotification().isColorized();
mShowingPublicInitialized = false;
updateNotificationColor();
if (mIsSummaryWithChildren) {
@@ -309,6 +319,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPublicLayout.updateExpandButtons(true);
updateLimits();
updateIconVisibilities();
+ updateShelfIconColor();
+ }
+
+ private void updateShelfIconColor() {
+ StatusBarIconView expandedIcon = mEntry.expandedIcon;
+ boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
+ boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
+ NotificationColorUtil.getInstance(mContext));
+ if (colorize) {
+ int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
+ expandedIcon.setImageTintList(ColorStateList.valueOf(color));
+ }
}
private void updateLimits() {
@@ -321,8 +343,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
boolean customView = layout.getContractedChild().getId()
!= com.android.internal.R.id.status_bar_latest_event_content;
boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
- int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
- mNotificationMinHeightLegacy : mNotificationMinHeight;
+ int minHeight;
+ if (customView && beforeN && !mIsSummaryWithChildren) {
+ minHeight = mNotificationMinHeightLegacy;
+ } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
+ minHeight = mNotificationMinHeightLarge;
+ } else {
+ minHeight = mNotificationMinHeight;
+ }
boolean headsUpCustom = layout.getHeadsUpChild() != null &&
layout.getHeadsUpChild().getId()
!= com.android.internal.R.id.status_bar_latest_event_content;
@@ -371,8 +399,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setAppName(String appName) {
mAppName = appName;
- if (mSettingsIconRow != null) {
- mSettingsIconRow.setAppName(mAppName);
+ if (mMenuRow != null) {
+ mMenuRow.setAppName(mAppName);
}
}
@@ -403,6 +431,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
row.setIsChildInGroup(false, null);
}
+ @Override
public boolean isChildInGroup() {
return mNotificationParent != null;
}
@@ -416,7 +445,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
* @param parent the new parent notification
*/
public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
- boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
+ boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
mNotificationParent = childInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(childInGroup);
resetBackgroundAlpha();
@@ -440,7 +469,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
protected boolean handleSlideBack() {
- if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
+ if (mMenuRow != null && mMenuRow.isVisible()) {
animateTranslateNotification(0 /* targetLeft */);
return true;
}
@@ -664,6 +693,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mHeadsUpManager = headsUpManager;
}
+ public void setGutsView(MenuItem item) {
+ if (mGuts != null) {
+ item.gutsContent.setInteractionListener(mGuts);
+ mGuts.setGutsContent(item.gutsContent);
+ }
+ }
+
public void reInflateViews() {
initDimens();
if (mIsSummaryWithChildren) {
@@ -680,16 +716,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mGuts.setVisibility(oldGuts.getVisibility());
addView(mGuts, index);
}
- if (mSettingsIconRow != null) {
- View oldSettings = mSettingsIconRow;
- int settingsIndex = indexOfChild(oldSettings);
- removeView(oldSettings);
- mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
- R.layout.notification_settings_icon_row, this, false);
- mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
- mSettingsIconRow.setAppName(mAppName);
- mSettingsIconRow.setVisibility(oldSettings.getVisibility());
- addView(mSettingsIconRow, settingsIndex);
+ if (mMenuRow != null) {
+ View oldMenu = mMenuRow;
+ int menuIndex = indexOfChild(oldMenu);
+ removeView(oldMenu);
+ mMenuRow = (NotificationMenuRow) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_menu_row, this, false);
+ mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ mMenuRow.setAppName(mAppName);
+ mMenuRow.setVisibility(oldMenu.getVisibility());
+ addView(mMenuRow, menuIndex);
}
for (NotificationContentView l : mLayouts) {
@@ -943,6 +979,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mPrivateLayout.getTranslationY();
}
+ public void setIsLowPriority(boolean isLowPriority) {
+ mIsLowPriority = isLowPriority;
+ mPrivateLayout.setIsLowPriority(isLowPriority);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setIsLowPriority(isLowPriority);
+ }
+ }
+
+ public void setUseIncreasedCollapsedHeight(boolean use) {
+ mUseIncreasedCollapsedHeight = use;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -956,6 +1004,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private void initDimens() {
mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
+ mNotificationMinHeightLarge = getFontScaledHeight(
+ R.dimen.notification_min_height_large);
mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
mMaxHeadsUpHeightLegacy = getFontScaledHeight(
@@ -1010,21 +1060,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
for (NotificationContentView l : mLayouts) {
l.setExpandClickListener(mExpandClickListener);
l.setContainingNotification(this);
}
-
- mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
- mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+ mMenuRowStub = (ViewStub) findViewById(R.id.menu_row_stub);
+ mMenuRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
- mSettingsIconRow = (NotificationSettingsIconRow) inflated;
- mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
- mSettingsIconRow.setAppName(mAppName);
+ mMenuRow = (NotificationMenuRow) inflated;
+ mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ mMenuRow.setAppName(mAppName);
}
});
mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
@@ -1043,6 +1091,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public void onInflate(ViewStub stub, View inflated) {
mChildrenContainer = (NotificationChildrenContainer) inflated;
+ mChildrenContainer.setIsLowPriority(mIsLowPriority);
mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
mTranslateableViews.add(mChildrenContainer);
@@ -1055,7 +1104,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mTranslateableViews.add(getChildAt(i));
}
// Remove views that don't translate
- mTranslateableViews.remove(mSettingsIconRowStub);
+ mTranslateableViews.remove(mMenuRowStub);
mTranslateableViews.remove(mChildrenContainerStub);
mTranslateableViews.remove(mGutsStub);
}
@@ -1070,8 +1119,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
invalidateOutline();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.resetState();
+ if (mMenuRow != null) {
+ mMenuRow.resetState(true /* notify */);
}
}
@@ -1098,8 +1147,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
invalidateOutline();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
+ if (mMenuRow != null) {
+ mMenuRow.updateMenuAlpha(translationX, getMeasuredWidth());
}
}
@@ -1136,8 +1185,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public void onAnimationEnd(Animator anim) {
- if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
- mSettingsIconRow.resetState();
+ if (!cancelled && mMenuRow != null && leftTarget == 0) {
+ mMenuRow.resetState(true /* notify */);
mTranslateAnim = null;
}
}
@@ -1147,17 +1196,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
public float getSpaceForGear() {
- if (mSettingsIconRow != null) {
- return mSettingsIconRow.getSpaceForGear();
+ if (mMenuRow != null) {
+ return mMenuRow.getSpaceForMenu();
}
return 0;
}
- public NotificationSettingsIconRow getSettingsRow() {
- if (mSettingsIconRow == null) {
- mSettingsIconRowStub.inflate();
+ public NotificationMenuRow getSettingsRow() {
+ if (mMenuRow == null) {
+ mMenuRowStub.inflate();
}
- return mSettingsIconRow;
+ return mMenuRow;
}
public void inflateGuts() {
@@ -1242,6 +1291,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
public void setUserExpanded(boolean userExpanded) {
setUserExpanded(userExpanded, false /* allowChildExpansion */);
+ updateShelfIconColor();
}
/**
@@ -1301,6 +1351,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (expand != mIsSystemExpanded) {
final boolean wasExpanded = isExpanded();
mIsSystemExpanded = expand;
+ updateShelfIconColor();
notifyHeightChanged(false /* needsAnimation */);
logExpansionEvent(false, wasExpanded);
if (mIsSummaryWithChildren) {
@@ -1378,12 +1429,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
}
private void onChildrenCountChanged() {
- mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
+ mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
@@ -1431,8 +1483,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateMaxHeights();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.updateVerticalLocation();
+ if (mMenuRow != null) {
+ mMenuRow.updateVerticalLocation();
}
updateContentShiftHeight();
}
@@ -1479,6 +1531,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mSensitiveHiddenInGeneral = hideSensitive;
}
+ @Override
public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
mHideSensitiveForIntrinsicHeight = hideSensitive;
if (mIsSummaryWithChildren) {
@@ -1491,6 +1544,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
long duration) {
boolean oldShowingPublic = mShowingPublic;
@@ -1555,6 +1609,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public boolean mustStayOnScreen() {
return mIsHeadsUp;
}
@@ -1741,9 +1796,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
- @Override
public void setShowingLegacyBackground(boolean showing) {
- super.setShowingLegacyBackground(showing);
for (NotificationContentView l : mLayouts) {
l.setShowingLegacyBackground(showing);
}
@@ -1827,10 +1880,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
} else if (isUserLocked()) {
return mChildrenContainer.getGroupExpandFraction();
}
+ } 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) {
float x = event.getX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 37a900e52e86..6a1f470c846a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -404,7 +404,9 @@ public abstract class ExpandableView extends FrameLayout {
}
/**
- * @return an amount between 0 and 1 of increased padding that this child needs
+ * @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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 08fd93da7924..d599ec1a2062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -47,6 +47,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.UserInfoController;
/**
* Controls the indications and error messages shown on the Keyguard
@@ -83,6 +84,8 @@ public class KeyguardIndicationController {
private int mChargingWattage;
private String mMessageToShowOnScreenOn;
+ private KeyguardUpdateMonitorCallback mUpdateMonitor;
+
private final DevicePolicyManager mDevicePolicyManager;
public KeyguardIndicationController(Context context, ViewGroup indicationArea,
@@ -106,7 +109,7 @@ public class KeyguardIndicationController {
mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
+ KeyguardUpdateMonitor.getInstance(context).registerCallback(getKeyguardCallback());
context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_TIME_TICK), null,
Dependency.get(Dependency.TIME_TICK_HANDLER));
@@ -114,6 +117,23 @@ public class KeyguardIndicationController {
updateDisclosure();
}
+ /**
+ * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
+ * {@link KeyguardIndicationController}.
+ *
+ * <p>Subclasses may override this method to extend or change the callback behavior by extending
+ * the {@link BaseKeyguardCallback}.
+ *
+ * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
+ * same instance.
+ */
+ protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
+ if (mUpdateMonitor == null) {
+ mUpdateMonitor = new BaseKeyguardCallback();
+ }
+ return mUpdateMonitor;
+ }
+
private void updateDisclosure() {
if (mDevicePolicyManager == null) {
return;
@@ -152,6 +172,12 @@ public class KeyguardIndicationController {
}
/**
+ * Sets the active controller managing changes and callbacks to user information.
+ */
+ public void setUserInfoController(UserInfoController userInfoController) {
+ }
+
+ /**
* Hides transient indication in {@param delayMs}.
*/
public void hideTransientIndicationDelayed(long delayMs) {
@@ -264,8 +290,37 @@ public class KeyguardIndicationController {
}
}
- KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
- public int mLastSuccessiveErrorMessage = -1;
+ public void setStatusBarKeyguardViewManager(
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ }
+
+ BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.post(() -> {
+ if (mVisible) {
+ updateIndication();
+ }
+ });
+ }
+ };
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_HIDE_TRANSIENT && mTransientIndication != null) {
+ mTransientIndication = null;
+ updateIndication();
+ } else if (msg.what == MSG_CLEAR_FP_MSG) {
+ mLockIcon.setTransientFpError(false);
+ hideTransientIndication();
+ }
+ }
+ };
+
+ protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
+ private int mLastSuccessiveErrorMessage = -1;
@Override
public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
@@ -372,34 +427,4 @@ public class KeyguardIndicationController {
}
}
};
-
- BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.post(() -> {
- if (mVisible) {
- updateIndication();
- }
- });
- }
- };
-
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_HIDE_TRANSIENT && mTransientIndication != null) {
- mTransientIndication = null;
- updateIndication();
- } else if (msg.what == MSG_CLEAR_FP_MSG) {
- mLockIcon.setTransientFpError(false);
- hideTransientIndication();
- }
- }
- };
-
- public void setStatusBarKeyguardViewManager(
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
- mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index b45cde87d79a..57d2e1c84115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -89,6 +89,7 @@ public class NotificationContentView extends FrameLayout {
private StatusBarNotification mStatusBarNotification;
private NotificationGroupManager mGroupManager;
private RemoteInputController mRemoteInputController;
+ private Runnable mExpandedVisibleListener;
private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
= new ViewTreeObserver.OnPreDrawListener() {
@@ -129,6 +130,7 @@ public class NotificationContentView extends FrameLayout {
private boolean mHeadsUpAnimatingAway;
private boolean mIconsVisible;
private int mClipBottomAmount;
+ private boolean mIsLowPriority;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -163,20 +165,31 @@ public class NotificationContentView extends FrameLayout {
if (mExpandedChild != null) {
int size = Math.min(maxSize, mNotificationMaxHeight);
ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
+ boolean useExactly = false;
if (layoutParams.height >= 0) {
// An actual height is set
size = Math.min(maxSize, layoutParams.height);
+ useExactly = true;
}
int spec = size == Integer.MAX_VALUE
? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ : MeasureSpec.makeMeasureSpec(size, useExactly
+ ? MeasureSpec.EXACTLY
+ : MeasureSpec.AT_MOST);
mExpandedChild.measure(widthMeasureSpec, spec);
maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
}
if (mContractedChild != null) {
int heightSpec;
int size = Math.min(maxSize, mSmallHeight);
- if (shouldContractedBeFixedSize()) {
+ ViewGroup.LayoutParams layoutParams = mContractedChild.getLayoutParams();
+ boolean useExactly = false;
+ if (layoutParams.height >= 0) {
+ // An actual height is set
+ size = Math.min(size, layoutParams.height);
+ useExactly = true;
+ }
+ if (shouldContractedBeFixedSize() || useExactly) {
heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
@@ -202,12 +215,15 @@ public class NotificationContentView extends FrameLayout {
if (mHeadsUpChild != null) {
int size = Math.min(maxSize, mHeadsUpHeight);
ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
+ boolean useExactly = false;
if (layoutParams.height >= 0) {
// An actual height is set
size = Math.min(size, layoutParams.height);
+ useExactly = true;
}
mHeadsUpChild.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+ : MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
}
if (mSingleLineView != null) {
@@ -225,12 +241,15 @@ public class NotificationContentView extends FrameLayout {
if (mAmbientChild != null) {
int size = Math.min(maxSize, mNotificationAmbientHeight);
ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
+ boolean useExactly = false;
if (layoutParams.height >= 0) {
// An actual height is set
size = Math.min(size, layoutParams.height);
+ useExactly = true;
}
mAmbientChild.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+ : MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
}
int ownHeight = Math.min(maxChildHeight, maxSize);
@@ -480,18 +499,14 @@ public class NotificationContentView extends FrameLayout {
com.android.internal.R.dimen.notification_action_list_height);
}
- if (isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
- return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_action_list_height);
- }
-
// Transition between heads-up & expanded, or pinned.
if (mHeadsUpChild != null && mExpandedChild != null) {
boolean transitioningBetweenHunAndExpanded =
isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
- && (mIsHeadsUp || mHeadsUpAnimatingAway);
+ && (mIsHeadsUp || mHeadsUpAnimatingAway)
+ && !mContainingNotification.isOnKeyguard();
if (transitioningBetweenHunAndExpanded || pinned) {
return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
}
@@ -504,7 +519,9 @@ public class NotificationContentView extends FrameLayout {
}
int hint;
- if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
+ if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
+ hint = mAmbientChild.getHeight();
+ } else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
hint = mHeadsUpChild.getHeight();
} else if (mExpandedChild != null) {
hint = mExpandedChild.getHeight();
@@ -595,7 +612,7 @@ public class NotificationContentView extends FrameLayout {
public int getMaxHeight() {
if (mExpandedChild != null) {
return mExpandedChild.getHeight();
- } else if (mIsHeadsUp && mHeadsUpChild != null) {
+ } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
return mHeadsUpChild.getHeight();
}
return mContractedChild.getHeight();
@@ -606,7 +623,7 @@ public class NotificationContentView extends FrameLayout {
}
public int getMinHeight(boolean likeGroupExpanded) {
- if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
+ if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded() || mIsLowPriority) {
return mContractedChild.getHeight();
} else {
return mSingleLineView.getHeight();
@@ -666,10 +683,6 @@ public class NotificationContentView extends FrameLayout {
visibleView.setVisibility(VISIBLE);
transferRemoteInputFocus(visibleType);
}
- NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
- if (visibleWrapper != null) {
- visibleWrapper.setContentHeight(mContentHeight, getMinContentHeightHint());
- }
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
|| (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
@@ -683,6 +696,10 @@ public class NotificationContentView extends FrameLayout {
if (changedType) {
focusExpandButtonIfNecessary();
}
+ NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
+ if (visibleWrapper != null) {
+ visibleWrapper.setContentHeight(mContentHeight, getMinContentHeightHint());
+ }
updateBackgroundColor(animate);
}
}
@@ -694,11 +711,21 @@ public class NotificationContentView extends FrameLayout {
forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+ fireExpandedVisibleListenerIfVisible();
// forceUpdateVisibilities cancels outstanding animations without updating the
// mAnimationStartVisibleType. Do so here instead.
mAnimationStartVisibleType = UNDEFINED;
}
+ private void fireExpandedVisibleListenerIfVisible() {
+ if (mExpandedVisibleListener != null && mExpandedChild != null && isShown()
+ && mExpandedChild.getVisibility() == VISIBLE) {
+ Runnable listener = mExpandedVisibleListener;
+ mExpandedVisibleListener = null;
+ listener.run();
+ }
+ }
+
private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
if (view == null) {
return;
@@ -752,6 +779,7 @@ public class NotificationContentView extends FrameLayout {
mSingleLineView, mSingleLineView);
updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
mAmbientChild, mAmbientWrapper);
+ fireExpandedVisibleListenerIfVisible();
// updateViewVisibilities cancels outstanding animations without updating the
// mAnimationStartVisibleType. Do so here instead.
mAnimationStartVisibleType = UNDEFINED;
@@ -783,6 +811,7 @@ public class NotificationContentView extends FrameLayout {
mAnimationStartVisibleType = UNDEFINED;
}
});
+ fireExpandedVisibleListenerIfVisible();
}
private void transferRemoteInputFocus(int visibleType) {
@@ -868,7 +897,7 @@ public class NotificationContentView extends FrameLayout {
height = mContentHeight;
}
int expandedVisualType = getVisualTypeForHeight(height);
- int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
+ int collapsedVisualType = mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority
? VISIBLE_TYPE_SINGLELINE
: getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
return mTransformationStartVisibleType == collapsedVisualType
@@ -889,11 +918,12 @@ public class NotificationContentView extends FrameLayout {
if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
return VISIBLE_TYPE_EXPANDED;
}
- if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
+ if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority) {
return VISIBLE_TYPE_SINGLELINE;
}
- if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null) {
+ if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
+ && !mContainingNotification.isOnKeyguard()) {
if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
return VISIBLE_TYPE_HEADSUP;
} else {
@@ -974,19 +1004,19 @@ public class NotificationContentView extends FrameLayout {
mStatusBarNotification = entry.notification;
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateSingleLineView();
- applyRemoteInput(entry);
if (mContractedChild != null) {
- mContractedWrapper.notifyContentUpdated(entry.notification);
+ mContractedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
}
if (mExpandedChild != null) {
- mExpandedWrapper.notifyContentUpdated(entry.notification);
+ mExpandedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
}
if (mHeadsUpChild != null) {
- mHeadsUpWrapper.notifyContentUpdated(entry.notification);
+ mHeadsUpWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
}
if (mAmbientChild != null) {
- mAmbientWrapper.notifyContentUpdated(entry.notification);
+ mAmbientWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
}
+ applyRemoteInput(entry);
updateShowingLegacyBackground();
mForceSelectNextLayout = true;
setDark(mDark, false /* animate */, 0 /* delay */);
@@ -1028,7 +1058,8 @@ public class NotificationContentView extends FrameLayout {
View bigContentView = mExpandedChild;
if (bigContentView != null) {
mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
- mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput);
+ mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput,
+ mExpandedWrapper);
} else {
mExpandedRemoteInput = null;
}
@@ -1042,7 +1073,7 @@ public class NotificationContentView extends FrameLayout {
View headsUpContentView = mHeadsUpChild;
if (headsUpContentView != null) {
mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
- mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput);
+ mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput, mHeadsUpWrapper);
} else {
mHeadsUpRemoteInput = null;
}
@@ -1056,7 +1087,7 @@ public class NotificationContentView extends FrameLayout {
private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
boolean hasRemoteInput, PendingIntent existingPendingIntent,
- RemoteInputView cachedView) {
+ RemoteInputView cachedView, NotificationViewWrapper wrapper) {
View actionContainerCandidate = view.findViewById(
com.android.internal.R.id.actions_container);
if (actionContainerCandidate instanceof FrameLayout) {
@@ -1095,6 +1126,8 @@ public class NotificationContentView extends FrameLayout {
mContext.getColor(R.color.remote_input_text_enabled),
mContext.getColor(R.color.remote_input_hint)));
+ existing.setWrapper(wrapper);
+
if (existingPendingIntent != null || existing.isActive()) {
// The current action could be gone, or the pending intent no longer valid.
// If we find a matching action in the new notification, focus, otherwise close.
@@ -1143,7 +1176,7 @@ public class NotificationContentView extends FrameLayout {
mExpandable = expandable;
// if the expanded child has the same height as the collapsed one we hide it.
if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
- if ((!mIsHeadsUp || mHeadsUpChild == null)) {
+ if (!mIsHeadsUp || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
if (mExpandedChild.getHeight() == mContractedChild.getHeight()) {
expandable = false;
}
@@ -1282,4 +1315,26 @@ public class NotificationContentView extends FrameLayout {
}
}
}
+
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+ if (isVisible) {
+ fireExpandedVisibleListenerIfVisible();
+ }
+ }
+
+ /**
+ * Sets a one-shot listener for when the expanded view becomes visible.
+ *
+ * This will fire the listener immediately if the expanded view is already visible.
+ */
+ public void setOnExpandedVisibleListener(Runnable r) {
+ mExpandedVisibleListener = r;
+ fireExpandedVisibleListenerIfVisible();
+ }
+
+ public void setIsLowPriority(boolean isLowPriority) {
+ mIsLowPriority = isLowPriority;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 3a891860c0cb..f73a5ea04ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -25,6 +25,7 @@ import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.view.View;
@@ -34,12 +35,14 @@ import android.widget.RemoteViews;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.Objects;
/**
@@ -71,6 +74,7 @@ public class NotificationData {
public RemoteViews cachedPublicContentView;
public RemoteViews cachedAmbientContentView;
public CharSequence remoteInputText;
+ public List<SnoozeCriterion> snoozeCriteria;
private int mCachedContrastColor = COLOR_INVALID;
private int mCachedContrastColorIsFor = COLOR_INVALID;
@@ -117,14 +121,20 @@ public class NotificationData {
return row.getPublicLayout().getContractedChild();
}
- public boolean cacheContentViews(Context ctx, Notification updatedNotification) {
+ public View getAmbientContentView() {
+ return row.getPrivateLayout().getAmbientChild();
+ }
+
+ public boolean cacheContentViews(Context ctx, Notification updatedNotification,
+ boolean isLowPriority, boolean useIncreasedCollapsedView) {
boolean applyInPlace = false;
if (updatedNotification != null) {
final Notification.Builder updatedNotificationBuilder
= Notification.Builder.recoverBuilder(ctx, updatedNotification);
- final RemoteViews newContentView = updatedNotificationBuilder.createContentView();
- final RemoteViews newBigContentView =
- updatedNotificationBuilder.createBigContentView();
+ final RemoteViews newContentView = createContentView(updatedNotificationBuilder,
+ isLowPriority, useIncreasedCollapsedView);
+ final RemoteViews newBigContentView = createBigContentView(
+ updatedNotificationBuilder, isLowPriority);
final RemoteViews newHeadsUpContentView =
updatedNotificationBuilder.createHeadsUpContentView();
final RemoteViews newPublicNotification
@@ -152,8 +162,9 @@ public class NotificationData {
final Notification.Builder builder
= Notification.Builder.recoverBuilder(ctx, notification.getNotification());
- cachedContentView = builder.createContentView();
- cachedBigContentView = builder.createBigContentView();
+ cachedContentView = createContentView(builder, isLowPriority,
+ useIncreasedCollapsedView);
+ cachedBigContentView = createBigContentView(builder, isLowPriority);
cachedHeadsUpContentView = builder.createHeadsUpContentView();
cachedPublicContentView = builder.makePublicContentView();
cachedAmbientContentView = builder.makeAmbientNotification();
@@ -163,6 +174,28 @@ public class NotificationData {
return applyInPlace;
}
+ private RemoteViews createBigContentView(Notification.Builder builder,
+ boolean isLowPriority) {
+ RemoteViews bigContentView = builder.createBigContentView();
+ if (bigContentView != null) {
+ return bigContentView;
+ }
+ if (isLowPriority) {
+ RemoteViews contentView = builder.createContentView();
+ Notification.Builder.makeHeaderExpanded(contentView);
+ return contentView;
+ }
+ return null;
+ }
+
+ private RemoteViews createContentView(Notification.Builder builder,
+ boolean isLowPriority, boolean useLarge) {
+ if (isLowPriority) {
+ return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
+ }
+ return builder.createContentView(useLarge);
+ }
+
// Returns true if the RemoteViews are the same.
private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
return (a == null && b == null) ||
@@ -256,8 +289,9 @@ public class NotificationData {
}
}
- public int getContrastedColor(Context context) {
- int rawColor = notification.getNotification().color;
+ public int getContrastedColor(Context context, boolean ambient) {
+ int rawColor = ambient ? Notification.COLOR_DEFAULT :
+ notification.getNotification().color;
if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
return mCachedContrastColor;
}
@@ -431,6 +465,14 @@ public class NotificationData {
return null;
}
+ public List<SnoozeCriterion> getSnoozeCriteria(String key) {
+ if (mRankingMap != null) {
+ mRankingMap.getRanking(key, mTmpRanking);
+ return mTmpRanking.getSnoozeCriteria();
+ }
+ return null;
+ }
+
public NotificationChannel getChannel(String key) {
if (mRankingMap != null) {
mRankingMap.getRanking(key, mTmpRanking);
@@ -453,6 +495,7 @@ public class NotificationData {
mGroupManager.onEntryUpdated(entry, oldSbn);
}
entry.channel = getChannel(entry.key);
+ entry.snoozeCriteria = getSnoozeCriteria(entry.key);
}
}
}
@@ -481,7 +524,7 @@ public class NotificationData {
Collections.sort(mSortedAndFiltered, mRankingComparator);
}
- boolean shouldFilterOut(StatusBarNotification sbn) {
+ public boolean shouldFilterOut(StatusBarNotification sbn) {
if (!(mEnvironment.isDeviceProvisioned() ||
showNotificationEvenIfUnprovisioned(sbn))) {
return true;
@@ -498,7 +541,7 @@ public class NotificationData {
return true;
}
- if (!BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
+ if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mGroupManager.isChildInGroupWithSummary(sbn)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 83104e685e22..f6056ddab093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -40,6 +40,7 @@ import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.widget.CompoundButton;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
@@ -53,6 +54,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.Set;
@@ -60,7 +63,8 @@ import java.util.Set;
/**
* The guts of a notification revealed when performing a long press.
*/
-public class NotificationGuts extends LinearLayout {
+public class NotificationGuts extends FrameLayout
+ implements NotificationMenuRowProvider.GutsInteractionListener {
private static final String TAG = "NotificationGuts";
private static final long CLOSE_GUTS_DELAY = 8000;
@@ -69,24 +73,14 @@ public class NotificationGuts extends LinearLayout {
private int mClipBottomAmount;
private int mActualHeight;
private boolean mExposed;
- private INotificationManager mINotificationManager;
- private int mStartingUserImportance;
- private StatusBarNotification mStatusBarNotification;
- private NotificationChannel mNotificationChannel;
-
- private View mImportanceGroup;
- private View mChannelDisabled;
- private Switch mChannelEnabledSwitch;
- private RadioButton mMinImportanceButton;
- private RadioButton mLowImportanceButton;
- private RadioButton mDefaultImportanceButton;
- private RadioButton mHighImportanceButton;
private Handler mHandler;
private Runnable mFalsingCheck;
private boolean mNeedsFalsingProtection;
private OnGutsClosedListener mListener;
+ private GutsContent mGutsContent;
+
public interface OnGutsClosedListener {
public void onGutsClosed(NotificationGuts guts);
}
@@ -103,11 +97,22 @@ public class NotificationGuts extends LinearLayout {
}
}
};
- final TypedArray ta =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Theme, 0, 0);
+ final TypedArray ta = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Theme, 0, 0);
ta.recycle();
}
+ public NotificationGuts(Context context) {
+ this(context, null);
+
+ }
+
+ public void setGutsContent(GutsContent content) {
+ mGutsContent = content;
+ removeAllViews();
+ addView(mGutsContent.getContentView());
+ }
+
public void resetFalsingCheck() {
mHandler.removeCallbacks(mFalsingCheck);
if (mNeedsFalsingProtection && mExposed) {
@@ -165,213 +170,23 @@ public class NotificationGuts extends LinearLayout {
void onClick(View v, int appUid);
}
- void bindNotification(final PackageManager pm, final INotificationManager iNotificationManager,
- final StatusBarNotification sbn, final NotificationChannel channel,
- OnSettingsClickListener onSettingsClick,
- OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
- mINotificationManager = iNotificationManager;
- mNotificationChannel = channel;
- mStatusBarNotification = sbn;
- mStartingUserImportance = channel.getImportance();
-
- final String pkg = sbn.getPackageName();
- int appUid = -1;
- String appname = pkg;
- Drawable pkgicon = null;
- try {
- final ApplicationInfo info = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (info != null) {
- appUid = info.uid;
- appname = String.valueOf(pm.getApplicationLabel(info));
- pkgicon = pm.getApplicationIcon(info);
- }
- } catch (PackageManager.NameNotFoundException e) {
- // app is gone, just show package name and generic icon
- pkgicon = pm.getDefaultActivityIcon();
- }
-
- // If this is the placeholder channel, don't use our channel-specific text.
- String appNameText;
- CharSequence channelNameText;
- if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- appNameText = appname;
- channelNameText = mContext.getString(R.string.notification_header_default_channel);
- } else {
- appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
- channelNameText = channel.getName();
- }
- ((TextView) findViewById(R.id.pkgname)).setText(appNameText);
- ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
-
- // Settings button.
- final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
- if (appUid >= 0 && onSettingsClick != null) {
- final int appUidF = appUid;
- settingsButton.setOnClickListener(
- (View view) -> { onSettingsClick.onClick(view, appUidF); });
- settingsButton.setText(R.string.notification_more_settings);
- } else {
- settingsButton.setVisibility(View.GONE);
- }
-
- // Done button.
- final TextView doneButton = (TextView) findViewById(R.id.done);
- doneButton.setText(R.string.notification_done);
- doneButton.setOnClickListener(onDoneClick);
-
- boolean nonBlockable = false;
- try {
- final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
- nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
- } catch (PackageManager.NameNotFoundException e) {
- // unlikely.
- }
- if (nonBlockablePkgs != null) {
- nonBlockable |= nonBlockablePkgs.contains(pkg);
- }
-
- final View importanceButtons = findViewById(R.id.importance_buttons);
- bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
-
- // Importance Text (hardcoded to 4 importance levels)
- final ViewGroup importanceTextGroup =
- (ViewGroup) findViewById(R.id.importance_buttons_text);
- final int size = importanceTextGroup.getChildCount();
- for (int i = 0; i < size; i++) {
- int importanceNameResId = 0;
- int importanceDescResId = 0;
- switch (i) {
- case 0:
- importanceNameResId = R.string.high_importance;
- importanceDescResId = R.string.notification_importance_high;
- break;
- case 1:
- importanceNameResId = R.string.default_importance;
- importanceDescResId = R.string.notification_importance_default;
- break;
- case 2:
- importanceNameResId = R.string.low_importance;
- importanceDescResId = R.string.notification_importance_low;
- break;
- case 3:
- importanceNameResId = R.string.min_importance;
- importanceDescResId = R.string.notification_importance_min;
- break;
- default:
- Log.e(TAG, "Too many importance groups in this layout.");
- break;
- }
- final ViewGroup importanceChildGroup = (ViewGroup) importanceTextGroup.getChildAt(i);
- ((TextView) importanceChildGroup.getChildAt(0)).setText(importanceNameResId);
- ((TextView) importanceChildGroup.getChildAt(1)).setText(importanceDescResId);
- }
-
- // Top-level importance group
- mImportanceGroup = findViewById(R.id.importance);
- mChannelDisabled = findViewById(R.id.channel_disabled);
- updateImportanceGroup();
- }
-
- public boolean hasImportanceChanged() {
- return mStartingUserImportance != getSelectedImportance();
- }
-
- private void saveImportance() {
- int selectedImportance = getSelectedImportance();
- if (selectedImportance == mStartingUserImportance) {
- return;
- }
- MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
- selectedImportance - mStartingUserImportance);
- mNotificationChannel.setImportance(selectedImportance);
- try {
- mINotificationManager.updateNotificationChannelForPackage(
- mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
- mNotificationChannel);
- } catch (RemoteException e) {
- // :(
- }
- }
-
- private int getSelectedImportance() {
- if (!mChannelEnabledSwitch.isChecked()) {
- return NotificationManager.IMPORTANCE_NONE;
- } else if (mMinImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_MIN;
- } else if (mLowImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_LOW;
- } else if (mDefaultImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_DEFAULT;
- } else if (mHighImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_HIGH;
- } else {
- return NotificationManager.IMPORTANCE_UNSPECIFIED;
- }
- }
-
- private void bindToggles(final View importanceButtons, final int importance,
- final boolean nonBlockable) {
- // Enabled Switch
- mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
- mChannelEnabledSwitch.setChecked(importance != NotificationManager.IMPORTANCE_NONE);
- mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
-
- // Importance Buttons
- mMinImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.min_importance);
- mLowImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.low_importance);
- mDefaultImportanceButton =
- (RadioButton) importanceButtons.findViewById(R.id.default_importance);
- mHighImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.high_importance);
-
- // Set to current importance setting
- switch (importance) {
- case NotificationManager.IMPORTANCE_UNSPECIFIED:
- case NotificationManager.IMPORTANCE_NONE:
- break;
- case NotificationManager.IMPORTANCE_MIN:
- mMinImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_LOW:
- mLowImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_DEFAULT:
- mDefaultImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_HIGH:
- case NotificationManager.IMPORTANCE_MAX:
- mHighImportanceButton.setChecked(true);
- break;
- }
-
- // Callback when checked.
- mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
- resetFalsingCheck();
- updateImportanceGroup();
- });
- ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
- (buttonView, isChecked) -> { resetFalsingCheck(); });
- }
-
- private void updateImportanceGroup() {
- final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
- mImportanceGroup.setVisibility(disabled ? View.GONE : View.VISIBLE);
- mChannelDisabled.setVisibility(disabled ? View.VISIBLE : View.GONE);
- }
-
public void closeControls(int x, int y, boolean saveImportance) {
- if (saveImportance) {
- saveImportance();
- }
if (getWindowToken() == null) {
if (mListener != null) {
mListener.onGutsClosed(this);
}
return;
}
+ if (mGutsContent == null || !mGutsContent.handleCloseControls()) {
+ animateClose(x, y);
+ }
+ setExposed(false, mNeedsFalsingProtection);
+ if (mListener != null) {
+ mListener.onGutsClosed(this);
+ }
+ }
+
+ private void animateClose(int x, int y) {
if (x == -1 || y == -1) {
x = (getLeft() + getRight()) / 2;
y = (getTop() + getHeight() / 2);
@@ -391,10 +206,6 @@ public class NotificationGuts extends LinearLayout {
}
});
a.start();
- setExposed(false, mNeedsFalsingProtection);
- if (mListener != null) {
- mListener.onGutsClosed(this);
- }
}
public void setActualHeight(int actualHeight) {
@@ -439,4 +250,14 @@ public class NotificationGuts extends LinearLayout {
public boolean isExposed() {
return mExposed;
}
+
+ @Override
+ public void onInteraction(View view) {
+ resetFalsingCheck();
+ }
+
+ @Override
+ public void closeGuts(View view) {
+ closeControls(-1 /* x */, -1 /* y */, true /* notify */);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
new file mode 100644
index 000000000000..bdbc9b32cbce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -0,0 +1,320 @@
+package com.android.systemui.statusbar;
+
+/*
+ * 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
+ */
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.SeekBar;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
+import com.android.systemui.statusbar.NotificationGuts.OnSettingsClickListener;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+import java.util.Set;
+
+/**
+ * The guts of a notification revealed when performing a long press.
+ */
+public class NotificationInfo extends LinearLayout implements GutsContent {
+ private static final String TAG = "InfoGuts";
+
+ private INotificationManager mINotificationManager;
+ private int mStartingUserImportance;
+ private StatusBarNotification mStatusBarNotification;
+ private NotificationChannel mNotificationChannel;
+
+ private ImageView mAutoButton;
+ private TextView mImportanceSummary;
+ private TextView mImportanceTitle;
+ private boolean mAuto;
+
+ private View mImportanceGroup;
+ private View mChannelDisabled;
+ private Switch mChannelEnabledSwitch;
+ private RadioButton mMinImportanceButton;
+ private RadioButton mLowImportanceButton;
+ private RadioButton mDefaultImportanceButton;
+ private RadioButton mHighImportanceButton;
+
+ private GutsInteractionListener mGutsInteractionListener;
+
+ public NotificationInfo(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public interface OnSettingsClickListener {
+ void onClick(View v, int appUid);
+ }
+
+ public void bindNotification(final PackageManager pm,
+ final INotificationManager iNotificationManager,
+ final StatusBarNotification sbn, final NotificationChannel channel,
+ OnSettingsClickListener onSettingsClick,
+ OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
+ mINotificationManager = iNotificationManager;
+ mNotificationChannel = channel;
+ mStatusBarNotification = sbn;
+ mStartingUserImportance = channel.getImportance();
+
+ final String pkg = sbn.getPackageName();
+ int appUid = -1;
+ String appname = pkg;
+ Drawable pkgicon = null;
+ try {
+ final ApplicationInfo info = pm.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ appUid = info.uid;
+ appname = String.valueOf(pm.getApplicationLabel(info));
+ pkgicon = pm.getApplicationIcon(info);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // app is gone, just show package name and generic icon
+ pkgicon = pm.getDefaultActivityIcon();
+ }
+
+ // If this is the placeholder channel, don't use our channel-specific text.
+ String appNameText;
+ CharSequence channelNameText;
+ if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ appNameText = appname;
+ channelNameText = mContext.getString(R.string.notification_header_default_channel);
+ } else {
+ appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
+ channelNameText = channel.getName();
+ }
+ ((TextView) findViewById(R.id.pkgname)).setText(appNameText);
+ ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
+
+ // Settings button.
+ final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
+ if (appUid >= 0 && onSettingsClick != null) {
+ final int appUidF = appUid;
+ settingsButton.setOnClickListener(
+ (View view) -> {
+ onSettingsClick.onClick(view, appUidF);
+ });
+ settingsButton.setText(R.string.notification_more_settings);
+ } else {
+ settingsButton.setVisibility(View.GONE);
+ }
+
+ // Done button.
+ final TextView doneButton = (TextView) findViewById(R.id.done);
+ doneButton.setText(R.string.notification_done);
+ doneButton.setOnClickListener(onDoneClick);
+
+ boolean nonBlockable = false;
+ try {
+ final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+ nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
+ } catch (PackageManager.NameNotFoundException e) {
+ // unlikely.
+ }
+ if (nonBlockablePkgs != null) {
+ nonBlockable |= nonBlockablePkgs.contains(pkg);
+ }
+
+ final View importanceButtons = findViewById(R.id.importance_buttons);
+ bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
+
+ // Importance Text (hardcoded to 4 importance levels)
+ final ViewGroup importanceTextGroup = (ViewGroup) findViewById(
+ R.id.importance_buttons_text);
+ final int size = importanceTextGroup.getChildCount();
+ for (int i = 0; i < size; i++) {
+ int importanceNameResId = 0;
+ int importanceDescResId = 0;
+ switch (i) {
+ case 0:
+ importanceNameResId = R.string.high_importance;
+ importanceDescResId = R.string.notification_importance_high;
+ break;
+ case 1:
+ importanceNameResId = R.string.default_importance;
+ importanceDescResId = R.string.notification_importance_default;
+ break;
+ case 2:
+ importanceNameResId = R.string.low_importance;
+ importanceDescResId = R.string.notification_importance_low;
+ break;
+ case 3:
+ importanceNameResId = R.string.min_importance;
+ importanceDescResId = R.string.notification_importance_min;
+ break;
+ default:
+ Log.e(TAG, "Too many importance groups in this layout.");
+ break;
+ }
+ final ViewGroup importanceChildGroup = (ViewGroup) importanceTextGroup.getChildAt(i);
+ ((TextView) importanceChildGroup.getChildAt(0)).setText(importanceNameResId);
+ ((TextView) importanceChildGroup.getChildAt(1)).setText(importanceDescResId);
+ }
+
+ // Top-level importance group
+ mImportanceGroup = findViewById(R.id.importance);
+ mChannelDisabled = findViewById(R.id.channel_disabled);
+ updateImportanceGroup();
+ }
+
+ public boolean hasImportanceChanged() {
+ return mStartingUserImportance != getSelectedImportance();
+ }
+
+ public void saveImportance() {
+ int selectedImportance = getSelectedImportance();
+ if (selectedImportance == mStartingUserImportance) {
+ return;
+ }
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
+ selectedImportance - mStartingUserImportance);
+ mNotificationChannel.setImportance(selectedImportance);
+ try {
+ mINotificationManager.updateNotificationChannelForPackage(
+ mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
+ mNotificationChannel);
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
+ private int getSelectedImportance() {
+ if (!mChannelEnabledSwitch.isChecked()) {
+ return NotificationManager.IMPORTANCE_NONE;
+ } else if (mMinImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_MIN;
+ } else if (mLowImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_LOW;
+ } else if (mDefaultImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_DEFAULT;
+ } else if (mHighImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_HIGH;
+ } else {
+ return NotificationManager.IMPORTANCE_UNSPECIFIED;
+ }
+ }
+
+ private void bindToggles(final View importanceButtons, final int importance,
+ final boolean nonBlockable) {
+ // Enabled Switch
+ mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
+ mChannelEnabledSwitch.setChecked(importance != NotificationManager.IMPORTANCE_NONE);
+ mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
+
+ // Importance Buttons
+ mMinImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.min_importance);
+ mLowImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.low_importance);
+ mDefaultImportanceButton = (RadioButton) importanceButtons
+ .findViewById(R.id.default_importance);
+ mHighImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.high_importance);
+
+ // Set to current importance setting
+ switch (importance) {
+ case NotificationManager.IMPORTANCE_UNSPECIFIED:
+ case NotificationManager.IMPORTANCE_NONE:
+ break;
+ case NotificationManager.IMPORTANCE_MIN:
+ mMinImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_LOW:
+ mLowImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_DEFAULT:
+ mDefaultImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_HIGH:
+ case NotificationManager.IMPORTANCE_MAX:
+ mHighImportanceButton.setChecked(true);
+ break;
+ }
+
+ // Callback when checked.
+ mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ mGutsInteractionListener.onInteraction(NotificationInfo.this);
+ updateImportanceGroup();
+ });
+ ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
+ (buttonView, isChecked) -> {
+ mGutsInteractionListener.onInteraction(NotificationInfo.this);
+ });
+ }
+
+ private void updateImportanceGroup() {
+ final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
+ mImportanceGroup.setVisibility(disabled ? View.GONE : View.VISIBLE);
+ mChannelDisabled.setVisibility(disabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void closeControls() {
+ if (mGutsInteractionListener != null) {
+ mGutsInteractionListener.closeGuts(this);
+ }
+ }
+
+ @Override
+ public void setInteractionListener(GutsInteractionListener listener) {
+ mGutsInteractionListener = listener;
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public boolean handleCloseControls() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
new file mode 100644
index 000000000000..355022f9794c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.OnMenuClickListener;
+
+public class NotificationMenuRow extends FrameLayout
+ implements PluginListener<NotificationMenuRowProvider>, View.OnClickListener {
+
+ private static final int ICON_ALPHA_ANIM_DURATION = 200;
+
+ private ExpandableNotificationRow mParent;
+ private OnMenuClickListener mListener;
+ private NotificationMenuRowProvider mMenuProvider;
+ private ArrayList<MenuItem> mMenuItems = new ArrayList<>();
+
+ private ValueAnimator mFadeAnimator;
+ private boolean mMenuFadedIn = false;
+ private boolean mAnimating = false;
+ private boolean mOnLeft = true;
+ private boolean mDismissing = false;
+ private boolean mSnapping = false;
+ private boolean mIconsPlaced = false;
+
+ private int[] mIconLocation = new int[2];
+ private int[] mParentLocation = new int[2];
+
+ private float mHorizSpaceForIcon;
+ private int mVertSpaceForIcons;
+
+ private int mIconPadding;
+ private int mIconTint;
+
+ private float mAlpha = 0f;
+
+ public NotificationMenuRow(Context context) {
+ this(context, null);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs);
+ mMenuItems.addAll(getDefaultNotificationMenuItems());
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ Dependency.get(PluginManager.class).addPluginListener(
+ NotificationMenuRowProvider.ACTION, this,
+ NotificationMenuRowProvider.VERSION, false /* Allow multiple */);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ Dependency.get(PluginManager.class).removePluginListener(this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ final Resources res = getResources();
+ mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
+ mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
+ mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
+ mIconTint = res.getColor(R.color.notification_gear_color);
+ updateMenu(false /* notify */);
+ }
+
+ public static MenuItem getLongpressMenuItem(Context context) {
+ Resources res = context.getResources();
+ Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
+ String settingsDescription = res.getString(R.string.notification_menu_gear_description);
+ NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(context).inflate(
+ R.layout.notification_info, null, false);
+ MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
+ return settings;
+ }
+
+ public ArrayList<MenuItem> getDefaultNotificationMenuItems() {
+ ArrayList<MenuItem> items = new ArrayList<MenuItem>();
+ Resources res = getResources();
+
+ Drawable snoozeIcon = res.getDrawable(R.drawable.ic_snooze);
+ NotificationSnooze content = (NotificationSnooze) LayoutInflater.from(mContext)
+ .inflate(R.layout.notification_snooze, null, false);
+ String snoozeDescription = res.getString(R.string.notification_menu_snooze_description);
+ MenuItem snooze = new MenuItem(snoozeIcon, snoozeDescription, content);
+ items.add(snooze);
+
+ Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
+ String settingsDescription = res.getString(R.string.notification_menu_gear_description);
+ NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_info, null, false);
+ MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
+ items.add(settings);
+ return items;
+ }
+
+ private void updateMenu(boolean notify) {
+ removeAllViews();
+ mMenuItems.clear();
+ if (mMenuProvider != null) {
+ mMenuItems.addAll(mMenuProvider.getMenuItems(getContext()));
+ }
+ mMenuItems.addAll(getDefaultNotificationMenuItems());
+ for (int i = 0; i < mMenuItems.size(); i++) {
+ final View v = createMenuView(mMenuItems.get(i));
+ mMenuItems.get(i).menuView = v;
+ }
+ resetState(notify);
+ }
+
+ private View createMenuView(MenuItem item) {
+ AlphaOptimizedImageView iv = new AlphaOptimizedImageView(getContext());
+ addView(iv);
+ iv.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
+ iv.setImageDrawable(item.icon);
+ iv.setOnClickListener(this);
+ iv.setColorFilter(mIconTint);
+ iv.setAlpha(mAlpha);
+ FrameLayout.LayoutParams lp = (LayoutParams) iv.getLayoutParams();
+ lp.width = (int) mHorizSpaceForIcon;
+ lp.height = (int) mHorizSpaceForIcon;
+ return iv;
+ }
+
+ public void resetState(boolean notify) {
+ setMenuAlpha(0f);
+ mIconsPlaced = false;
+ mMenuFadedIn = false;
+ mAnimating = false;
+ mSnapping = false;
+ mDismissing = false;
+ setMenuLocation(mOnLeft ? 1 : -1 /* on left */);
+ if (mListener != null && notify) {
+ mListener.onMenuReset(mParent);
+ }
+ }
+
+ public void setMenuClickListener(OnMenuClickListener listener) {
+ mListener = listener;
+ }
+
+ public void setNotificationRowParent(ExpandableNotificationRow parent) {
+ mParent = parent;
+ setMenuLocation(mOnLeft ? 1 : -1);
+ }
+
+ public void setAppName(String appName) {
+ Resources res = getResources();
+ final int count = mMenuItems.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem item = mMenuItems.get(i);
+ String description = String.format(
+ res.getString(R.string.notification_menu_accessibility),
+ appName, item.menuDescription);
+ item.menuView.setContentDescription(description);
+ }
+ }
+
+ public ExpandableNotificationRow getNotificationParent() {
+ return mParent;
+ }
+
+ public void setMenuAlpha(float alpha) {
+ mAlpha = alpha;
+ if (alpha == 0) {
+ mMenuFadedIn = false; // Can fade in again once it's gone.
+ setVisibility(View.INVISIBLE);
+ } else {
+ setVisibility(View.VISIBLE);
+ }
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ getChildAt(i).setAlpha(mAlpha);
+ }
+ }
+
+ /**
+ * Returns whether the menu is displayed on the left side of the view or not.
+ */
+ public boolean isMenuOnLeft() {
+ return mOnLeft;
+ }
+
+ /**
+ * Returns the horizontal space in pixels required to display the menu.
+ */
+ public float getSpaceForMenu() {
+ return mHorizSpaceForIcon * getChildCount();
+ }
+
+ /**
+ * Indicates whether the menu is visible at 1 alpha. Does not indicate if entire view is
+ * visible.
+ */
+ public boolean isVisible() {
+ return mAlpha > 0;
+ }
+
+ public void cancelFadeAnimator() {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ }
+
+ public void updateMenuAlpha(final float transX, final float size) {
+ if (mAnimating || !mMenuFadedIn) {
+ // Don't adjust when animating, or if the menu hasn't been shown yet.
+ return;
+ }
+
+ final float fadeThreshold = size * 0.3f;
+ final float absTrans = Math.abs(transX);
+ float desiredAlpha = 0;
+
+ if (absTrans == 0) {
+ desiredAlpha = 0;
+ } else if (absTrans <= fadeThreshold) {
+ desiredAlpha = 1;
+ } else {
+ desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
+ }
+ setMenuAlpha(desiredAlpha);
+ }
+
+ public void fadeInMenu(final boolean fromLeft, final float transX,
+ final float notiThreshold) {
+ if (mDismissing || mAnimating) {
+ return;
+ }
+ if (isMenuLocationChange(transX)) {
+ setMenuAlpha(0f);
+ }
+ setMenuLocation((int) transX);
+ mFadeAnimator = ValueAnimator.ofFloat(mAlpha, 1);
+ mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float absTrans = Math.abs(transX);
+
+ boolean pastGear = (fromLeft && transX <= notiThreshold)
+ || (!fromLeft && absTrans <= notiThreshold);
+ if (pastGear && !mMenuFadedIn) {
+ setMenuAlpha((float) animation.getAnimatedValue());
+ }
+ }
+ });
+ mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimating = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // TODO should animate back to 0f from current alpha
+ setMenuAlpha(0f);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimating = false;
+ mMenuFadedIn = mAlpha == 1;
+ }
+ });
+ mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mFadeAnimator.setDuration(ICON_ALPHA_ANIM_DURATION);
+ mFadeAnimator.start();
+ }
+
+ public void updateVerticalLocation() {
+ if (mParent == null || mMenuItems.size() == 0) {
+ return;
+ }
+ int parentHeight = mParent.getCollapsedHeight();
+ float translationY;
+ if (parentHeight < mVertSpaceForIcons) {
+ translationY = (parentHeight / 2) - (mHorizSpaceForIcon / 2);
+ } else {
+ translationY = (mVertSpaceForIcons - mHorizSpaceForIcon) / 2;
+ }
+ setTranslationY(translationY);
+ }
+
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ mIconsPlaced = false;
+ setMenuLocation(mOnLeft ? 1 : -1);
+ }
+
+ public void setMenuLocation(int translation) {
+ boolean onLeft = translation > 0;
+ if ((mIconsPlaced && onLeft == mOnLeft) || mSnapping || mParent == null) {
+ // Do nothing
+ return;
+ }
+ final boolean isRtl = mParent.isLayoutRtl();
+ final int count = getChildCount();
+ final int width = getWidth();
+ for (int i = 0; i < count; i++) {
+ final View v = getChildAt(i);
+ final float left = isRtl
+ ? -(width - mHorizSpaceForIcon * (i + 1))
+ : i * mHorizSpaceForIcon;
+ final float right = isRtl
+ ? -i * mHorizSpaceForIcon
+ : width - (mHorizSpaceForIcon * (i + 1));
+ v.setTranslationX(onLeft ? left : right);
+ }
+ mOnLeft = onLeft;
+ mIconsPlaced = true;
+ }
+
+ public boolean isMenuLocationChange(float translation) {
+ boolean onLeft = translation > mIconPadding;
+ boolean onRight = translation < -mIconPadding;
+ if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
+ return true;
+ }
+ return false;
+ }
+
+ public void setDismissing() {
+ mDismissing = true;
+ }
+
+ public void setSnapping(boolean snapping) {
+ mSnapping = snapping;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) {
+ // Nothing to do
+ return;
+ }
+ v.getLocationOnScreen(mIconLocation);
+ mParent.getLocationOnScreen(mParentLocation);
+ final int centerX = (int) (mHorizSpaceForIcon / 2);
+ final int centerY = (int) (v.getTranslationY() * 2 + v.getHeight()) / 2;
+ final int x = mIconLocation[0] - mParentLocation[0] + centerX;
+ final int y = mIconLocation[1] - mParentLocation[1] + centerY;
+ final int index = indexOfChild(v);
+ mListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ }
+
+ @Override
+ public void onPluginConnected(NotificationMenuRowProvider plugin, Context pluginContext) {
+ mMenuProvider = plugin;
+ updateMenu(false /* notify */);
+ }
+
+ @Override
+ public void onPluginDisconnected(NotificationMenuRowProvider plugin) {
+ mMenuProvider = null;
+ updateMenu(false /* notify */);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
deleted file mode 100644
index 431564723992..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-
-public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
-
- private static final int GEAR_ALPHA_ANIM_DURATION = 200;
-
- public interface SettingsIconRowListener {
- /**
- * Called when the gear behind a notification is touched.
- */
- public void onGearTouched(ExpandableNotificationRow row, int x, int y);
-
- /**
- * Called when a notification is slid back over the gear.
- */
- public void onSettingsIconRowReset(ExpandableNotificationRow row);
- }
-
- private ExpandableNotificationRow mParent;
- private AlphaOptimizedImageView mGearIcon;
- private float mHorizSpaceForGear;
- private SettingsIconRowListener mListener;
-
- private ValueAnimator mFadeAnimator;
- private boolean mSettingsFadedIn = false;
- private boolean mAnimating = false;
- private boolean mOnLeft = true;
- private boolean mDismissing = false;
- private boolean mSnapping = false;
- private boolean mIconPlaced = false;
-
- private int[] mGearLocation = new int[2];
- private int[] mParentLocation = new int[2];
- private int mVertSpaceForGear;
-
- public NotificationSettingsIconRow(Context context) {
- this(context, null);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mGearIcon = (AlphaOptimizedImageView) findViewById(R.id.gear_icon);
- mGearIcon.setOnClickListener(this);
- setOnClickListener(this);
- mHorizSpaceForGear =
- getResources().getDimensionPixelOffset(R.dimen.notification_gear_width);
- mVertSpaceForGear = getResources().getDimensionPixelOffset(R.dimen.notification_min_height);
- resetState();
- }
-
- public void resetState() {
- setGearAlpha(0f);
- mIconPlaced = false;
- mSettingsFadedIn = false;
- mAnimating = false;
- mSnapping = false;
- mDismissing = false;
- setIconLocation(true /* on left */);
- if (mListener != null) {
- mListener.onSettingsIconRowReset(mParent);
- }
- }
-
- public void setGearListener(SettingsIconRowListener listener) {
- mListener = listener;
- }
-
- public void setNotificationRowParent(ExpandableNotificationRow parent) {
- mParent = parent;
- setIconLocation(mOnLeft);
- }
-
- public void setAppName(String appName) {
- Resources res = getResources();
- String description = String.format(res.getString(R.string.notification_gear_accessibility),
- appName);
- mGearIcon.setContentDescription(description);
- }
-
- public ExpandableNotificationRow getNotificationParent() {
- return mParent;
- }
-
- public void setGearAlpha(float alpha) {
- if (alpha == 0) {
- mSettingsFadedIn = false; // Can fade in again once it's gone.
- setVisibility(View.INVISIBLE);
- } else {
- setVisibility(View.VISIBLE);
- }
- mGearIcon.setAlpha(alpha);
- }
-
- /**
- * Returns whether the icon is on the left side of the view or not.
- */
- public boolean isIconOnLeft() {
- return mOnLeft;
- }
-
- /**
- * Returns the horizontal space in pixels required to display the gear behind a notification.
- */
- public float getSpaceForGear() {
- return mHorizSpaceForGear;
- }
-
- /**
- * Indicates whether the gear is visible at 1 alpha. Does not indicate
- * if entire view is visible.
- */
- public boolean isVisible() {
- return mGearIcon.getAlpha() > 0;
- }
-
- public void cancelFadeAnimator() {
- if (mFadeAnimator != null) {
- mFadeAnimator.cancel();
- }
- }
-
- public void updateSettingsIcons(final float transX, final float size) {
- if (mAnimating || !mSettingsFadedIn) {
- // Don't adjust when animating, or if the gear hasn't been shown yet.
- return;
- }
-
- final float fadeThreshold = size * 0.3f;
- final float absTrans = Math.abs(transX);
- float desiredAlpha = 0;
-
- if (absTrans == 0) {
- desiredAlpha = 0;
- } else if (absTrans <= fadeThreshold) {
- desiredAlpha = 1;
- } else {
- desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
- }
- setGearAlpha(desiredAlpha);
- }
-
- public void fadeInSettings(final boolean fromLeft, final float transX,
- final float notiThreshold) {
- if (mDismissing || mAnimating) {
- return;
- }
- if (isIconLocationChange(transX)) {
- setGearAlpha(0f);
- }
- setIconLocation(transX > 0 /* fromLeft */);
- mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
- mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float absTrans = Math.abs(transX);
-
- boolean pastGear = (fromLeft && transX <= notiThreshold)
- || (!fromLeft && absTrans <= notiThreshold);
- if (pastGear && !mSettingsFadedIn) {
- setGearAlpha((float) animation.getAnimatedValue());
- }
- }
- });
- mFadeAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mAnimating = true;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- // TODO should animate back to 0f from current alpha
- mGearIcon.setAlpha(0f);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- mSettingsFadedIn = mGearIcon.getAlpha() == 1;
- }
- });
- mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
- mFadeAnimator.setDuration(GEAR_ALPHA_ANIM_DURATION);
- mFadeAnimator.start();
- }
-
- public void updateVerticalLocation() {
- if (mParent == null) {
- return;
- }
- int parentHeight = mParent.getCollapsedHeight();
- if (parentHeight < mVertSpaceForGear) {
- mGearIcon.setTranslationY((parentHeight / 2) - (mGearIcon.getHeight() / 2));
- } else {
- mGearIcon.setTranslationY((mVertSpaceForGear - mGearIcon.getHeight()) / 2);
- }
- }
-
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- setIconLocation(mOnLeft);
- }
-
- public void setIconLocation(boolean onLeft) {
- if ((mIconPlaced && onLeft == mOnLeft) || mSnapping || mParent == null
- || mGearIcon.getWidth() == 0) {
- // Do nothing
- return;
- }
- final boolean isRtl = mParent.isLayoutRtl();
- final float left = isRtl
- ? -(mParent.getWidth() - mHorizSpaceForGear)
- : 0;
- final float right = isRtl
- ? 0
- : mParent.getWidth() - mHorizSpaceForGear;
- final float centerX = ((mHorizSpaceForGear - mGearIcon.getWidth()) / 2);
- setTranslationX(onLeft ? left + centerX : right + centerX);
- mOnLeft = onLeft;
- mIconPlaced = true;
- }
-
- public boolean isIconLocationChange(float translation) {
- boolean onLeft = translation > mGearIcon.getPaddingStart();
- boolean onRight = translation < -mGearIcon.getPaddingStart();
- if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
- return true;
- }
- return false;
- }
-
- public void setDismissing() {
- mDismissing = true;
- }
-
- public void setSnapping(boolean snapping) {
- mSnapping = snapping;
- }
-
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.gear_icon) {
- if (mListener != null) {
- mGearIcon.getLocationOnScreen(mGearLocation);
- mParent.getLocationOnScreen(mParentLocation);
-
- final int centerX = (int) (mHorizSpaceForGear / 2);
- final int centerY =
- (int) (mGearIcon.getTranslationY() * 2 + mGearIcon.getHeight())/ 2;
- final int x = mGearLocation[0] - mParentLocation[0] + centerX;
- final int y = mGearLocation[1] - mParentLocation[1] + centerY;
- mListener.onGearTouched(mParent, x, y);
- }
- } else {
- // Do nothing when the background is touched.
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index e8e9d4ebec6f..2425076a4442 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -68,6 +68,7 @@ public class NotificationShelf extends ActivatableNotificationView {
private float mMaxShelfEnd;
private int mRelativeOffset;
private boolean mInteractive;
+ private boolean mAnimationsEnabled = true;
public NotificationShelf(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -388,12 +389,13 @@ public class NotificationShelf extends ActivatableNotificationView {
View rowIcon = row.getNotificationIcon();
float notificationIconPosition = row.getTranslationY() + row.getContentTranslation();
- if (usingLinearInterpolation) {
+ boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
+ if (usingLinearInterpolation && !stayingInShelf) {
// If we interpolate from the notification position, this might lead to a slightly
// odd interpolation, since the notification position changes as well. Let's interpolate
// from a fixed distance. We can only do this if we don't animate and the icon is
// always in the interpolated positon.
- notificationIconPosition = mMaxShelfEnd - getIntrinsicHeight() - iconTransformDistance;
+ notificationIconPosition = getTranslationY() - iconTransformDistance;
}
float notificationIconSize = 0.0f;
int iconTopPadding;
@@ -426,7 +428,7 @@ public class NotificationShelf extends ActivatableNotificationView {
iconState.hidden = transitionAmount == 0.0f;
iconState.alpha = alpha;
iconState.yTranslation = iconYTranslation;
- if (row.isInShelf() && !row.isTransformingIntoShelf()) {
+ if (stayingInShelf) {
iconState.iconAppearAmount = 1.0f;
iconState.alpha = 1.0f;
iconState.scaleX = 1.0f;
@@ -573,6 +575,15 @@ public class NotificationShelf extends ActivatableNotificationView {
mMaxShelfEnd = maxShelfEnd;
}
+ public void setAnimationsEnabled(boolean enabled) {
+ mAnimationsEnabled = enabled;
+ mCollapsedIcons.setAnimationsEnabled(enabled);
+ if (!enabled) {
+ // we need to wait with enabling the animations until the first frame has passed
+ mShelfIcons.setAnimationsEnabled(false);
+ }
+ }
+
private class ShelfState extends ExpandableViewState {
private float openedAmount;
private boolean hasItemsInStableShelf;
@@ -585,6 +596,7 @@ public class NotificationShelf extends ActivatableNotificationView {
setOpenedAmount(openedAmount);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
+ mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
}
@Override
@@ -594,6 +606,7 @@ public class NotificationShelf extends ActivatableNotificationView {
setOpenedAmount(openedAmount);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
+ mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
new file mode 100644
index 000000000000..1992b6c9ccdd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -0,0 +1,211 @@
+package com.android.systemui.statusbar;
+/*
+ * 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
+ */
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioGroup;
+import android.widget.RadioGroup.OnCheckedChangeListener;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.android.systemui.R;
+
+public class NotificationSnooze extends LinearLayout
+ implements NotificationMenuRowProvider.SnoozeGutsContent, View.OnClickListener {
+
+ private static final int MAX_ASSISTANT_SUGGESTIONS = 2;
+ private GutsInteractionListener mGutsInteractionListener;
+ private SnoozeListener mSnoozeListener;
+ private StatusBarNotification mSbn;
+
+ private TextView mSelectedOptionText;
+ private TextView mUndoButton;
+ private ViewGroup mSnoozeOptionView;
+ private List<SnoozeOption> mSnoozeOptions;
+
+ private SnoozeOption mSelectedOption;
+
+ public NotificationSnooze(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ // Create the different options based on list
+ mSnoozeOptions = getDefaultSnoozeOptions();
+ createOptionViews();
+
+ // Snackbar
+ mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default);
+ mSelectedOptionText.setOnClickListener(this);
+ mUndoButton = (TextView) findViewById(R.id.undo);
+ mUndoButton.setOnClickListener(this);
+
+ // Default to first option in list
+ setSelected(mSnoozeOptions.get(0));
+ }
+
+ public void setSnoozeOptions(final List<SnoozeCriterion> snoozeList) {
+ if (snoozeList == null) {
+ return;
+ }
+ mSnoozeOptions.clear();
+ mSnoozeOptions = getDefaultSnoozeOptions();
+ final int count = Math.min(MAX_ASSISTANT_SUGGESTIONS, snoozeList.size());
+ for (int i = 0; i < count; i++) {
+ SnoozeCriterion sc = snoozeList.get(i);
+ mSnoozeOptions.add(new SnoozeOption(sc, 0, sc.getExplanation(), sc.getConfirmation()));
+ }
+ createOptionViews();
+ }
+
+ private ArrayList<SnoozeOption> getDefaultSnoozeOptions() {
+ ArrayList<SnoozeOption> options = new ArrayList<>();
+ options.add(createOption(R.string.snooze_option_15_min, 15));
+ options.add(createOption(R.string.snooze_option_30_min, 30));
+ options.add(createOption(R.string.snooze_option_1_hour, 60));
+ return options;
+ }
+
+ private SnoozeOption createOption(int descriptionResId, int minutes) {
+ Resources res = getResources();
+ String resultText = String.format(
+ res.getString(R.string.snoozed_for_time), res.getString(descriptionResId));
+ return new SnoozeOption(null, minutes, res.getString(descriptionResId), resultText);
+ }
+
+ private void createOptionViews() {
+ mSnoozeOptionView = (ViewGroup) findViewById(R.id.snooze_options);
+ mSnoozeOptionView.removeAllViews();
+ mSnoozeOptionView.setVisibility(View.GONE);
+ final Resources res = getResources();
+ final int textSize = res.getDimensionPixelSize(R.dimen.snooze_option_text_size);
+ final int p = res.getDimensionPixelSize(R.dimen.snooze_option_padding);
+
+ // Add all the options
+ for (int i = 0; i < mSnoozeOptions.size(); i++) {
+ SnoozeOption option = mSnoozeOptions.get(i);
+ TextView tv = new TextView(getContext());
+ tv.setTextColor(Color.WHITE);
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+ tv.setPadding(p, p, p, p);
+ mSnoozeOptionView.addView(tv);
+ tv.setText(option.description);
+ tv.setTag(option);
+ tv.setOnClickListener(this);
+ }
+
+ // Add the undo option as final item
+ TextView tv = new TextView(getContext());
+ tv.setTextColor(Color.WHITE);
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+ tv.setPadding(p, p, p, p);
+ mSnoozeOptionView.addView(tv);
+ tv.setText(R.string.snooze_option_dont_snooze);
+ tv.setOnClickListener(this);
+ }
+
+ private void showSnoozeOptions(boolean show) {
+ mSelectedOptionText.setVisibility(show ? View.GONE : View.VISIBLE);
+ mUndoButton.setVisibility(show ? View.GONE : View.VISIBLE);
+ mSnoozeOptionView.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
+ private void setSelected(SnoozeOption option) {
+ mSelectedOption = option;
+ mSelectedOptionText.setText(option.confirmation);
+ showSnoozeOptions(false);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mGutsInteractionListener != null) {
+ mGutsInteractionListener.onInteraction(this);
+ }
+ final int id = v.getId();
+ final SnoozeOption tag = (SnoozeOption) v.getTag();
+ if (tag != null) {
+ setSelected(tag);
+ } else if (id == R.id.snooze_option_default) {
+ // Show more snooze options
+ showSnoozeOptions(true);
+ } else {
+ undoSnooze();
+ }
+ }
+
+ private void undoSnooze() {
+ mSelectedOption = null;
+ mGutsInteractionListener.closeGuts(this);
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public void setStatusBarNotification(StatusBarNotification sbn) {
+ mSbn = sbn;
+ }
+
+ @Override
+ public void setInteractionListener(GutsInteractionListener listener) {
+ mGutsInteractionListener = listener;
+ }
+
+ @Override
+ public void setSnoozeListener(SnoozeListener listener) {
+ mSnoozeListener = listener;
+ }
+
+ @Override
+ public boolean handleCloseControls() {
+ // When snooze is closed (i.e. there was interaction outside of the notification)
+ // then we commit the snooze action.
+ if (mSnoozeListener != null && mSelectedOption != null) {
+ mSnoozeListener.snoozeNotification(mSbn, mSelectedOption);
+ return true;
+ } else {
+ // Reset the view once it's closed
+ setSelected(mSnoozeOptions.get(0));
+ showSnoozeOptions(false);
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index dba7130793ca..f9d0cd61f037 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -29,6 +30,7 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.R;
/**
* A view which can draw a scrim
@@ -73,6 +75,14 @@ public class ScrimView extends View
public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrimView);
+
+ try {
+ mScrimColor = ta.getColor(R.styleable.ScrimView_scrimColor, Color.BLACK);
+ } finally {
+ ta.recycle();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 1128101f142b..45eb5df43a06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -16,15 +16,18 @@
package com.android.systemui.statusbar;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.telephony.SubscriptionInfo;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -74,8 +77,10 @@ public class SignalClusterView
private boolean mEthernetVisible = false;
private int mEthernetIconId = 0;
private int mLastEthernetIconId = -1;
+ private int mWifiBadgeId = -1;
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
+ private int mLastWifiBadgeId = -1;
private int mLastWifiStrengthId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
@@ -215,7 +220,7 @@ public class SignalClusterView
int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
- TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
apply();
applyIconTint();
@@ -226,7 +231,7 @@ public class SignalClusterView
@Override
protected void onDetachedFromWindow() {
mMobileSignalGroup.removeAllViews();
- TunerService.get(mContext).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
mSecurityController.removeCallback(this);
mNetworkController.removeCallback(this);
@@ -259,6 +264,7 @@ public class SignalClusterView
boolean activityIn, boolean activityOut, String description) {
mWifiVisible = statusIcon.visible && !mBlockWifi;
mWifiStrengthId = statusIcon.icon;
+ mWifiBadgeId = statusIcon.iconOverlay;
mWifiDescription = statusIcon.contentDescription;
apply();
@@ -267,7 +273,7 @@ public class SignalClusterView
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
+ String description, boolean isWide, int subId, boolean roaming) {
PhoneState state = getState(subId);
if (state == null) {
return;
@@ -278,6 +284,7 @@ public class SignalClusterView
state.mMobileDescription = statusIcon.contentDescription;
state.mMobileTypeDescription = typeContentDescription;
state.mIsMobileTypeIconWide = statusType != 0 && isWide;
+ state.mRoaming = roaming;
apply();
}
@@ -399,6 +406,7 @@ public class SignalClusterView
mWifi.setImageDrawable(null);
mWifiDark.setImageDrawable(null);
mLastWifiStrengthId = -1;
+ mLastWifiBadgeId = -1;
}
for (PhoneState state : mPhoneStates) {
@@ -464,10 +472,16 @@ public class SignalClusterView
(mEthernetVisible ? "VISIBLE" : "GONE")));
if (mWifiVisible) {
- if (mWifiStrengthId != mLastWifiStrengthId) {
- setIconForView(mWifi, mWifiStrengthId);
- setIconForView(mWifiDark, mWifiStrengthId);
+ if (mWifiStrengthId != mLastWifiStrengthId || mWifiBadgeId != mLastWifiBadgeId) {
+ if (mWifiBadgeId == -1) {
+ setIconForView(mWifi, mWifiStrengthId);
+ setIconForView(mWifiDark, mWifiStrengthId);
+ } else {
+ setBadgedWifiIconForView(mWifi, mWifiStrengthId, mWifiBadgeId);
+ setBadgedWifiIconForView(mWifiDark, mWifiStrengthId, mWifiBadgeId);
+ }
mLastWifiStrengthId = mWifiStrengthId;
+ mLastWifiBadgeId = mWifiBadgeId;
}
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
@@ -529,6 +543,10 @@ public class SignalClusterView
// Using the imageView's context to retrieve the Drawable so that theme is preserved.
Drawable icon = imageView.getContext().getDrawable(iconId);
+ setScaledIcon(imageView, icon);
+ }
+
+ private void setScaledIcon(ImageView imageView, Drawable icon) {
if (mIconScaleFactor == 1.f) {
imageView.setImageDrawable(icon);
} else {
@@ -536,6 +554,33 @@ public class SignalClusterView
}
}
+ /**
+ * Creates and sets a LayerDrawable from the given ids on the given view.
+ *
+ * <p>This method will also scale the icon by {@link #mIconScaleFactor} if appropriate.
+ */
+ private void setBadgedWifiIconForView(ImageView imageView, @DrawableRes int wifiPieId,
+ @DrawableRes int badgeId) {
+ // Using the imageView's context to retrieve the Drawable so that theme is preserved.;
+ LayerDrawable icon = new LayerDrawable(new Drawable[] {
+ imageView.getContext().getDrawable(wifiPieId),
+ imageView.getContext().getDrawable(badgeId)});
+
+ // The LayerDrawable shares an underlying state so we must mutate the object to change the
+ // color between the light and dark themes.
+ icon.mutate().setTint(getColorAttr(imageView.getContext(), R.attr.singleToneColor));
+
+ setScaledIcon(imageView, icon);
+ }
+
+ /** Returns the given color attribute value, or white if not defined. */
+ @ColorInt private static int getColorAttr(Context context, int attr) {
+ TypedArray ta = context.obtainStyledAttributes(new int[] {attr});
+ @ColorInt int colorAccent = ta.getColor(0, Color.WHITE);
+ ta.recycle();
+ return colorAccent;
+ }
+
public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
|| !mTintArea.equals(tintArea);
@@ -587,7 +632,8 @@ public class SignalClusterView
private String mMobileDescription, mMobileTypeDescription;
private ViewGroup mMobileGroup;
- private ImageView mMobile, mMobileDark, mMobileType;
+ private ImageView mMobile, mMobileDark, mMobileType, mMobileRoaming;
+ public boolean mRoaming;
public PhoneState(int subId, Context context) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -601,6 +647,7 @@ public class SignalClusterView
mMobile = (ImageView) root.findViewById(R.id.mobile_signal);
mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark);
mMobileType = (ImageView) root.findViewById(R.id.mobile_type);
+ mMobileRoaming = (ImageView) root.findViewById(R.id.mobile_roaming);
}
public boolean apply(boolean isSecondaryIcon) {
@@ -636,6 +683,7 @@ public class SignalClusterView
(mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
+ mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
return mMobileVisible;
}
@@ -695,6 +743,8 @@ public class SignalClusterView
StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
mMobile, mMobileDark);
setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
+ setTint(mMobileRoaming, StatusBarIconController.getTint(tintArea, mMobileRoaming,
+ tint));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 399b0d293ac2..6283148c84f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -256,9 +256,16 @@ public class StatusBarIconView extends AnimatedImageView {
if (mIcon == null) {
return false;
}
- Drawable drawable = getIcon(mIcon);
+ Drawable drawable;
+ try {
+ drawable = getIcon(mIcon);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
+ return false;
+ }
+
if (drawable == null) {
- Log.w(TAG, "No icon for slot " + mSlot);
+ Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
return false;
}
if (withClear) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
index dd7c4c7a6a03..063252f08f36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
@@ -22,7 +22,7 @@ import com.android.systemui.statusbar.notification.TransformState;
* A view that can be transformed to and from.
*/
public interface TransformableView {
- int TRANSFORMING_VIEW_HEADER = 0;
+ int TRANSFORMING_VIEW_ICON = 0;
int TRANSFORMING_VIEW_TITLE = 1;
int TRANSFORMING_VIEW_TEXT = 2;
int TRANSFORMING_VIEW_IMAGE = 3;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index cd6c31f370d3..1c89e32a02bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -23,6 +23,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Interpolator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -298,5 +299,14 @@ public class ViewTransformationHelper implements TransformableView {
TransformState otherState) {
return false;
}
+
+ /**
+ * Get a custom interpolator for this animation
+ * @param interpolationType the type of the interpolation, i.e TranslationX / TranslationY
+ * @param isFrom true if this transformation from the other view
+ */
+ public Interpolator getCustomInterpolator(int interpolationType, boolean isFrom) {
+ return null;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 3bbda4be9fd1..7e08d5605f40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -24,24 +24,22 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v4.util.SimpleArrayMap;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.LinearLayout;
-
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
import java.net.URISyntaxException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
* A controller to populate data for CarNavigationBarView and handle user interactions.
- * <p/>
- * Each button inside the navigation bar is defined by data in arrays_car.xml. OEMs can customize
- * the navigation buttons by updating arrays_car.xml appropriately in an overlay.
+ *
+ * <p>Each button inside the navigation bar is defined by data in arrays_car.xml. OEMs can
+ * customize the navigation buttons by updating arrays_car.xml appropriately in an overlay.
*/
class CarNavigationBarController {
private static final String TAG = "CarNavBarController";
@@ -51,48 +49,49 @@ class CarNavigationBarController {
private static final String EXTRA_FACET_ID = "filter_id";
private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
- // Each facet of the navigation bar maps to a set of package names or categories defined in
- // arrays_car.xml. Package names for a given facet are delimited by ";"
- private static final String FACET_FILTER_DEMILITER = ";";
+ /**
+ * Each facet of the navigation bar maps to a set of package names or categories defined in
+ * arrays_car.xml. Package names for a given facet are delimited by ";".
+ */
+ private static final String FACET_FILTER_DELIMITER = ";";
+
+ private final Context mContext;
+ private final CarNavigationBarView mNavBar;
+ private final CarStatusBar mStatusBar;
- private Context mContext;
- private CarNavigationBarView mNavBar;
- private CarStatusBar mStatusBar;
+ /**
+ * Set of categories each facet will filter on.
+ */
+ private final List<String[]> mFacetCategories = new ArrayList<>();
- // Set of categories each facet will filter on.
- private List<String[]> mFacetCategories = new ArrayList<String[]>();
- // Set of package names each facet will filter on.
- private List<String[]> mFacetPackages = new ArrayList<String[]>();
+ /**
+ * Set of package names each facet will filter on.
+ */
+ private final List<String[]> mFacetPackages = new ArrayList<>();
- private SimpleArrayMap<String, Integer> mFacetCategoryMap
- = new SimpleArrayMap<String, Integer>();
- private SimpleArrayMap<String, Integer> mFacetPackageMap
- = new SimpleArrayMap<String, Integer>();
+ private final SimpleArrayMap<String, Integer> mFacetCategoryMap = new SimpleArrayMap<>();
+ private final SimpleArrayMap<String, Integer> mFacetPackageMap = new SimpleArrayMap<>();
- private List<Intent> mIntents;
- private List<Intent> mLongPressIntents;
+ private final List<CarNavigationButton> mNavButtons = new ArrayList<>();
- private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
+ private final SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
private int mCurrentFacetIndex;
- private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
-
private Intent mPersistentTaskIntent;
- public CarNavigationBarController(Context context,
- CarNavigationBarView navBar,
- CarStatusBar activityStarter) {
+ public CarNavigationBarController(Context context, CarNavigationBarView navBar,
+ CarStatusBar activityStarter) {
mContext = context;
mNavBar = navBar;
mStatusBar = activityStarter;
bind();
if (context.getResources().getBoolean(R.bool.config_enablePersistentDockedActivity)) {
- setupPersistentDockedTask(context);
+ setupPersistentDockedTask();
}
}
- private void setupPersistentDockedTask(Context context) {
+ private void setupPersistentDockedTask() {
try {
mPersistentTaskIntent = Intent.parseUri(
mContext.getString(R.string.config_persistentDockedActivityIntentUri),
@@ -137,64 +136,85 @@ class CarNavigationBarController {
}
}
+ /**
+ * Iterates through the items in arrays_car.xml and sets up the facet bar buttons to
+ * perform the task in that configuration file when clicked or long-pressed.
+ */
private void bind() {
- // Read up arrays_car.xml and populate the navigation bar here.
- Resources r = mContext.getResources();
- TypedArray icons = r.obtainTypedArray(R.array.car_facet_icons);
- TypedArray intents = r.obtainTypedArray(R.array.car_facet_intent_uris);
- TypedArray longpressIntents =
- r.obtainTypedArray(R.array.car_facet_longpress_intent_uris);
- TypedArray facetPackageNames = r.obtainTypedArray(R.array.car_facet_package_filters);
-
- TypedArray facetCategories = r.obtainTypedArray(R.array.car_facet_category_filters);
-
- if (icons.length() != intents.length()
- || icons.length() != longpressIntents.length()
- || icons.length() != facetPackageNames.length()
- || icons.length() != facetCategories.length()) {
- throw new RuntimeException("car_facet array lengths do not match");
- }
+ Resources res = mContext.getResources();
- mIntents = createEmptyIntentList(icons.length());
- mLongPressIntents = createEmptyIntentList(icons.length());
+ TypedArray icons = res.obtainTypedArray(R.array.car_facet_icons);
+ TypedArray intents = res.obtainTypedArray(R.array.car_facet_intent_uris);
+ TypedArray longPressIntents = res.obtainTypedArray(R.array.car_facet_longpress_intent_uris);
+ TypedArray facetPackageNames = res.obtainTypedArray(R.array.car_facet_package_filters);
+ TypedArray facetCategories = res.obtainTypedArray(R.array.car_facet_category_filters);
- for (int i = 0; i < icons.length(); i++) {
- Drawable icon = icons.getDrawable(i);
- try {
- mIntents.set(i,
- Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
+ try {
+ if (icons.length() != intents.length()
+ || icons.length() != longPressIntents.length()
+ || icons.length() != facetPackageNames.length()
+ || icons.length() != facetCategories.length()) {
+ throw new RuntimeException("car_facet array lengths do not match");
+ }
- String longpressUri = longpressIntents.getString(i);
- boolean hasLongpress = !longpressUri.isEmpty();
- if (hasLongpress) {
- mLongPressIntents.set(i,
- Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
- }
+ for (int i = 0, size = icons.length(); i < size; i++) {
+ Drawable icon = icons.getDrawable(i);
+ CarNavigationButton button = createNavButton(icon);
+ initClickListeners(button, i, intents.getString(i), longPressIntents.getString(i));
- CarNavigationButton button = createNavButton(icon, i, hasLongpress);
mNavButtons.add(button);
- mNavBar.addButton(button,
- createNavButton(icon, i, hasLongpress) /* lightsOutButton */);
-
- initFacetFilterMaps(i,
- facetPackageNames.getString(i).split(FACET_FILTER_DEMILITER),
- facetCategories.getString(i).split(FACET_FILTER_DEMILITER));
- mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
- } catch (URISyntaxException e) {
- throw new RuntimeException("Malformed intent uri", e);
+ mNavBar.addButton(button, createNavButton(icon) /* lightsOutButton */);
+
+ initFacetFilterMaps(i, facetPackageNames.getString(i).split(FACET_FILTER_DELIMITER),
+ facetCategories.getString(i).split(FACET_FILTER_DELIMITER));
+ mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
+ }
+ } finally {
+ // Clean up all the TypedArrays.
+ icons.recycle();
+ intents.recycle();
+ longPressIntents.recycle();
+ facetPackageNames.recycle();
+ facetCategories.recycle();
+ }
+ }
+
+ /**
+ * Recreates each of the buttons on a density or font scale change. This manual process is
+ * necessary since this class is not part of an activity that automatically gets recreated.
+ */
+ public void onDensityOrFontScaleChanged() {
+ TypedArray icons = mContext.getResources().obtainTypedArray(R.array.car_facet_icons);
+
+ try {
+ int length = icons.length();
+ if (length != mNavButtons.size()) {
+ // This should not happen since the mNavButtons list is created from the length
+ // of the icons array in bind().
+ throw new RuntimeException("car_facet array lengths do not match number of "
+ + "created buttons.");
+ }
+
+ for (int i = 0; i < length; i++) {
+ Drawable icon = icons.getDrawable(i);
+
+ // Setting a new icon will trigger a requestLayout() call if necessary.
+ mNavButtons.get(i).setResources(icon);
}
+ } finally {
+ icons.recycle();
}
}
private void initFacetFilterMaps(int id, String[] packageNames, String[] categories) {
mFacetCategories.add(categories);
- for (int i = 0; i < categories.length; i++) {
- mFacetCategoryMap.put(categories[i], id);
+ for (String category : categories) {
+ mFacetCategoryMap.put(category, id);
}
mFacetPackages.add(packageNames);
- for (int i = 0; i < packageNames.length; i++) {
- mFacetPackageMap.put(packageNames[i], id);
+ for (String packageName : packageNames) {
+ mFacetPackageMap.put(packageName, id);
}
}
@@ -223,8 +243,10 @@ class CarNavigationBarController {
}
/**
- * Helper method to check if a given facet has multiple packages associated with it.
- * This can be resource defined package names or package names filtered by facet category.
+ * Helper method to check if a given facet has multiple packages associated with it. This can
+ * be resource defined package names or package names filtered by facet category.
+ *
+ * @return {@code true} if the facet at the given index has more than one package.
*/
private boolean facetHasMultiplePackages(int index) {
PackageManager pm = mContext.getPackageManager();
@@ -259,6 +281,10 @@ class CarNavigationBarController {
return false;
}
+ /**
+ * Sets the facet at the given index to be the facet that is currently active. The button will
+ * be highlighted appropriately.
+ */
private void setCurrentFacet(int index) {
if (index == mCurrentFacetIndex) {
return;
@@ -273,11 +299,16 @@ class CarNavigationBarController {
mNavButtons.get(index).setSelected(true /* selected */,
mFacetHasMultipleAppsCache.get(index) /* showMoreIcon */);
}
+
mCurrentFacetIndex = index;
}
- private CarNavigationButton createNavButton(Drawable icon, final int id,
- boolean longClickEnabled) {
+ /**
+ * Creates the View that is used for the buttons along the navigation bar.
+ *
+ * @param icon The icon to be used for the button.
+ */
+ private CarNavigationButton createNavButton(Drawable icon) {
CarNavigationButton button = (CarNavigationButton) View.inflate(mContext,
R.layout.car_navigation_button, null);
button.setResources(icon);
@@ -285,37 +316,49 @@ class CarNavigationBarController {
new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
button.setLayoutParams(lp);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- onFacetClicked(id);
- }
- });
-
- if (longClickEnabled) {
- button.setLongClickable(true);
- button.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- onFacetLongClicked(id);
- return true;
- }
- });
- } else {
- button.setLongClickable(false);
- }
-
return button;
}
- private void startActivity(Intent intent, ActivityStarter.Callback callback) {
- if (mStatusBar != null && intent != null) {
- mStatusBar.startActivity(intent, false, callback);
+ /**
+ * Initializes the click and long click listeners that correspond to the given command string.
+ * The click listeners are attached to the given button.
+ */
+ private void initClickListeners(View button, int index, String clickString,
+ String longPressString) {
+ // Each button at least have an action when pressed.
+ if (TextUtils.isEmpty(clickString)) {
+ throw new RuntimeException("Facet at index " + index + " does not have click action.");
+ }
+
+ try {
+ Intent intent = Intent.parseUri(clickString, Intent.URI_INTENT_SCHEME);
+ button.setOnClickListener(v -> onFacetClicked(intent, index));
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Malformed intent uri", e);
+ }
+
+ if (TextUtils.isEmpty(longPressString)) {
+ button.setLongClickable(false);
+ return;
+ }
+
+ try {
+ Intent intent = Intent.parseUri(longPressString, Intent.URI_INTENT_SCHEME);
+ button.setOnLongClickListener(v -> {
+ onFacetLongClicked(intent, index);
+ return true;
+ });
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Malformed long-press intent uri", e);
}
}
- private void onFacetClicked(int index) {
- Intent intent = mIntents.get(index);
+ /**
+ * Handles a click on a facet. A click will trigger the given Intent.
+ *
+ * @param index The index of the facet that was clicked.
+ */
+ private void onFacetClicked(Intent intent, int index) {
String packageName = intent.getPackage();
if (packageName == null) {
@@ -341,13 +384,13 @@ class CarNavigationBarController {
mStatusBar.startActivityOnStack(intent, stackId);
}
- private void onFacetLongClicked(int index) {
+ /**
+ * Handles a long-press on a facet. The long-press will trigger the given Intent.
+ *
+ * @param index The index of the facet that was clicked.
+ */
+ private void onFacetLongClicked(Intent intent, int index) {
setCurrentFacet(index);
- mStatusBar.startActivityOnStack(mLongPressIntents.get(index),
- StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- }
-
- private List<Intent> createEmptyIntentList(int size) {
- return Arrays.asList(new Intent[size]);
+ mStatusBar.startActivityOnStack(intent, StackId.FULLSCREEN_WORKSPACE_STACK_ID);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index f24e40b13578..41613894252a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -35,11 +35,13 @@ import android.widget.LinearLayout;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -47,14 +49,12 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
* A status bar (and navigation bar) tailored for the automotive use case.
*/
-public class CarStatusBar extends PhoneStatusBar implements
+public class CarStatusBar extends StatusBar implements
CarBatteryController.BatteryViewHandler {
private static final String TAG = "CarStatusBar";
- private SystemServicesProxy mSystemServicesProxy;
private TaskStackListenerImpl mTaskStackListener;
- private CarNavigationBarView mCarNavigationBar;
private CarNavigationBarController mController;
private FullscreenUserSwitcher mFullscreenUserSwitcher;
@@ -62,7 +62,6 @@ public class CarStatusBar extends PhoneStatusBar implements
private BatteryMeterView mBatteryMeterView;
private ConnectedDeviceSignalController mConnectedDeviceSignalController;
- private View mSignalsView;
private CarNavigationBarView mNavigationBarView;
@Override
@@ -72,6 +71,8 @@ public class CarStatusBar extends PhoneStatusBar implements
SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
registerPackageChangeReceivers();
+ mStackScroller.setScrollingEnabled(true);
+
createBatteryController();
mCarBatteryController.startListening();
mConnectedDeviceSignalController.startListening();
@@ -96,16 +97,16 @@ public class CarStatusBar extends PhoneStatusBar implements
mBatteryMeterView.setVisibility(View.GONE);
ViewStub stub = (ViewStub) statusBarView.findViewById(R.id.connected_device_signals_stub);
- mSignalsView = stub.inflate();
+ View signalsView = stub.inflate();
// When a ViewStub if inflated, it does not respect the margins on the inflated view.
// As a result, manually add the ending margin.
- ((LinearLayout.LayoutParams) mSignalsView.getLayoutParams()).setMarginEnd(
+ ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
mContext.getResources().getDimensionPixelOffset(
R.dimen.status_bar_connected_device_signal_margin_end));
mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
- mSignalsView);
+ signalsView);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
@@ -126,12 +127,11 @@ public class CarStatusBar extends PhoneStatusBar implements
return;
}
- mCarNavigationBar =
- (CarNavigationBarView) View.inflate(mContext, R.layout.car_navigation_bar, null);
- mController = new CarNavigationBarController(mContext, mCarNavigationBar,
+ mNavigationBarView = (CarNavigationBarView) View.inflate(mContext,
+ R.layout.car_navigation_bar, null);
+ mController = new CarNavigationBarController(mContext, mNavigationBarView,
this /* ActivityStarter*/);
- mNavigationBarView = mCarNavigationBar;
- mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true);
+ mNavigationBarView.getBarTransitions().setAlwaysOpaque(true);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
@@ -148,6 +148,31 @@ public class CarStatusBar extends PhoneStatusBar implements
}
@Override
+ public NavigationBarView getNavigationBarView() {
+ return mNavigationBarView;
+ }
+
+ @Override
+ protected View.OnTouchListener getStatusBarWindowTouchListener() {
+ // Usually, a touch on the background window will dismiss the notification shade. However,
+ // for the car use-case, the shade should remain unless the user switches to a different
+ // facet (e.g. phone).
+ return null;
+ }
+
+ /**
+ * Returns the {@link com.android.systemui.SwipeHelper.LongPressListener} that will be
+ * triggered when a notification card is long-pressed.
+ */
+ @Override
+ protected SwipeHelper.LongPressListener getNotificationLongClicker() {
+ // For the automative use case, we do not want to the user to be able to interact with
+ // a notification other than a regular click. As a result, just return null for the
+ // long click listener.
+ return null;
+ }
+
+ @Override
public void showBatteryView() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
@@ -272,4 +297,14 @@ public class CarStatusBar extends PhoneStatusBar implements
options.setLaunchStackId(stackId);
return startActivityWithOptions(intent, options.toBundle());
}
+
+ /**
+ * Ensures that relevant child views are appropriately recreated when the device's density
+ * changes.
+ */
+ @Override
+ protected void onDensityOrFontScaleChanged() {
+ super.onDensityOrFontScaleChanged();
+ mController.onDensityOrFontScaleChanged();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index c308930cf691..67f8426586ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -20,7 +20,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.ScalingDrawableWrapper;
import com.android.systemui.statusbar.policy.BluetoothController;
-import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
/**
* Controller that monitors signal strength for a device that is connected via bluetooth.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 8e6c15391f69..f8b6dee46a8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -20,7 +20,7 @@ import android.view.View;
import android.view.ViewStub;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
@@ -32,7 +32,7 @@ public class FullscreenUserSwitcher {
private UserGridView mUserGridView;
private UserSwitcherController mUserSwitcherController;
- public FullscreenUserSwitcher(PhoneStatusBar statusBar,
+ public FullscreenUserSwitcher(StatusBar statusBar,
UserSwitcherController userSwitcherController,
ViewStub containerStub) {
mUserSwitcherController = userSwitcherController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
index d90a21dec117..137b5cfbabe4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -29,12 +29,12 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.UserUtil;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.UserSwitcherController;
public class UserGridView extends GridView {
- private PhoneStatusBar mStatusBar;
+ private StatusBar mStatusBar;
private UserSwitcherController mUserSwitcherController;
private Adapter mAdapter;
private int mPendingUserId = UserHandle.USER_NULL;
@@ -43,7 +43,7 @@ public class UserGridView extends GridView {
super(context, attrs);
}
- public void init(PhoneStatusBar statusBar, UserSwitcherController userSwitcherController) {
+ public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) {
mStatusBar = statusBar;
mUserSwitcherController = userSwitcherController;
mAdapter = new Adapter(mUserSwitcherController);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/CustomInterpolatorTransformation.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/CustomInterpolatorTransformation.java
new file mode 100644
index 000000000000..de4c3128e99f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/CustomInterpolatorTransformation.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
+
+import static com.android.systemui.statusbar.TransformableView.TRANSFORMING_VIEW_TITLE;
+import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y;
+
+/**
+ * A custom transformation that modifies the interpolator
+ */
+public abstract class CustomInterpolatorTransformation
+ extends ViewTransformationHelper.CustomTransformation {
+
+ private final int mViewType;
+
+ public CustomInterpolatorTransformation(int viewType) {
+ mViewType = viewType;
+ }
+
+ @Override
+ public boolean transformTo(TransformState ownState, TransformableView notification,
+ float transformationAmount) {
+ if (!hasCustomTransformation()) {
+ return false;
+ }
+ TransformState otherState = notification.getCurrentState(mViewType);
+ if (otherState == null) {
+ return false;
+ }
+ View view = ownState.getTransformedView();
+ CrossFadeHelper.fadeOut(view, transformationAmount);
+ ownState.transformViewFullyTo(otherState, this, transformationAmount);
+ otherState.recycle();
+ return true;
+ }
+
+ protected boolean hasCustomTransformation() {
+ return true;
+ }
+
+ @Override
+ public boolean transformFrom(TransformState ownState,
+ TransformableView notification, float transformationAmount) {
+ if (!hasCustomTransformation()) {
+ return false;
+ }
+ TransformState otherState = notification.getCurrentState(mViewType);
+ if (otherState == null) {
+ return false;
+ }
+ View view = ownState.getTransformedView();
+ CrossFadeHelper.fadeIn(view, transformationAmount);
+ ownState.transformViewFullyFrom(otherState, this, transformationAmount);
+ otherState.recycle();
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
deleted file mode 100644
index 9501f907e575..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.util.Pools;
-import android.view.NotificationHeaderView;
-import android.view.View;
-
-import com.android.systemui.statusbar.CrossFadeHelper;
-
-/**
- * A transform state of a text view.
-*/
-public class HeaderTransformState extends TransformState {
-
- private static Pools.SimplePool<HeaderTransformState> sInstancePool
- = new Pools.SimplePool<>(40);
- private View mExpandButton;
- private View mWorkProfileIcon;
- private TransformState mWorkProfileState;
-
- @Override
- public void initFrom(View view) {
- super.initFrom(view);
- if (view instanceof NotificationHeaderView) {
- NotificationHeaderView header = (NotificationHeaderView) view;
- mExpandButton = header.getExpandButton();
- mWorkProfileState = TransformState.obtain();
- mWorkProfileIcon = header.getWorkProfileIcon();
- mWorkProfileState.initFrom(mWorkProfileIcon);
- }
- }
-
- @Override
- public boolean transformViewTo(TransformState otherState, float transformationAmount) {
- // if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one and transform the work profile icon.
- if (!(mTransformedView instanceof NotificationHeaderView)) {
- return false;
- }
- NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
- int childCount = header.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View headerChild = header.getChildAt(i);
- if (headerChild.getVisibility() == View.GONE) {
- continue;
- }
- if (headerChild != mExpandButton) {
- headerChild.setVisibility(View.INVISIBLE);
- } else {
- CrossFadeHelper.fadeOut(mExpandButton, transformationAmount);
- }
- }
- return true;
- }
-
- @Override
- public void transformViewFrom(TransformState otherState, float transformationAmount) {
- // if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one and transform the work profile icon.
- if (!(mTransformedView instanceof NotificationHeaderView)) {
- return;
- }
- NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
- header.setVisibility(View.VISIBLE);
- header.setAlpha(1.0f);
- int childCount = header.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View headerChild = header.getChildAt(i);
- if (headerChild.getVisibility() == View.GONE) {
- continue;
- }
- if (headerChild == mExpandButton) {
- CrossFadeHelper.fadeIn(mExpandButton, transformationAmount);
- } else {
- headerChild.setVisibility(View.VISIBLE);
- if (headerChild == mWorkProfileIcon) {
- mWorkProfileState.transformViewFullyFrom(
- ((HeaderTransformState) otherState).mWorkProfileState,
- transformationAmount);
- }
- }
- }
- return;
- }
-
- public static HeaderTransformState obtain() {
- HeaderTransformState instance = sInstancePool.acquire();
- if (instance != null) {
- return instance;
- }
- return new HeaderTransformState();
- }
-
- @Override
- public void recycle() {
- super.recycle();
- sInstancePool.release(this);
- }
-
- @Override
- protected void reset() {
- super.reset();
- mExpandButton = null;
- mWorkProfileState = null;
- if (mWorkProfileState != null) {
- mWorkProfileState.recycle();
- mWorkProfileState = null;
- }
- }
-
- @Override
- public void setVisible(boolean visible, boolean force) {
- super.setVisible(visible, force);
- if (!(mTransformedView instanceof NotificationHeaderView)) {
- return;
- }
- NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
- int childCount = header.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View headerChild = header.getChildAt(i);
- if (!force && headerChild.getVisibility() == View.GONE) {
- continue;
- }
- headerChild.animate().cancel();
- if (headerChild.getVisibility() != View.GONE) {
- headerChild.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- if (headerChild == mExpandButton) {
- headerChild.setAlpha(visible ? 1.0f : 0.0f);
- }
- if (headerChild == mWorkProfileIcon) {
- headerChild.setTranslationX(0);
- headerChild.setTranslationY(0);
- }
- }
- }
-
- @Override
- public void prepareFadeIn() {
- super.prepareFadeIn();
- if (!(mTransformedView instanceof NotificationHeaderView)) {
- return;
- }
- NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
- int childCount = header.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View headerChild = header.getChildAt(i);
- if (headerChild.getVisibility() == View.GONE) {
- continue;
- }
- headerChild.animate().cancel();
- headerChild.setVisibility(View.VISIBLE);
- headerChild.setAlpha(1.0f);
- if (headerChild == mWorkProfileIcon) {
- headerChild.setTranslationX(0);
- headerChild.setTranslationY(0);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index 6084770f5db5..78b967a35b42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -36,8 +36,8 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
- super.notifyContentUpdated(notification);
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ super.notifyContentUpdated(notification, isLowPriority);
updateImageTag(notification);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
index 3f4912550407..39db2434af5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
@@ -41,11 +41,11 @@ public class NotificationBigTextTemplateViewWrapper extends NotificationTemplate
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
resolveViews(notification);
- super.notifyContentUpdated(notification);
+ super.notifyContentUpdated(notification, isLowPriority);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 85e87ddc84df..e5f32df8af7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -40,14 +40,13 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
private final ViewInvertHelper mInvertHelper;
private final Paint mGreyPaint = new Paint();
- private int mBackgroundColor = 0;
- private static final int CUSTOM_BACKGROUND_TAG = R.id.custom_background_color;
- private boolean mShouldInvertDark;
private boolean mShowingLegacyBackground;
+ private int mLegacyColor;
protected NotificationCustomViewWrapper(View view, ExpandableNotificationRow row) {
super(view, row);
mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
+ mLegacyColor = row.getContext().getColor(R.color.notification_legacy_background_color);
}
@Override
@@ -106,29 +105,17 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
- super.notifyContentUpdated(notification);
- Drawable background = mView.getBackground();
- mBackgroundColor = 0;
- if (background instanceof ColorDrawable) {
- mBackgroundColor = ((ColorDrawable) background).getColor();
- mView.setBackground(null);
- mView.setTag(CUSTOM_BACKGROUND_TAG, mBackgroundColor);
- } else if (mView.getTag(CUSTOM_BACKGROUND_TAG) != null) {
- mBackgroundColor = (int) mView.getTag(CUSTOM_BACKGROUND_TAG);
- }
- mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
- }
-
- private boolean isColorLight(int backgroundColor) {
- return Color.alpha(backgroundColor) == 0
- || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
+ protected boolean shouldClearBackgroundOnReapply() {
+ return false;
}
@Override
public int getCustomBackgroundColor() {
- // Parent notifications should always use the normal background color
- return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
+ int customBackgroundColor = super.getCustomBackgroundColor();
+ if (customBackgroundColor == 0 && mShowingLegacyBackground) {
+ return mLegacyColor;
+ }
+ return customBackgroundColor;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 3e4c75897d69..8eab2e914d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -31,8 +31,12 @@ import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -42,17 +46,21 @@ import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.Stack;
+import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y;
+
/**
* Wraps a notification header view.
*/
public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
+ private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
+ = new PathInterpolator(0.4f, 0f, 0.7f, 1f);
private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
0, PorterDuff.Mode.SRC_ATOP);
private final int mIconDarkAlpha;
private final int mIconDarkColor = 0xffffffff;
- protected final ViewInvertHelper mInvertHelper;
+ protected final ViewInvertHelper mInvertHelper;
protected final ViewTransformationHelper mTransformationHelper;
protected int mColor;
@@ -60,19 +68,50 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
private ImageView mExpandButton;
private NotificationHeaderView mNotificationHeader;
+ private TextView mHeaderText;
+ private ImageView mWorkProfileImage;
+ private boolean mIsLowPriority;
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
super(view, row);
mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
mTransformationHelper = new ViewTransformationHelper();
+
+ // we want to avoid that the header clashes with the other text when transforming
+ // low-priority
+ mTransformationHelper.setCustomTransformation(
+ new CustomInterpolatorTransformation(TRANSFORMING_VIEW_TITLE) {
+
+ @Override
+ public Interpolator getCustomInterpolator(int interpolationType,
+ boolean isFrom) {
+ boolean isLowPriority = mView instanceof NotificationHeaderView;
+ if (interpolationType == TRANSFORM_Y) {
+ if (isLowPriority && !isFrom
+ || !isLowPriority && isFrom) {
+ return Interpolators.LINEAR_OUT_SLOW_IN;
+ } else {
+ return LOW_PRIORITY_HEADER_CLOSE;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean hasCustomTransformation() {
+ return mIsLowPriority;
+ }
+ }, TRANSFORMING_VIEW_TITLE);
resolveHeaderViews();
updateInvertHelper();
}
protected void resolveHeaderViews() {
mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+ mHeaderText = (TextView) mView.findViewById(com.android.internal.R.id.header_text);
mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+ mWorkProfileImage = (ImageView) mView.findViewById(com.android.internal.R.id.profile_badge);
mColor = resolveColor(mExpandButton);
mNotificationHeader = (NotificationHeaderView) mView.findViewById(
com.android.internal.R.id.notification_header);
@@ -89,9 +128,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
- super.notifyContentUpdated(notification);
-
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ super.notifyContentUpdated(notification, isLowPriority);
+ mIsLowPriority = isLowPriority;
ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
// Reinspect the notification.
@@ -100,6 +139,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
updateTransformedTypes();
addRemainingTransformTypes();
updateCropToPaddingForImageViews();
+ mIcon.setTag(ImageTransformState.ICON_TAG, notification.getNotification().getSmallIcon());
+ // The work profile image is always the same lets just set the icon tag for it not to
+ // animate
+ mWorkProfileImage.setTag(ImageTransformState.ICON_TAG,
+ notification.getNotification().getSmallIcon());
// We need to reset all views that are no longer transforming in case a view was previously
// transformed, but now we decided to transform its container instead.
@@ -154,8 +198,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
protected void updateTransformedTypes() {
mTransformationHelper.reset();
- mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER,
- mNotificationHeader);
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON, mIcon);
+ if (mIsLowPriority) {
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
+ mHeaderText);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 4ce330c06223..04ee6aa18b37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -40,11 +40,11 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
resolveViews(notification);
- super.notifyContentUpdated(notification);
+ super.notifyContentUpdated(notification, isLowPriority);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
index ff2febfa38f8..defeab2c1cc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -22,7 +22,11 @@ import com.android.systemui.statusbar.TransformableView;
import android.content.Context;
import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
import android.view.View;
+import android.widget.TextView;
+
+import java.util.ArrayList;
/**
* Wraps a notification containing a messaging template
@@ -30,6 +34,7 @@ import android.view.View;
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
private View mContractedMessage;
+ private ArrayList<View> mHistoricMessages = new ArrayList<View>();
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
@@ -44,21 +49,33 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
&& ((MessagingLinearLayout) container).getChildCount() > 0) {
MessagingLinearLayout messagingContainer = (MessagingLinearLayout) container;
- // Only consider the first child - transforming to a position other than the first
- // looks bad because we have to move across other messages that are fading in.
- View child = messagingContainer.getChildAt(0);
- if (child.getId() == messagingContainer.getContractedChildId()) {
- mContractedMessage = child;
+ int childCount = messagingContainer.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = messagingContainer.getChildAt(i);
+
+ if (child.getVisibility() == View.GONE
+ && child instanceof TextView
+ && !TextUtils.isEmpty(((TextView) child).getText())) {
+ mHistoricMessages.add(child);
+ }
+
+ // Only consider the first visible child - transforming to a position other than the
+ // first looks bad because we have to move across other messages that are fading in.
+ if (child.getId() == messagingContainer.getContractedChildId()) {
+ mContractedMessage = child;
+ } else if (child.getVisibility() == View.VISIBLE) {
+ break;
+ }
}
}
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
resolveViews();
- super.notifyContentUpdated(notification);
+ super.notifyContentUpdated(notification, isLowPriority);
}
@Override
@@ -70,4 +87,11 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
mContractedMessage);
}
}
+
+ @Override
+ public void setRemoteInputVisible(boolean visible) {
+ for (int i = 0; i < mHistoricMessages.size(); i++) {
+ mHistoricMessages.get(i).setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index b984c0ba8e3e..e9956ff9f109 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -133,11 +133,11 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification) {
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
resolveTemplateViews(notification);
- super.notifyContentUpdated(notification);
+ super.notifyContentUpdated(notification, isLowPriority);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 16348dfe5818..5f5e1e46e9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -19,12 +19,17 @@ package com.android.systemui.statusbar.notification;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.ColorMatrix;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
import android.view.NotificationHeaderView;
import android.view.View;
import com.android.systemui.Interpolators;
+import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
@@ -40,6 +45,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
protected final ExpandableNotificationRow mRow;
protected boolean mDark;
+ private int mBackgroundColor = 0;
+ protected boolean mShouldInvertDark;
protected boolean mDarkInitialized = false;
public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
@@ -80,11 +87,30 @@ public abstract class NotificationViewWrapper implements TransformableView {
/**
* Notifies this wrapper that the content of the view might have changed.
- * @param notification
+ * @param notification the notification this is wrapped around
+ * @param isLowPriority is this notification low priority
*/
- public void notifyContentUpdated(StatusBarNotification notification) {
+ public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
mDarkInitialized = false;
- };
+ Drawable background = mView.getBackground();
+ if (shouldClearBackgroundOnReapply()) {
+ mBackgroundColor = 0;
+ }
+ if (background instanceof ColorDrawable) {
+ mBackgroundColor = ((ColorDrawable) background).getColor();
+ mView.setBackground(null);
+ }
+ mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
+ }
+
+ protected boolean shouldClearBackgroundOnReapply() {
+ return true;
+ }
+
+ private boolean isColorLight(int backgroundColor) {
+ return Color.alpha(backgroundColor) == 0
+ || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
+ }
protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
@@ -155,7 +181,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
public int getCustomBackgroundColor() {
- return 0;
+ // Parent notifications should always use the normal background color
+ return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
}
public void setShowingLegacyBackground(boolean showing) {
@@ -163,4 +190,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
public void setContentHeight(int contentHeight, int minHeightHint) {
}
+
+ public void setRemoteInputVisible(boolean visible) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 770ec950504a..d15ab10e09ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -18,10 +18,10 @@ package com.android.systemui.statusbar.notification;
import android.util.ArraySet;
import android.util.Pools;
-import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -38,10 +38,11 @@ import com.android.systemui.statusbar.ViewTransformationHelper;
*/
public class TransformState {
+ public static final int TRANSFORM_X = 0x1;
+ public static final int TRANSFORM_Y = 0x10;
+ public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y;
+
private static final float UNDEFINED = -1f;
- private static final int TRANSOFORM_X = 0x1;
- private static final int TRANSOFORM_Y = 0x10;
- private static final int TRANSOFORM_ALL = TRANSOFORM_X | TRANSOFORM_Y;
private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
@@ -80,25 +81,31 @@ public class TransformState {
}
public void transformViewFullyFrom(TransformState otherState, float transformationAmount) {
- transformViewFrom(otherState, TRANSOFORM_ALL, null, transformationAmount);
+ transformViewFrom(otherState, TRANSFORM_ALL, null, transformationAmount);
+ }
+
+ public void transformViewFullyFrom(TransformState otherState,
+ ViewTransformationHelper.CustomTransformation customTransformation,
+ float transformationAmount) {
+ transformViewFrom(otherState, TRANSFORM_ALL, customTransformation, transformationAmount);
}
public void transformViewVerticalFrom(TransformState otherState,
ViewTransformationHelper.CustomTransformation customTransformation,
float transformationAmount) {
- transformViewFrom(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
+ transformViewFrom(otherState, TRANSFORM_Y, customTransformation, transformationAmount);
}
public void transformViewVerticalFrom(TransformState otherState, float transformationAmount) {
- transformViewFrom(otherState, TRANSOFORM_Y, null, transformationAmount);
+ transformViewFrom(otherState, TRANSFORM_Y, null, transformationAmount);
}
private void transformViewFrom(TransformState otherState, int transformationFlags,
ViewTransformationHelper.CustomTransformation customTransformation,
float transformationAmount) {
final View transformedView = mTransformedView;
- boolean transformX = (transformationFlags & TRANSOFORM_X) != 0;
- boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
+ boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
+ boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
boolean transformScale = transformScale();
// lets animate the positions correctly
if (transformationAmount == 0.0f
@@ -153,14 +160,30 @@ public class TransformState {
float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
transformationAmount);
if (transformX) {
+ float interpolation = interpolatedValue;
+ if (customTransformation != null) {
+ Interpolator customInterpolator =
+ customTransformation.getCustomInterpolator(TRANSFORM_X, true /* isFrom */);
+ if (customInterpolator != null) {
+ interpolation = customInterpolator.getInterpolation(transformationAmount);
+ }
+ }
transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
0.0f,
- interpolatedValue));
+ interpolation));
}
if (transformY) {
+ float interpolation = interpolatedValue;
+ if (customTransformation != null) {
+ Interpolator customInterpolator =
+ customTransformation.getCustomInterpolator(TRANSFORM_Y, true /* isFrom */);
+ if (customInterpolator != null) {
+ interpolation = customInterpolator.getInterpolation(transformationAmount);
+ }
+ }
transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
0.0f,
- interpolatedValue));
+ interpolation));
}
if (transformScale) {
float transformationStartScaleX = getTransformationStartScaleX();
@@ -207,17 +230,23 @@ public class TransformState {
}
public void transformViewFullyTo(TransformState otherState, float transformationAmount) {
- transformViewTo(otherState, TRANSOFORM_ALL, null, transformationAmount);
+ transformViewTo(otherState, TRANSFORM_ALL, null, transformationAmount);
+ }
+
+ public void transformViewFullyTo(TransformState otherState,
+ ViewTransformationHelper.CustomTransformation customTransformation,
+ float transformationAmount) {
+ transformViewTo(otherState, TRANSFORM_ALL, customTransformation, transformationAmount);
}
public void transformViewVerticalTo(TransformState otherState,
ViewTransformationHelper.CustomTransformation customTransformation,
float transformationAmount) {
- transformViewTo(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
+ transformViewTo(otherState, TRANSFORM_Y, customTransformation, transformationAmount);
}
public void transformViewVerticalTo(TransformState otherState, float transformationAmount) {
- transformViewTo(otherState, TRANSOFORM_Y, null, transformationAmount);
+ transformViewTo(otherState, TRANSFORM_Y, null, transformationAmount);
}
private void transformViewTo(TransformState otherState, int transformationFlags,
@@ -226,8 +255,8 @@ public class TransformState {
// lets animate the positions correctly
final View transformedView = mTransformedView;
- boolean transformX = (transformationFlags & TRANSOFORM_X) != 0;
- boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
+ boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
+ boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
boolean transformScale = transformScale();
// lets animate the positions correctly
if (transformationAmount == 0.0f) {
@@ -264,23 +293,37 @@ public class TransformState {
int[] ownPosition = getLaidOutLocationOnScreen();
if (transformX) {
float endX = otherStablePosition[0] - ownPosition[0];
- if (customTransformation != null
- && customTransformation.customTransformTarget(this, otherState)) {
- endX = mTransformationEndX;
+ float interpolation = interpolatedValue;
+ if (customTransformation != null) {
+ if (customTransformation.customTransformTarget(this, otherState)) {
+ endX = mTransformationEndX;
+ }
+ Interpolator customInterpolator =
+ customTransformation.getCustomInterpolator(TRANSFORM_X, false /* isFrom */);
+ if (customInterpolator != null) {
+ interpolation = customInterpolator.getInterpolation(transformationAmount);
+ }
}
transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
endX,
- interpolatedValue));
+ interpolation));
}
if (transformY) {
float endY = otherStablePosition[1] - ownPosition[1];
- if (customTransformation != null
- && customTransformation.customTransformTarget(this, otherState)) {
- endY = mTransformationEndY;
+ float interpolation = interpolatedValue;
+ if (customTransformation != null) {
+ if (customTransformation.customTransformTarget(this, otherState)) {
+ endY = mTransformationEndY;
+ }
+ Interpolator customInterpolator =
+ customTransformation.getCustomInterpolator(TRANSFORM_Y, false /* isFrom */);
+ if (customInterpolator != null) {
+ interpolation = customInterpolator.getInterpolation(transformationAmount);
+ }
}
transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
endY,
- interpolatedValue));
+ interpolation));
}
if (transformScale) {
View otherView = otherState.getTransformedView();
@@ -402,11 +445,6 @@ public class TransformState {
result.initFrom(view);
return result;
}
- if (view instanceof NotificationHeaderView) {
- HeaderTransformState result = HeaderTransformState.obtain();
- result.initFrom(view);
- return result;
- }
if (view instanceof ImageView) {
ImageTransformState result = ImageTransformState.obtain();
result.initFrom(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 42d9433b4367..0773108b3d60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -16,11 +16,7 @@
package com.android.systemui.statusbar.phone;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -98,7 +94,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
private DozeScrimController mDozeScrimController;
private KeyguardViewMediator mKeyguardViewMediator;
private ScrimController mScrimController;
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
private final UnlockMethodCache mUnlockMethodCache;
private final Context mContext;
private boolean mGoingToSleep;
@@ -109,7 +105,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator,
ScrimController scrimController,
- PhoneStatusBar phoneStatusBar,
+ StatusBar statusBar,
UnlockMethodCache unlockMethodCache) {
mContext = context;
mPowerManager = context.getSystemService(PowerManager.class);
@@ -119,7 +115,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
mDozeScrimController = dozeScrimController;
mKeyguardViewMediator = keyguardViewMediator;
mScrimController = scrimController;
- mPhoneStatusBar = phoneStatusBar;
+ mStatusBar = statusBar;
mUnlockMethodCache = unlockMethodCache;
}
@@ -218,7 +214,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
break;
case MODE_WAKE_AND_UNLOCK_PULSING:
Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
- mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+ mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
true /* allowEnterAnimation */);
// Fall through.
Trace.endSection();
@@ -228,8 +224,8 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
mDozeScrimController.abortPulsing();
mKeyguardViewMediator.onWakeAndUnlocking();
mScrimController.setWakeAndUnlocking();
- if (mPhoneStatusBar.getNavigationBarView() != null) {
- mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
Trace.endSection();
break;
@@ -240,7 +236,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
if (mMode != MODE_WAKE_AND_UNLOCK_PULSING) {
mStatusBarWindowManager.setForceDozeBrightness(false);
}
- mPhoneStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyFpAuthModeChanged();
Trace.endSection();
}
@@ -309,7 +305,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
mMode = MODE_NONE;
releaseFingerprintWakeLock();
mStatusBarWindowManager.setForceDozeBrightness(false);
- mPhoneStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyFpAuthModeChanged();
}
public void startKeyguardFadingAway() {
@@ -320,14 +316,14 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
public void run() {
mStatusBarWindowManager.setForceDozeBrightness(false);
}
- }, PhoneStatusBar.FADE_KEYGUARD_DURATION_PULSING);
+ }, StatusBar.FADE_KEYGUARD_DURATION_PULSING);
}
public void finishKeyguardFadingAway() {
mMode = MODE_NONE;
- if (mPhoneStatusBar.getNavigationBarView() != null) {
- mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
}
- mPhoneStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyFpAuthModeChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 79120d889c2f..14f991997e35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,10 @@ package com.android.systemui.statusbar.phone;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
+import static com.android.systemui.tuner.LockscreenFragment.getIntentButton;
+
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.admin.DevicePolicyManager;
@@ -31,6 +35,7 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.AssetFileDescriptor.AutoCloseOutputStream;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -43,6 +48,7 @@ import android.os.UserHandle;
import android.provider.MediaStore;
import android.service.media.CameraPrewarmService;
import android.telecom.TelecomManager;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -53,6 +59,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.TextView;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -74,6 +81,9 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.PreviewInflater;
+import com.android.systemui.tuner.LockscreenFragment;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
@@ -81,9 +91,10 @@ import com.android.systemui.statusbar.policy.PreviewInflater;
*/
public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
UnlockMethodCache.OnUnlockMethodChangedListener,
- AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
+ AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener,
+ Tunable {
- final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
+ final static String TAG = "StatusBar/KeyguardBottomAreaView";
public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
@@ -124,7 +135,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private PreviewInflater mPreviewInflater;
private KeyguardIndicationController mIndicationController;
private AccessibilityController mAccessibilityController;
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
private boolean mUserSetupComplete;
@@ -148,7 +159,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private Drawable mLeftAssistIcon;
private IntentButton mRightButton = new DefaultRightButton();
+ private IntentButton mRightDefault = mRightButton;
+ private IntentButton mRightPlugin;
+ private String mRightButtonStr;
private IntentButton mLeftButton = new DefaultLeftButton();
+ private IntentButton mLeftDefault = mLeftButton;
+ private IntentButton mLeftPlugin;
+ private String mLeftButtonStr;
+ private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -190,7 +208,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == ACTION_CLICK) {
if (host == mLockIcon) {
- mPhoneStatusBar.animateCollapsePanels(
+ mStatusBar.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
return true;
} else if (host == mRightAffordanceView) {
@@ -241,17 +259,22 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- PluginManager.getInstance(getContext()).addPluginListener(RIGHT_BUTTON_PLUGIN,
+ mAccessibilityController.addStateChangedCallback(this);
+ Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN,
mRightListener, IntentButtonProvider.VERSION, false /* Only allow one */);
- PluginManager.getInstance(getContext()).addPluginListener(LEFT_BUTTON_PLUGIN,
+ Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN,
mLeftListener, IntentButtonProvider.VERSION, false /* Only allow one */);
+ Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON,
+ LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- PluginManager.getInstance(getContext()).removePluginListener(mRightListener);
- PluginManager.getInstance(getContext()).removePluginListener(mLeftListener);
+ mAccessibilityController.removeStateChangedCallback(this);
+ Dependency.get(PluginManager.class).removePluginListener(mRightListener);
+ Dependency.get(PluginManager.class).removePluginListener(mLeftListener);
+ Dependency.get(TunerService.class).removeTunable(this);
}
private void initAccessibility() {
@@ -305,8 +328,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mRightAffordanceView.setContentDescription(state.contentDescription);
}
- public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
- mPhoneStatusBar = phoneStatusBar;
+ public void setStatusBar(StatusBar statusBar) {
+ mStatusBar = statusBar;
updateCameraVisibility(); // in case onFinishInflate() was called too early
}
@@ -370,13 +393,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private boolean isCameraDisabledByDpm() {
final DevicePolicyManager dpm =
(DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null && mPhoneStatusBar != null) {
+ if (dpm != null && mStatusBar != null) {
try {
final int userId = ActivityManager.getService().getCurrentUser().id;
final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
final boolean disabledBecauseKeyguardSecure =
(disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
- && mPhoneStatusBar.isKeyguardSecure();
+ && mStatusBar.isKeyguardSecure();
return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
} catch (RemoteException e) {
Log.e(TAG, "Can't get userId", e);
@@ -412,7 +435,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
if (!mAccessibilityController.isAccessibilityEnabled()) {
handleTrustCircleClick();
} else {
- mPhoneStatusBar.animateCollapsePanels(
+ mStatusBar.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
}
}
@@ -425,8 +448,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
private void handleTrustCircleClick() {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK, 0 /* lengthDp - N/A */,
+ mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_LOCK, 0 /* lengthDp - N/A */,
0 /* velocityDp - N/A */);
mIndicationController.showTransientIndication(
R.string.keyguard_indication_trust_disabled);
@@ -549,11 +571,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mAssistManager.launchVoiceAssistFromKeyguard();
}
};
- if (mPhoneStatusBar.isKeyguardCurrentlySecure()) {
+ if (mStatusBar.isKeyguardCurrentlySecure()) {
AsyncTask.execute(runnable);
} else {
- mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */,
- false /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */);
+ boolean dismissShade = !TextUtils.isEmpty(mRightButtonStr)
+ && Dependency.get(TunerService.class).getValue(LOCKSCREEN_RIGHT_UNLOCK, 1) != 0;
+ mStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */,
+ dismissShade, false /* afterKeyguardGone */, true /* deferred */);
}
}
@@ -571,7 +595,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
});
} else {
- mActivityStarter.startActivity(mLeftButton.getIntent(), false /* dismissShade */);
+ boolean dismissShade = !TextUtils.isEmpty(mLeftButtonStr)
+ && Dependency.get(TunerService.class).getValue(LOCKSCREEN_LEFT_UNLOCK, 1) != 0;
+ mActivityStarter.startActivity(mLeftButton.getIntent(), dismissShade);
}
}
@@ -763,15 +789,33 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
inflateCameraPreview();
}
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) {
+ mLeftButtonStr = newValue;
+ mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null;
+ mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
+ updateLeftAffordance();
+ } else {
+ mRightButtonStr = newValue;
+ mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
+ updateRightAffordanceIcon();
+ updateCameraVisibility();
+ inflateCameraPreview();
+ }
+ }
+
private void setRightButton(IntentButton button) {
- mRightButton = button;
+ mRightPlugin = button;
+ mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
updateRightAffordanceIcon();
updateCameraVisibility();
inflateCameraPreview();
}
private void setLeftButton(IntentButton button) {
- mLeftButton = button;
+ mLeftPlugin = button;
+ mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
mLeftIsVoiceAssist = false;
updateLeftAffordance();
}
@@ -785,7 +829,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onPluginDisconnected(IntentButtonProvider plugin) {
- setRightButton(new DefaultRightButton());
+ setRightButton(null);
}
};
@@ -798,7 +842,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onPluginDisconnected(IntentButtonProvider plugin) {
- setLeftButton(new DefaultLeftButton());
+ setLeftButton(null);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 4535992ed5b8..7c4588983b4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -20,15 +20,19 @@ import android.graphics.Rect;
import android.view.View;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.policy.BatteryController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
/**
* Controls how light status bar flag applies to the icons.
*/
-public class LightBarController implements BatteryController.BatteryStateChangeCallback {
+public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
@@ -203,4 +207,37 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
public void onPowerSaveChanged(boolean isPowerSave) {
reevaluate();
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("LightBarController: ");
+ pw.print(" mSystemUiVisibility=0x"); pw.print(
+ Integer.toHexString(mSystemUiVisibility));
+ pw.print(" mFullscreenStackVisibility=0x"); pw.print(
+ Integer.toHexString(mFullscreenStackVisibility));
+ pw.print(" mDockedStackVisibility=0x"); pw.println(
+ Integer.toHexString(mDockedStackVisibility));
+
+ pw.print(" mFullscreenLight="); pw.print(mFullscreenLight);
+ pw.print(" mDockedLight="); pw.println(mDockedLight);
+
+ pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds);
+ pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds);
+
+ pw.print(" mNavigationLight="); pw.print(mNavigationLight);
+ pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
+
+ pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode);
+ pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
+
+ pw.print(" mScrimAlpha="); pw.print(mScrimAlpha);
+ pw.print(" mScrimAlphaBelowThreshold="); pw.println(mScrimAlphaBelowThreshold);
+ pw.println();
+ pw.println(" StatusBarTransitionsController:");
+ mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
+ pw.println();
+ pw.println(" NavigationBarTransitionsController:");
+ mNavigationBarController.dump(fd, pw, args);
+ pw.println();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 0f9f0563b7fe..07f37ab01f5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -20,13 +20,18 @@ import android.animation.ValueAnimator;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
+import android.util.TimeUtils;
+import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Class to control all aspects about light bar changes.
*/
-public class LightBarTransitionsController {
+public class LightBarTransitionsController implements Dumpable {
public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
@@ -147,6 +152,26 @@ public class LightBarTransitionsController {
mApplier.applyDarkIntensity(darkIntensity);
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print(" mTransitionDeferring="); pw.print(mTransitionDeferring);
+ if (mTransitionDeferring) {
+ pw.println();
+ pw.print(" mTransitionDeferringStartTime=");
+ pw.println(TimeUtils.formatUptime(mTransitionDeferringStartTime));
+
+ pw.print(" mTransitionDeferringDuration=");
+ TimeUtils.formatDuration(mTransitionDeferringDuration, pw);
+ pw.println();
+ }
+ pw.print(" mTransitionPending="); pw.print(mTransitionPending);
+ pw.print(" mTintChangePending="); pw.println(mTintChangePending);
+
+ pw.print(" mPendingDarkIntensity="); pw.print(mPendingDarkIntensity);
+ pw.print(" mDarkIntensity="); pw.print(mDarkIntensity);
+ pw.print(" mNextDarkIntensity="); pw.println(mNextDarkIntensity);
+ }
+
/**
* Interface to apply a specific dark intensity.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 695b500363e2..ef42b2f43287 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -29,11 +29,12 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.policy.AccessibilityController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
/**
* Manages the different states and animations of the unlock icon.
*/
-public class LockIcon extends KeyguardAffordanceView {
+public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChangedListener {
private static final int FP_DRAW_OFF_TIMEOUT = 800;
@@ -49,6 +50,7 @@ public class LockIcon extends KeyguardAffordanceView {
private boolean mDeviceInteractive;
private boolean mScreenOn;
private boolean mLastScreenOn;
+ private Drawable mUserAvatarIcon;
private TrustDrawable mTrustDrawable;
private final UnlockMethodCache mUnlockMethodCache;
private AccessibilityController mAccessibilityController;
@@ -80,6 +82,12 @@ public class LockIcon extends KeyguardAffordanceView {
mTrustDrawable.stop();
}
+ @Override
+ public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ mUserAvatarIcon = picture;
+ update();
+ }
+
public void setTransientFpError(boolean transientFpError) {
mTransientFpError = transientFpError;
update();
@@ -126,27 +134,33 @@ public class LockIcon extends KeyguardAffordanceView {
boolean trustHidden = anyFingerprintIcon;
if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
|| mScreenOn != mLastScreenOn || force) {
- boolean isAnim = true;
- int iconRes = getAnimationResForTransition(mLastState, state, mLastDeviceInteractive,
+ int iconAnimRes =
+ getAnimationResForTransition(mLastState, state, mLastDeviceInteractive,
mDeviceInteractive, mLastScreenOn, mScreenOn);
- if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
+ boolean isAnim = iconAnimRes != -1;
+ if (iconAnimRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
anyFingerprintIcon = true;
useAdditionalPadding = true;
trustHidden = true;
- } else if (iconRes == R.drawable.trusted_state_to_error_animation) {
+ } else if (iconAnimRes == R.drawable.trusted_state_to_error_animation) {
anyFingerprintIcon = true;
useAdditionalPadding = false;
trustHidden = true;
- } else if (iconRes == R.drawable.error_to_trustedstate_animation) {
+ } else if (iconAnimRes == R.drawable.error_to_trustedstate_animation) {
anyFingerprintIcon = true;
useAdditionalPadding = false;
trustHidden = false;
}
- if (iconRes == -1) {
- iconRes = getIconForState(state, mScreenOn, mDeviceInteractive);
- isAnim = false;
+
+ Drawable icon;
+ if (isAnim) {
+ // Load the animation resource.
+ icon = mContext.getDrawable(iconAnimRes);
+ } else {
+ // Load the static icon resource based on the current state.
+ icon = getIconForState(state, mScreenOn, mDeviceInteractive);
}
- Drawable icon = mContext.getDrawable(iconRes);
+
final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
? (AnimatedVectorDrawable) icon
: null;
@@ -175,7 +189,7 @@ public class LockIcon extends KeyguardAffordanceView {
animation.start();
}
- if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
+ if (iconAnimRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
removeCallbacks(mDrawOffTimeout);
postDelayed(mDrawOffTimeout, FP_DRAW_OFF_TIMEOUT);
} else {
@@ -225,25 +239,38 @@ public class LockIcon extends KeyguardAffordanceView {
mAccessibilityController = accessibilityController;
}
- private int getIconForState(int state, boolean screenOn, boolean deviceInteractive) {
+ private Drawable getIconForState(int state, boolean screenOn, boolean deviceInteractive) {
+ int iconRes;
switch (state) {
case STATE_LOCKED:
- return R.drawable.ic_lock_24dp;
+ iconRes = R.drawable.ic_lock_24dp;
+ break;
case STATE_LOCK_OPEN:
- return R.drawable.ic_lock_open_24dp;
+ if (mUnlockMethodCache.isTrustManaged() && mUnlockMethodCache.isTrusted()
+ && mUserAvatarIcon != null) {
+ return mUserAvatarIcon;
+ } else {
+ iconRes = R.drawable.ic_lock_open_24dp;
+ }
+ break;
case STATE_FACE_UNLOCK:
- return com.android.internal.R.drawable.ic_account_circle;
+ iconRes = com.android.internal.R.drawable.ic_account_circle;
+ break;
case STATE_FINGERPRINT:
// If screen is off and device asleep, use the draw on animation so the first frame
// gets drawn.
- return screenOn && deviceInteractive
+ iconRes = screenOn && deviceInteractive
? R.drawable.ic_fingerprint
: R.drawable.lockscreen_fingerprint_draw_on_animation;
+ break;
case STATE_FINGERPRINT_ERROR:
- return R.drawable.ic_fingerprint_error;
+ iconRes = R.drawable.ic_fingerprint_error;
+ break;
default:
throw new IllegalArgumentException();
}
+
+ return mContext.getDrawable(iconRes);
}
private int getAnimationResForTransition(int oldState, int newState,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
new file mode 100644
index 000000000000..83b96bfc4faf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.metrics.LogMaker;
+import android.util.ArrayMap;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
+
+/**
+ * Wrapper that emits both new- and old-style gesture logs.
+ * TODO: delete this once the old logs are no longer needed.
+ */
+public class LockscreenGestureLogger {
+ private ArrayMap<Integer, Integer> mLegacyMap;
+ private LogMaker mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
+ .setType(MetricsEvent.TYPE_ACTION);
+
+ public LockscreenGestureLogger() {
+ mLegacyMap = new ArrayMap<>(EventLogConstants.METRICS_GESTURE_TYPE_MAP.length);
+ for (int i = 0; i < EventLogConstants.METRICS_GESTURE_TYPE_MAP.length ; i++) {
+ mLegacyMap.put(EventLogConstants.METRICS_GESTURE_TYPE_MAP[i], i);
+ }
+ }
+
+ public void write(int gesture, int length, int velocity) {
+ MetricsLogger.action(mLogMaker.setCategory(gesture)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .addTaggedData(MetricsEvent.FIELD_GESTURE_LENGTH, length)
+ .addTaggedData(MetricsEvent.FIELD_GESTURE_VELOCITY, velocity));
+ // also write old-style logs for backward-0compatibility
+ EventLogTags.writeSysuiLockscreenGesture(safeLookup(gesture), length, velocity);
+ }
+
+ private int safeLookup(int gesture) {
+ Integer value = mLegacyMap.get(gesture);
+ if (value == null) {
+ return MetricsEvent.VIEW_UNKNOWN;
+ }
+ return value;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index af6e2595f0b6..99b3aa878c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -51,7 +51,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
private static final String TAG = "LockscreenWallpaper";
- private final PhoneStatusBar mBar;
+ private final StatusBar mBar;
private final WallpaperManager mWallpaperManager;
private final Handler mH;
private final KeyguardUpdateMonitor mUpdateMonitor;
@@ -64,7 +64,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
private UserHandle mSelectedUser;
private AsyncTask<Void, Void, LoaderResult> mLoader;
- public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
+ public LockscreenWallpaper(Context ctx, StatusBar bar, Handler h) {
mBar = bar;
mH = h;
mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 3c46d269750f..808cd2108829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -20,9 +20,10 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG_WINDOW_STATE;
-import static com.android.systemui.statusbar.phone.PhoneStatusBar.dumpBarTransitions;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
+import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -67,7 +68,6 @@ import com.android.keyguard.LatencyTracker;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.SystemUIApplication;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -80,6 +80,7 @@ import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
import java.util.Locale;
/**
@@ -102,10 +103,10 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
private int mNavigationIconHints = 0;
private int mNavigationBarMode;
- protected AccessibilityManager mAccessibilityManager;
+ private AccessibilityManager mAccessibilityManager;
private int mDisabledFlags1;
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
private Recents mRecents;
private Divider mDivider;
private WindowManager mWindowManager;
@@ -128,11 +129,13 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
super.onCreate(savedInstanceState);
mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
mCommandQueue.addCallbacks(this);
- mPhoneStatusBar = SysUiServiceProvider.getComponent(getContext(), PhoneStatusBar.class);
+ mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
mWindowManager = getContext().getSystemService(WindowManager.class);
mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
+ mAccessibilityManager.addAccessibilityServicesStateChangeListener(
+ this::updateAccessibilityServicesState);
if (savedInstanceState != null) {
mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
}
@@ -150,6 +153,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
public void onDestroy() {
super.onDestroy();
mCommandQueue.removeCallbacks(this);
+ mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
+ this::updateAccessibilityServicesState);
try {
WindowManagerGlobal.getWindowManagerService()
.removeRotationWatcher(mRotationWatcher);
@@ -262,7 +267,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
if (mNavigationBarView != null) {
mNavigationBarView.setNavigationIconHints(hints);
}
- mPhoneStatusBar.checkBarModes();
+ mStatusBar.checkBarModes();
}
@Override
@@ -300,21 +305,21 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
/**
* Calls appTransitionStarting for the nav bar regardless of whether keyguard is going away.
- * public so PhoneStatusBar can force this when needed.
+ * public so StatusBar can force this when needed.
*/
public void doAppTransitionStarting(long startTime, long duration) {
mNavigationBarView.getLightTransitionsController().appTransitionStarting(startTime,
duration);
}
- // Injected from PhoneStatusBar at creation.
+ // Injected from StatusBar at creation.
public void setCurrentSysuiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
- mNavigationBarMode = mPhoneStatusBar.computeBarMode(0, mSystemUiVisibility,
+ mNavigationBarMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
checkNavBarModes();
- mPhoneStatusBar.touchAutoHide();
+ mStatusBar.touchAutoHide();
mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
true /* nbModeChanged */, mNavigationBarMode);
}
@@ -331,7 +336,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
// update navigation bar mode
final int nbMode = getView() == null
- ? -1 : mPhoneStatusBar.computeBarMode(oldVal, newVal,
+ ? -1 : mStatusBar.computeBarMode(oldVal, newVal,
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
nbModeChanged = nbMode != -1;
@@ -340,7 +345,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
mNavigationBarMode = nbMode;
checkNavBarModes();
}
- mPhoneStatusBar.touchAutoHide();
+ mStatusBar.touchAutoHide();
}
}
@@ -370,7 +375,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
}
private boolean shouldDisableNavbarGestures() {
- return !mPhoneStatusBar.isDeviceProvisioned()
+ return !mStatusBar.isDeviceProvisioned()
|| (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
}
@@ -403,6 +408,10 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
homeButton.setOnLongClickListener(this::onHomeLongClick);
+
+ ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
+ accessibilityButton.setOnClickListener(this::onAccessibilityClick);
+ accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
}
private boolean onHomeTouch(View v, MotionEvent event) {
@@ -418,7 +427,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
TelecomManager telecomManager =
getContext().getSystemService(TelecomManager.class);
if (telecomManager != null && telecomManager.isRinging()) {
- if (mPhoneStatusBar.isKeyguardShowing()) {
+ if (mStatusBar.isKeyguardShowing()) {
Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
"No heads up");
mHomeBlockedThisTouch = true;
@@ -428,18 +437,18 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mPhoneStatusBar.awakenDreams();
+ mStatusBar.awakenDreams();
break;
}
return false;
}
private void onVerticalChanged(boolean isVertical) {
- mPhoneStatusBar.setQsScrimEnabled(!isVertical);
+ mStatusBar.setQsScrimEnabled(!isVertical);
}
private boolean onNavigationTouch(View v, MotionEvent event) {
- mPhoneStatusBar.checkUserAutohide(v, event);
+ mStatusBar.checkUserAutohide(v, event);
return false;
}
@@ -450,7 +459,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
}
MetricsLogger.action(getContext(), MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mAssistManager.startAssist(new Bundle() /* args */);
- mPhoneStatusBar.awakenDreams();
+ mStatusBar.awakenDreams();
if (mNavigationBarView != null) {
mNavigationBarView.abortCurrentGesture();
}
@@ -478,7 +487,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
LatencyTracker.getInstance(getContext()).onActionStart(
LatencyTracker.ACTION_TOGGLE_RECENTS);
}
- mPhoneStatusBar.awakenDreams();
+ mStatusBar.awakenDreams();
mCommandQueue.toggleRecentApps();
}
@@ -546,16 +555,43 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
private boolean onLongPressRecents() {
if (mRecents == null || !ActivityManager.supportsMultiWindow()
- || !mDivider.getView().getSnapAlgorithm()
- .isSplitScreenFeasible()) {
+ || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()) {
return false;
}
- return mPhoneStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
+ return mStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
}
- // ----- Methods that PhoneStatusBar talks to (should be minimized) -----
+ private void onAccessibilityClick(View v) {
+ mAccessibilityManager.notifyAccessibilityButtonClicked();
+ }
+
+ private boolean onAccessibilityLongClick(View v) {
+ // TODO(b/34720082): Target service selection via long click
+ android.widget.Toast.makeText(getContext(), "Service selection coming soon...",
+ android.widget.Toast.LENGTH_LONG).show();
+ return true;
+ }
+
+ private void updateAccessibilityServicesState() {
+ final List<AccessibilityServiceInfo> services =
+ mAccessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ int requestingServices = 0;
+ for (int i = services.size() - 1; i >= 0; --i) {
+ AccessibilityServiceInfo info = services.get(i);
+ if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
+ requestingServices++;
+ }
+ }
+
+ final boolean showAccessibilityButton = requestingServices >= 1;
+ final boolean targetSelection = requestingServices >= 2;
+ mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
+ }
+
+ // ----- Methods that StatusBar talks to (should be minimized) -----
public void setLightBarController(LightBarController lightBarController) {
mLightBarController = lightBarController;
@@ -585,7 +621,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
}
public void checkNavBarModes() {
- mPhoneStatusBar.checkBarMode(mNavigationBarMode,
+ mStatusBar.checkBarMode(mNavigationBarMode,
mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 228e8ea843b5..ee9a791585c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -29,6 +29,7 @@ import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
@@ -87,7 +88,11 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
mTaskSwitcherDetector = new GestureDetector(context, this);
- TunerService.get(context).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
+ Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
+ }
+
+ public void destroy() {
+ Dependency.get(TunerService.class).removeTunable(this);
}
public void setComponents(RecentsComponent recentsComponent, Divider divider,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index f04a9ee71404..5fb99dabfeab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.Display;
@@ -29,6 +30,7 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Space;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
@@ -47,6 +49,8 @@ public class NavigationBarInflaterView extends FrameLayout
private static final String TAG = "NavBarInflater";
public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
+ public static final String NAV_BAR_LEFT = "sysui_nav_bar_left";
+ public static final String NAV_BAR_RIGHT = "sysui_nav_bar_right";
public static final String MENU_IME = "menu_ime";
public static final String BACK = "back";
@@ -55,6 +59,8 @@ public class NavigationBarInflaterView extends FrameLayout
public static final String NAVSPACE = "space";
public static final String CLIPBOARD = "clipboard";
public static final String KEY = "key";
+ public static final String LEFT = "left";
+ public static final String RIGHT = "right";
public static final String GRAVITY_SEPARATOR = ";";
public static final String BUTTON_SEPARATOR = ",";
@@ -130,14 +136,16 @@ public class NavigationBarInflaterView extends FrameLayout
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
- PluginManager.getInstance(getContext()).addPluginListener(NavBarButtonProvider.ACTION, this,
+ Dependency.get(TunerService.class).addTunable(this, NAV_BAR_VIEWS, NAV_BAR_LEFT,
+ NAV_BAR_RIGHT);
+ Dependency.get(PluginManager.class).addPluginListener(NavBarButtonProvider.ACTION, this,
NavBarButtonProvider.VERSION, true /* Allow multiple */);
}
@Override
protected void onDetachedFromWindow() {
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
+ Dependency.get(PluginManager.class).removePluginListener(this);
super.onDetachedFromWindow();
}
@@ -148,6 +156,9 @@ public class NavigationBarInflaterView extends FrameLayout
clearViews();
inflateLayout(newValue);
}
+ } else if (NAV_BAR_LEFT.equals(key) || NAV_BAR_RIGHT.equals(key)) {
+ clearViews();
+ inflateLayout(mCurrentLayout);
}
}
@@ -268,6 +279,13 @@ public class NavigationBarInflaterView extends FrameLayout
boolean landscape) {
View v = null;
String button = extractButton(buttonSpec);
+ if (LEFT.equals(button)) {
+ buttonSpec = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE);
+ button = extractButton(buttonSpec);
+ } else if (RIGHT.equals(button)) {
+ buttonSpec = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME);
+ button = extractButton(buttonSpec);
+ }
// Let plugins go first so they can override a standard view if they want.
for (NavBarButtonProvider provider : mPlugins) {
v = provider.createView(buttonSpec, parent);
@@ -291,7 +309,14 @@ public class NavigationBarInflaterView extends FrameLayout
v = inflater.inflate(R.layout.custom_key, parent, false);
((KeyButtonView) v).setCode(code);
if (uri != null) {
- ((KeyButtonView) v).loadAsync(uri);
+ if (uri.contains(":")) {
+ ((KeyButtonView) v).loadAsync(Icon.createWithContentUri(uri));
+ } else if (uri.contains("/")) {
+ int index = uri.indexOf('/');
+ String pkg = uri.substring(0, index);
+ int id = Integer.parseInt(uri.substring(index + 1));
+ ((KeyButtonView) v).loadAsync(Icon.createWithResource(pkg, id));
+ }
}
}
return v;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 319f124f0554..5d13289ef9cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -47,13 +46,13 @@ import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.phone.NavGesture;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -79,6 +78,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private int mCurrentRotation = -1;
boolean mShowMenu;
+ boolean mShowAccessibilityButton;
+ boolean mLongClickableAccessibilityButton;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
@@ -90,6 +91,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private KeyButtonDrawable mDockedIcon;
private KeyButtonDrawable mImeIcon;
private KeyButtonDrawable mMenuIcon;
+ private KeyButtonDrawable mAccessibilityIcon;
private GestureHelper mGestureHelper;
private DeadZone mDeadZone;
@@ -202,7 +204,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mVertical = false;
mShowMenu = false;
- mGestureHelper = new NavigationBarGestureHelper(context);
+
+ mShowAccessibilityButton = false;
+ mLongClickableAccessibilityButton = false;
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -215,6 +219,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
+ mButtonDispatchers.put(R.id.accessibility_button,
+ new ButtonDispatcher(R.id.accessibility_button));
}
public BarTransitions getBarTransitions() {
@@ -289,6 +295,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return mButtonDispatchers.get(R.id.ime_switcher);
}
+ public ButtonDispatcher getAccessibilityButton() {
+ return mButtonDispatchers.get(R.id.accessibility_button);
+ }
+
public SparseArray<ButtonDispatcher> getButtonDispatchers() {
return mButtonDispatchers;
}
@@ -322,6 +332,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mRecentIcon = getDrawable(ctx,
R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
+ mAccessibilityIcon = getDrawable(ctx, R.drawable.ic_sysbar_accessibility_button,
+ R.drawable.ic_sysbar_accessibility_button_dark);
Context darkContext = new ContextThemeWrapper(ctx, R.style.DualToneDarkTheme);
Context lightContext = new ContextThemeWrapper(ctx, R.style.DualToneLightTheme);
@@ -413,6 +425,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
setMenuVisibility(mShowMenu, true);
getMenuButton().setImageDrawable(mMenuIcon);
+ setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
+ getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
+
setDisabledFlags(mDisabledFlags, true);
mBarTransitions.reapplyDarkIntensity();
@@ -519,13 +534,25 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mShowMenu = show;
- // Only show Menu if IME switcher not shown.
- final boolean shouldShow = mShowMenu &&
+ // Only show Menu if IME switcher and Accessibility button not shown.
+ final boolean shouldShow = mShowMenu && !mShowAccessibilityButton &&
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
}
+ public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
+ mShowAccessibilityButton = visible;
+ mLongClickableAccessibilityButton = longClickable;
+ if (visible) {
+ // Accessibility button overrides Menu button.
+ setMenuVisibility(false, true);
+ }
+
+ getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ getAccessibilityButton().setLongClickable(longClickable);
+ }
+
@Override
public void onFinishInflate() {
mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
@@ -553,8 +580,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
@Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
- throws RemoteException {
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
+ boolean isHomeStackResizable) throws RemoteException {
}
@Override
@@ -635,6 +662,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
private void updateTaskSwitchHelper() {
+ if (mGestureHelper == null) return;
boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
mGestureHelper.setBarState(mVertical, isRtl);
}
@@ -754,14 +782,18 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- PluginManager.getInstance(getContext()).addPluginListener(NavGesture.ACTION, this,
+ onPluginDisconnected(null); // Create default gesture helper
+ Dependency.get(PluginManager.class).addPluginListener(NavGesture.ACTION, this,
NavGesture.VERSION, false /* Only one */);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- PluginManager.getInstance(getContext()).removePluginListener(this);
+ Dependency.get(PluginManager.class).removePluginListener(this);
+ if (mGestureHelper != null) {
+ mGestureHelper.destroy();
+ }
}
@Override
@@ -774,6 +806,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
public void onPluginDisconnected(NavGesture plugin) {
NavigationBarGestureHelper defaultHelper = new NavigationBarGestureHelper(getContext());
defaultHelper.setComponents(mRecentsComponent, mDivider, this);
+ if (mGestureHelper != null) {
+ mGestureHelper.destroy();
+ }
mGestureHelper = defaultHelper;
updateTaskSwitchHelper();
}
@@ -784,7 +819,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
final Point size = new Point();
mDisplay.getRealSize(size);
- pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this)
+ pw.println(String.format(" this: " + StatusBar.viewInfo(this)
+ " " + visibilityToString(getVisibility())));
getWindowVisibleDisplayFrame(r);
@@ -808,6 +843,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
dumpButton(pw, "home", getHomeButton());
dumpButton(pw, "rcnt", getRecentsButton());
dumpButton(pw, "menu", getMenuButton());
+ dumpButton(pw, "a11y", getAccessibilityButton());
pw.println(" }");
}
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 345dcbdc61c4..0386398ddae5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -33,7 +33,7 @@ public class NotificationIconAreaController {
private int mIconHPadding;
private int mIconTint = Color.WHITE;
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
protected View mNotificationIconArea;
private NotificationIconContainer mNotificationIcons;
private NotificationIconContainer mShelfIcons;
@@ -41,8 +41,8 @@ public class NotificationIconAreaController {
private NotificationStackScrollLayout mNotificationScrollLayout;
private Context mContext;
- public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
- mPhoneStatusBar = phoneStatusBar;
+ public NotificationIconAreaController(Context context, StatusBar statusBar) {
+ mStatusBar = statusBar;
mNotificationColorUtil = NotificationColorUtil.getInstance(context);
mContext = context;
@@ -64,11 +64,11 @@ public class NotificationIconAreaController {
mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
R.id.notificationIcons);
- NotificationShelf shelf = mPhoneStatusBar.getNotificationShelf();
+ NotificationShelf shelf = mStatusBar.getNotificationShelf();
mShelfIcons = shelf.getShelfIcons();
shelf.setCollapsedIcons(mNotificationIcons);
- mNotificationScrollLayout = mPhoneStatusBar.getNotificationScrollLayout();
+ mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
}
public void onDensityOrFontScaleChanged(Context context) {
@@ -124,7 +124,7 @@ public class NotificationIconAreaController {
}
protected int getHeight() {
- return mPhoneStatusBar.getStatusBarHeight();
+ return mStatusBar.getStatusBarHeight();
}
protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
@@ -133,7 +133,7 @@ public class NotificationIconAreaController {
&& !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) {
return false;
}
- if (!PhoneStatusBar.isTopLevelChild(entry)) {
+ if (!StatusBar.isTopLevelChild(entry)) {
return false;
}
if (entry.row.getVisibility() == View.GONE) {
@@ -154,18 +154,6 @@ public class NotificationIconAreaController {
NotificationShelf.SHOW_AMBIENT_ICONS);
applyNotificationIconsTint();
- ArrayList<NotificationData.Entry> activeNotifications
- = notificationData.getActiveNotifications();
- for (int i = 0; i < activeNotifications.size(); i++) {
- NotificationData.Entry entry = activeNotifications.get(i);
- boolean isPreL = Boolean.TRUE.equals(entry.expandedIcon.getTag(R.id.icon_is_pre_L));
- boolean colorize = !isPreL
- || NotificationUtils.isGrayscale(entry.expandedIcon, mNotificationColorUtil);
- if (colorize) {
- int color = entry.getContrastedColor(mContext);
- entry.expandedIcon.setImageTintList(ColorStateList.valueOf(color));
- }
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index c25a45cc37e0..571ae2653948 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -104,6 +104,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private float mOpenedAmount = 0.0f;
private float mVisualOverflowAdaption;
private boolean mDisallowNextAnimation;
+ private boolean mAnimationsEnabled = true;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -255,7 +256,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
iconState.visibleState = StatusBarIconView.STATE_ICON;
if (firstOverflowIndex == -1 && (isAmbient
|| (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart)))) {
- firstOverflowIndex = noOverflowAfter ? i - 1 : i;
+ firstOverflowIndex = noOverflowAfter && !isAmbient ? i - 1 : i;
int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
visualOverflowStart = overflowStart + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT)
- totalDotLength / 2
@@ -422,6 +423,20 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
return mIconSize;
}
+ public void setAnimationsEnabled(boolean enabled) {
+ if (!enabled && mAnimationsEnabled) {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ ViewState childState = mIconStates.get(child);
+ if (childState != null) {
+ childState.cancelAnimations(child);
+ childState.applyToView(child);
+ }
+ }
+ }
+ mAnimationsEnabled = enabled;
+ }
+
public class IconState extends ViewState {
public float iconAppearAmount = 1.0f;
public float clampedAppearAmount = 1.0f;
@@ -438,52 +453,59 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
StatusBarIconView icon = (StatusBarIconView) view;
boolean animate = false;
AnimationProperties animationProperties = null;
- if (justAdded) {
- super.applyToView(icon);
- icon.setAlpha(0.0f);
- icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, false /* animate */);
- animationProperties = ADD_ICON_PROPERTIES;
- animate = true;
- } else if (visibleState != icon.getVisibleState()) {
- animationProperties = DOT_ANIMATION_PROPERTIES;
- animate = true;
- }
- if (!animate && mAddAnimationStartIndex >= 0
- && indexOfChild(view) >= mAddAnimationStartIndex
- && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+ boolean animationsAllowed = mAnimationsEnabled && !mDisallowNextAnimation;
+ if (animationsAllowed) {
+ if (justAdded) {
+ super.applyToView(icon);
+ if (iconAppearAmount != 0.0f) {
+ icon.setAlpha(0.0f);
+ icon.setVisibleState(StatusBarIconView.STATE_HIDDEN,
+ false /* animate */);
+ animationProperties = ADD_ICON_PROPERTIES;
+ animate = true;
+ }
+ } else if (visibleState != icon.getVisibleState()) {
+ animationProperties = DOT_ANIMATION_PROPERTIES;
+ animate = true;
+ }
+ if (!animate && mAddAnimationStartIndex >= 0
+ && indexOfChild(view) >= mAddAnimationStartIndex
+ && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
|| visibleState != StatusBarIconView.STATE_HIDDEN)) {
- animationProperties = DOT_ANIMATION_PROPERTIES;
- animate = true;
- }
- if (needsCannedAnimation) {
- AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
- animationFilter.reset();
- animationFilter.combineFilter(ICON_ANIMATION_PROPERTIES.getAnimationFilter());
- mTempProperties.resetCustomInterpolators();
- mTempProperties.combineCustomInterpolators(ICON_ANIMATION_PROPERTIES);
- if (animationProperties != null) {
- animationFilter.combineFilter(animationProperties.getAnimationFilter());
- mTempProperties.combineCustomInterpolators(animationProperties);
+ animationProperties = DOT_ANIMATION_PROPERTIES;
+ animate = true;
+ }
+ if (needsCannedAnimation) {
+ AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
+ animationFilter.reset();
+ animationFilter.combineFilter(
+ ICON_ANIMATION_PROPERTIES.getAnimationFilter());
+ mTempProperties.resetCustomInterpolators();
+ mTempProperties.combineCustomInterpolators(ICON_ANIMATION_PROPERTIES);
+ if (animationProperties != null) {
+ animationFilter.combineFilter(animationProperties.getAnimationFilter());
+ mTempProperties.combineCustomInterpolators(animationProperties);
+ }
+ animationProperties = mTempProperties;
+ animationProperties.setDuration(CANNED_ANIMATION_DURATION);
+ animate = true;
+ mCannedAnimationStartIndex = indexOfChild(view);
+ }
+ if (!animate && mCannedAnimationStartIndex >= 0
+ && indexOfChild(view) > mCannedAnimationStartIndex
+ && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+ || visibleState != StatusBarIconView.STATE_HIDDEN)) {
+ AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
+ animationFilter.reset();
+ animationFilter.animateX();
+ mTempProperties.resetCustomInterpolators();
+ animationProperties = mTempProperties;
+ animationProperties.setDuration(CANNED_ANIMATION_DURATION);
+ animate = true;
}
- animationProperties = mTempProperties;
- animationProperties.setDuration(CANNED_ANIMATION_DURATION);
- animate = true;
- mCannedAnimationStartIndex = indexOfChild(view);
- }
- if (!animate && mCannedAnimationStartIndex >= 0
- && indexOfChild(view) > mCannedAnimationStartIndex
- && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
- || visibleState != StatusBarIconView.STATE_HIDDEN)) {
- AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
- animationFilter.reset();
- animationFilter.animateX();
- mTempProperties.resetCustomInterpolators();
- animationProperties = mTempProperties;
- animationProperties.setDuration(CANNED_ANIMATION_DURATION);
- animate = true;
}
- icon.setVisibleState(visibleState);
- if (animate && !mDisallowNextAnimation) {
+ icon.setVisibleState(visibleState, animationsAllowed);
+ if (animate) {
animateTo(icon, animationProperties);
} else {
super.applyToView(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3bdd5e5c6db9..5da3a101b4bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -26,6 +26,7 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -43,6 +44,7 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
@@ -92,7 +94,7 @@ public class NotificationPanelView extends PanelView implements
public static final long DOZE_ANIMATION_DURATION = 700;
- private KeyguardAffordanceHelper mAfforanceHelper;
+ private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
private QS mQs;
@@ -137,6 +139,7 @@ public class NotificationPanelView extends PanelView implements
protected int mQsMinExpansionHeight;
protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
+ private boolean mQsOverscrollExpansionEnabled;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
private float mLastOverscroll;
@@ -212,14 +215,17 @@ public class NotificationPanelView extends PanelView implements
private int mIndicationBottomPadding;
private boolean mIsFullWidth;
private boolean mDark;
+ private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
mFalsingManager = FalsingManager.getInstance(context);
+ mQsOverscrollExpansionEnabled =
+ getResources().getBoolean(R.bool.config_enableQuickSettingsOverscrollExpansion);
}
- public void setStatusBar(PhoneStatusBar bar) {
+ public void setStatusBar(StatusBar bar) {
mStatusBar = bar;
}
@@ -239,8 +245,8 @@ public class NotificationPanelView extends PanelView implements
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
- mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
- mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
+ mAffordanceHelper = new KeyguardAffordanceHelper(this, getContext());
+ mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
mLastOrientation = getResources().getConfiguration().orientation;
mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
@@ -516,7 +522,7 @@ public class NotificationPanelView extends PanelView implements
mBlockTouches = false;
mUnlockIconActive = false;
if (!mLaunchingAffordance) {
- mAfforanceHelper.reset(false);
+ mAffordanceHelper.reset(false);
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
}
closeQs();
@@ -596,7 +602,8 @@ public class NotificationPanelView extends PanelView implements
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
return true;
}
- if (!isFullyCollapsed() && onQsIntercept(event)) {
+
+ if (mQsOverscrollExpansionEnabled && !isFullyCollapsed() && onQsIntercept(event)) {
return true;
}
return super.onInterceptTouchEvent(event);
@@ -710,10 +717,9 @@ public class NotificationPanelView extends PanelView implements
private void logQsSwipeDown(float y) {
float vel = getCurrentQSVelocity();
final int gesture = mStatusBarState == StatusBarState.KEYGUARD
- ? EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS
- : EventLogConstants.SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS;
- EventLogTags.writeSysuiLockscreenGesture(
- gesture,
+ ? MetricsEvent.ACTION_LS_QS
+ : MetricsEvent.ACTION_SHADE_QS_PULL;
+ mLockscreenGestureLogger.write(gesture,
(int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
(int) (vel / mStatusBar.getDisplayDensity()));
}
@@ -762,14 +768,17 @@ public class NotificationPanelView extends PanelView implements
}
if ((!mIsExpanding || mHintAnimationRunning)
&& !mQsExpanded
- && mStatusBar.getBarState() != StatusBarState.SHADE) {
- mAfforanceHelper.onTouchEvent(event);
+ && mStatusBar.getBarState() != StatusBarState.SHADE
+ && !mDozing) {
+ mAffordanceHelper.onTouchEvent(event);
}
if (mOnlyAffordanceInThisMotion) {
return true;
}
mHeadsUpTouchHelper.onTouchEvent(event);
- if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
+
+ if (mQsOverscrollExpansionEnabled && !mHeadsUpTouchHelper.isTrackingHeadsUp()
+ && handleQsTouch(event)) {
return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -881,7 +890,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected boolean shouldGestureIgnoreXTouchSlop(float x, float y) {
- return !mAfforanceHelper.isOnAffordanceIcon(x, y);
+ return !mAffordanceHelper.isOnAffordanceIcon(x, y);
}
private void onQsTouch(MotionEvent event) {
@@ -952,6 +961,10 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
+ if (!mQsOverscrollExpansionEnabled) {
+ return;
+ }
+
cancelQsAnimation();
if (!mQsExpansionEnabled) {
amount = 0f;
@@ -966,6 +979,10 @@ public class NotificationPanelView extends PanelView implements
@Override
public void flingTopOverscroll(float velocity, boolean open) {
+ if (!mQsOverscrollExpansionEnabled) {
+ return;
+ }
+
mLastOverscroll = 0f;
mQsExpansionFromOverscroll = false;
setQsExpansion(mQsExpansionHeight);
@@ -1722,7 +1739,7 @@ public class NotificationPanelView extends PanelView implements
}
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
- mAfforanceHelper.animateHideLeftRightIcon();
+ mAffordanceHelper.animateHideLeftRightIcon();
}
mNotificationStackScroller.onPanelTrackingStarted();
}
@@ -1739,7 +1756,7 @@ public class NotificationPanelView extends PanelView implements
if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
if (!mHintAnimationRunning) {
- mAfforanceHelper.reset(true);
+ mAffordanceHelper.reset(true);
}
}
if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
@@ -1785,7 +1802,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mAfforanceHelper.onConfigurationChanged();
+ mAffordanceHelper.onConfigurationChanged();
if (newConfig.orientation != mLastOrientation) {
resetVerticalPanelPosition();
}
@@ -1806,7 +1823,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
if (layoutDirection != mOldLayoutDirection) {
- mAfforanceHelper.onRtlPropertiesChanged();
+ mAffordanceHelper.onRtlPropertiesChanged();
mOldLayoutDirection = layoutDirection;
}
}
@@ -1818,9 +1835,7 @@ public class NotificationPanelView extends PanelView implements
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
} else if (mQsExpansionEnabled) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_TAP_TO_OPEN_QS,
- 0, 0);
+ mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
flingSettings(0 /* vel */, true /* expand */, null, true /* isClick */);
}
}
@@ -1835,8 +1850,7 @@ public class NotificationPanelView extends PanelView implements
int lengthDp = Math.abs((int) (translation / displayDensity));
int velocityDp = Math.abs((int) (vel / displayDensity));
if (start) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
+ mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
mFalsingManager.onLeftAffordanceOn();
if (mFalsingManager.shouldEnforceBouncer()) {
@@ -1854,9 +1868,7 @@ public class NotificationPanelView extends PanelView implements
} else {
if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
mLastCameraLaunchSource)) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA,
- lengthDp, velocityDp);
+ mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
}
mFalsingManager.onCameraOn();
if (mFalsingManager.shouldEnforceBouncer()) {
@@ -1938,7 +1950,7 @@ public class NotificationPanelView extends PanelView implements
return;
}
mHintAnimationRunning = true;
- mAfforanceHelper.startHintAnimation(rightIcon, new Runnable() {
+ mAffordanceHelper.startHintAnimation(rightIcon, new Runnable() {
@Override
public void run() {
mHintAnimationRunning = false;
@@ -2151,8 +2163,8 @@ public class NotificationPanelView extends PanelView implements
switch (mStatusBar.getBarState()) {
case StatusBarState.KEYGUARD:
if (!mDozingOnDown) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT,
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_HINT,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
startUnlockHintAnimation();
}
@@ -2351,7 +2363,7 @@ public class NotificationPanelView extends PanelView implements
} else {
animate = false;
}
- mAfforanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+ mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
}
public void onAffordanceLaunchEnded() {
@@ -2397,7 +2409,7 @@ public class NotificationPanelView extends PanelView implements
? null : resolveInfo.activityInfo.packageName;
return packageToLaunch != null &&
(keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
- !mAfforanceHelper.isSwipingInProgress();
+ !mAffordanceHelper.isSwipingInProgress();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 18e394e2836a..48a8329d085e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -33,6 +33,7 @@ import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
@@ -55,12 +56,13 @@ public abstract class PanelView extends FrameLayout {
private static final int PEEK_ANIMATION_DURATION = 360;
private long mDownTime;
private float mMinExpandHeight;
+ private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
- protected PhoneStatusBar mStatusBar;
+ protected StatusBar mStatusBar;
protected HeadsUpManager mHeadsUpManager;
private float mPeekHeight;
@@ -110,6 +112,11 @@ public abstract class PanelView extends FrameLayout {
private float mInitialTouchX;
private boolean mTouchDisabled;
+ /**
+ * Whether or not the PanelView can be expanded or collapsed with a drag.
+ */
+ private boolean mNotificationsDragEnabled;
+
private Interpolator mBounceInterpolator;
protected KeyguardBottomAreaView mKeyguardBottomArea;
@@ -190,6 +197,8 @@ public abstract class PanelView extends FrameLayout {
0.84f /* y2 */);
mBounceInterpolator = new BounceInterpolator();
mFalsingManager = FalsingManager.getInstance(context);
+ mNotificationsDragEnabled =
+ getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
}
protected void loadDimens() {
@@ -232,6 +241,15 @@ public abstract class PanelView extends FrameLayout {
return false;
}
+ // If dragging should not expand the notifications shade, then return false.
+ if (!mNotificationsDragEnabled) {
+ if (mTracking) {
+ // Turn off tracking if it's on or the shade can get stuck in the down position.
+ onTrackingStopped(true /* expand */);
+ }
+ return false;
+ }
+
// On expanding, single mouse click expands the panel instead of dragging.
if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (event.getAction() == MotionEvent.ACTION_UP) {
@@ -423,8 +441,8 @@ public abstract class PanelView extends FrameLayout {
float displayDensity = mStatusBar.getDisplayDensity();
int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
int velocityDp = (int) Math.abs(vel / displayDensity);
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK,
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_UNLOCK,
heightDp, velocityDp);
}
fling(vel, expand, isFalseTouch(x, y));
@@ -487,7 +505,7 @@ public abstract class PanelView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mInstantExpanding
+ if (mInstantExpanding || !mNotificationsDragEnabled
|| (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
return 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 c80b3ad47a4a..7e08812435d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -30,10 +30,10 @@ import com.android.systemui.R;
public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
- private static final boolean DEBUG = PhoneStatusBar.DEBUG;
+ private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
- PhoneStatusBar mBar;
+ StatusBar mBar;
boolean mIsFullyOpenedPanel = false;
private final PhoneStatusBarTransitions mBarTransitions;
@@ -59,7 +59,7 @@ public class PhoneStatusBarView extends PanelBar {
return mBarTransitions;
}
- public void setBar(PhoneStatusBar bar) {
+ public void setBar(StatusBar bar) {
mBar = bar;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 2f76cb1c0709..a1022c4757a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -71,7 +71,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
public static final String TILES_SETTING = Secure.QS_TILES;
private final Context mContext;
- private final PhoneStatusBar mStatusBar;
+ private final StatusBar mStatusBar;
private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
protected final ArrayList<String> mTileSpecs = new ArrayList<>();
private final TileServices mServices;
@@ -81,7 +81,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
private final StatusBarIconController mIconController;
private int mCurrentUser;
- public QSTileHost(Context context, PhoneStatusBar statusBar,
+ public QSTileHost(Context context, StatusBar statusBar,
StatusBarIconController iconController) {
mIconController = iconController;
mContext = context;
@@ -89,7 +89,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
mServices = new TileServices(this, Dependency.get(Dependency.BG_LOOPER));
- TunerService.get(mContext).addTunable(this, TILES_SETTING);
+ Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);
// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
mAutoTiles = new AutoTileManager(context, this);
}
@@ -101,7 +101,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
public void destroy() {
mTiles.values().forEach(tile -> tile.destroy());
mAutoTiles.destroy();
- TunerService.get(mContext).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
mServices.destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 9e9380295f0c..4307a2e1ac6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -21,14 +21,17 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.icu.text.NumberFormat;
import android.os.UserManager;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.AttributeSet;
+import android.util.SparseBooleanArray;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -55,6 +58,8 @@ import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -63,10 +68,7 @@ import com.android.systemui.tuner.TunerService;
public class QuickStatusBarHeader extends BaseStatusBarHeader implements
NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
- BatteryStateChangeCallback {
-
- private static final String TAG = "QuickStatusBarHeader";
-
+ BatteryStateChangeCallback, SignalCallback {
private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
private ActivityStarter mActivityStarter;
@@ -96,16 +98,21 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
private boolean mShowEmergencyCallsOnly;
protected MultiUserSwitch mMultiUserSwitch;
private ImageView mMultiUserAvatar;
-
+ private boolean mAlwaysShowMultiUserSwitch;
private TouchAnimator mAnimator;
protected TouchAnimator mSettingsAlpha;
private float mExpansionAmount;
protected QSTileHost mHost;
+
protected View mEdit;
+ private boolean mShowEditIcon;
+
private boolean mShowFullAlarm;
private float mDateTimeTranslation;
private TextView mBatteryLevel;
+ private SparseBooleanArray mRoamingsBySubId = new SparseBooleanArray();
+ private boolean mIsRoaming;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -114,25 +121,37 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ Resources res = getResources();
mEmergencyOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
+ mShowEditIcon = res.getBoolean(R.bool.config_showQuickSettingsEditingIcon);
+
mEdit = findViewById(android.R.id.edit);
- findViewById(android.R.id.edit).setOnClickListener(view ->
- Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
- mQsPanel.showEdit(view)));
+ mEdit.setVisibility(mShowEditIcon ? VISIBLE : GONE);
+
+ if (mShowEditIcon) {
+ findViewById(android.R.id.edit).setOnClickListener(view ->
+ Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
+ mQsPanel.showEdit(view)));
+ }
mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
mDateTimeGroup.setPivotX(0);
mDateTimeGroup.setPivotY(0);
- mDateTimeTranslation = getResources().getDimension(R.dimen.qs_date_time_translation);
- mShowFullAlarm = getResources().getBoolean(R.bool.quick_settings_show_full_alarm);
+ mDateTimeTranslation = res.getDimension(R.dimen.qs_date_time_translation);
+ mShowFullAlarm = res.getBoolean(R.bool.quick_settings_show_full_alarm);
mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
+ mExpandIndicator.setVisibility(
+ res.getBoolean(R.bool.config_showQuickSettingsExpandIndicator)
+ ? VISIBLE : GONE);
mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
+ mHeaderQsPanel.setVisibility(res.getBoolean(R.bool.config_showQuickSettingsRow)
+ ? VISIBLE : GONE);
mSettingsButton = (SettingsButton) findViewById(R.id.settings_button);
mSettingsContainer = findViewById(R.id.settings_button_container);
@@ -146,6 +165,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+ mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher);
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
@@ -157,11 +177,15 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
// Set the light/dark theming on the header status UI to match the current theme.
SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster);
int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
- float intensity = colorForeground / (float) Color.WHITE;
+ float intensity = colorForeground == Color.WHITE ? 0 : 1;
cluster.setIconTint(colorForeground, intensity, new Rect(0, 0, 0, 0));
BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
battery.setRawColors(colorForeground, colorSecondary);
+
+ mNextAlarmController = Dependency.get(NextAlarmController.class);
+ mUserInfoController = Dependency.get(UserInfoController.class);
+ mActivityStarter = Dependency.get(ActivityStarter.class);
}
@Override
@@ -191,11 +215,8 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
updateSettingsAnimator();
}
- protected void updateSettingsAnimator() {
- mSettingsAlpha = new TouchAnimator.Builder()
- .addFloat(mEdit, "alpha", 0, 1)
- .addFloat(mMultiUserSwitch, "alpha", 0, 1)
- .build();
+ private void updateSettingsAnimator() {
+ mSettingsAlpha = createSettingsAlphaAnimator();
final boolean isRtl = isLayoutRtl();
if (isRtl && mDateTimeGroup.getWidth() == 0) {
@@ -212,6 +233,27 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
}
}
+ @Nullable
+ private TouchAnimator createSettingsAlphaAnimator() {
+ // If the settings icon is not shown and the user switcher is always shown, then there
+ // is nothing to animate.
+ if (!mShowEditIcon && mAlwaysShowMultiUserSwitch) {
+ return null;
+ }
+
+ TouchAnimator.Builder animatorBuilder = new TouchAnimator.Builder();
+
+ if (mShowEditIcon) {
+ animatorBuilder.addFloat(mEdit, "alpha", 0, 1);
+ }
+
+ if (!mAlwaysShowMultiUserSwitch) {
+ animatorBuilder.addFloat(mMultiUserSwitch, "alpha", 0, 1);
+ }
+
+ return animatorBuilder.build();
+ }
+
@Override
public int getCollapsedHeight() {
return getHeight();
@@ -252,7 +294,10 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
mExpansionAmount = headerExpansionFraction;
updateDateTimePosition();
mAnimator.setPosition(headerExpansionFraction);
- mSettingsAlpha.setPosition(headerExpansionFraction);
+
+ if (mSettingsAlpha != null) {
+ mSettingsAlpha.setPosition(headerExpansionFraction);
+ }
updateAlarmVisibilities();
@@ -260,14 +305,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mNextAlarmController = Dependency.get(NextAlarmController.class);
- mUserInfoController = Dependency.get(UserInfoController.class);
- mActivityStarter = Dependency.get(ActivityStarter.class);
- }
-
- @Override
@VisibleForTesting
public void onDetachedFromWindow() {
setListening(false);
@@ -301,21 +338,26 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
});
}
- protected void updateVisibilities() {
+ private void updateVisibilities() {
updateAlarmVisibilities();
updateDateTimePosition();
- mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
+ mEmergencyOnly.setVisibility(mExpanded && (mShowEmergencyCallsOnly || mIsRoaming)
? View.VISIBLE : View.INVISIBLE);
mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
- mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo
+
+ mMultiUserSwitch.setVisibility((mExpanded || mAlwaysShowMultiUserSwitch)
+ && mMultiUserSwitch.hasMultipleUsers() && !isDemo
? View.VISIBLE : View.INVISIBLE);
- mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+
+ if (mShowEditIcon) {
+ mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+ }
}
private void updateDateTimePosition() {
- mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly
+ mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly || mIsRoaming
? mExpansionAmount * mDateTimeTranslation : 0);
}
@@ -325,11 +367,13 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
mUserInfoController.addCallback(this);
if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
Dependency.get(NetworkController.class).addEmergencyListener(this);
+ Dependency.get(NetworkController.class).addCallback(this);
}
} else {
mNextAlarmController.removeCallback(this);
mUserInfoController.removeCallback(this);
Dependency.get(NetworkController.class).removeEmergencyListener(this);
+ Dependency.get(NetworkController.class).removeCallback(this);
}
}
@@ -410,6 +454,28 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
// Don't care.
}
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+ int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
+ String description, boolean isWide, int subId, boolean roaming) {
+ mRoamingsBySubId.put(subId, roaming);
+ boolean isRoaming = calculateRoaming();
+ if (mIsRoaming != isRoaming) {
+ mIsRoaming = isRoaming;
+ mEmergencyOnly.setText(mIsRoaming ? R.string.accessibility_data_connection_roaming
+ : com.android.internal.R.string.emergency_calls_only);
+ if (mExpanded) {
+ updateEverything();
+ }
+ }
+ }
+
+ private boolean calculateRoaming() {
+ for (int i = 0; i < mRoamingsBySubId.size(); i++) {
+ if (mRoamingsBySubId.valueAt(i)) return true;
+ }
+ return false;
+ }
+
@Override
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
mMultiUserAvatar.setImageDrawable(picture);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 8fcbf38db2df..b30d3abc2375 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -23,13 +23,13 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.graphics.ColorUtils;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
-
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -49,7 +49,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
= new PathInterpolator(0f, 0, 0.7f, 1f);
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
= new PathInterpolator(0.3f, 0f, 0.8f, 1f);
- private static final float SCRIM_BEHIND_ALPHA = 0.62f;
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
@@ -66,7 +65,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private final View mHeadsUpScrim;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- protected float mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
+ protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
@@ -109,6 +108,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
mLightBarController = lightBarController;
+ mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
+
updateHeadsUpScrim(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 21c7ccdc0ec9..bffa14fb2296 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1,3 +1,5 @@
+
+
/*
* Copyright (C) 2010 The Android Open Source Project
*
@@ -69,12 +71,11 @@ import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -114,6 +115,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationMessagingUtil;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -127,8 +129,6 @@ import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.SystemUIApplication;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingLog;
@@ -141,6 +141,8 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
@@ -151,7 +153,6 @@ import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.DragDownHelper;
@@ -160,9 +161,13 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationContentView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.NotificationGuts;
+import com.android.systemui.statusbar.NotificationInfo;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.NotificationSnooze;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
@@ -171,7 +176,6 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -183,11 +187,9 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
@@ -197,17 +199,103 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
+import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
+import android.app.ActivityManager.StackId;
+import android.app.INotificationManager;
+import android.app.KeyguardManager;
+import android.app.NotificationChannel;
+import android.app.RemoteInput;
+import android.app.TaskStackBuilder;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.service.notification.NotificationListenerService;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.view.IWindowManager;
+import android.view.ViewAnimationUtils;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.DejankUtils;
+import com.android.systemui.RecentsComponent;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeGutsContent;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.util.NotificationChannels;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+import java.util.Stack;
+
+public class StatusBar extends SystemUI implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
- OnHeadsUpChangedListener, VisualStabilityManager.Callback {
- static final String TAG = "PhoneStatusBar";
- public static final boolean DEBUG = BaseStatusBar.DEBUG;
+ OnHeadsUpChangedListener, VisualStabilityManager.Callback, SnoozeListener,
+ CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
+ ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
+ ExpandableNotificationRow.OnExpandClickListener {
+ public static final boolean MULTIUSER_DEBUG = false;
+
+ public static final boolean ENABLE_REMOTE_INPUT =
+ SystemProperties.getBoolean("debug.enable_remote_input", true);
+ public static final boolean ENABLE_CHILD_NOTIFICATIONS
+ = SystemProperties.getBoolean("debug.child_notifs", true);
+ public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+ SystemProperties.getBoolean("debug.force_remoteinput_history", false);
+ private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
+
+ protected static final int MSG_SHOW_RECENT_APPS = 1019;
+ protected static final int MSG_HIDE_RECENT_APPS = 1020;
+ protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
+ protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
+ protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
+ protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
+ protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
+
+ protected static final boolean ENABLE_HEADS_UP = true;
+ protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
+
+ // Must match constant in Settings. Used to highlight preferences when linking to Settings.
+ private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
+ // Should match the values in PhoneWindowManager
+ public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
+ public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+
+ private static final String BANNER_ACTION_CANCEL =
+ "com.android.systemui.statusbar.banner_action_cancel";
+ private static final String BANNER_ACTION_SETUP =
+ "com.android.systemui.statusbar.banner_action_setup";
+ private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
+ = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
+ static final String TAG = "StatusBar";
+ public static final boolean DEBUG = false;
public static final boolean SPEW = false;
public static final boolean DUMPTRUCK = true; // extra dumpsys info
public static final boolean DEBUG_GESTURES = false;
@@ -299,6 +387,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
}
+ /**
+ * The {@link StatusBarState} of the status bar.
+ */
+ protected int mState;
+ protected boolean mBouncerShowing;
+ protected boolean mShowLockscreenNotifications;
+ protected boolean mAllowLockscreenRemoteInput;
+
PhoneStatusBarPolicy mIconPolicy;
VolumeComponent mVolumeComponent;
@@ -309,14 +405,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
int mNaturalBarHeight = -1;
- Display mDisplay;
Point mCurrentDisplaySize = new Point();
protected StatusBarWindowView mStatusBarWindow;
protected PhoneStatusBarView mStatusBarView;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected StatusBarWindowManager mStatusBarWindowManager;
- private UnlockMethodCache mUnlockMethodCache;
+ protected UnlockMethodCache mUnlockMethodCache;
private DozeServiceHost mDozeServiceHost;
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
@@ -415,6 +510,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
+ protected H mHandler = createHandler();
final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -510,8 +606,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
new ArraySet<>();
private long mLastVisibilityReportUptimeMs;
- private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
-
private Runnable mLaunchTransitionEndRunnable;
protected boolean mLaunchTransitionFadingAway;
private ExpandableNotificationRow mDraggedDownRow;
@@ -522,6 +616,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private Vibrator mVibrator;
private long[] mCameraLaunchGestureVibePattern;
+ private final int[] mTmpInt2 = new int[2];
+
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
@@ -608,12 +704,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
+ private NotificationMessagingUtil mMessagingUtil;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private UserSwitcherController mUserSwitcherController;
private NetworkController mNetworkController;
private KeyguardMonitorImpl mKeyguardMonitor;
private BatteryController mBatteryController;
- private DeviceProvisionedController mDeviceProvisionedController;
+ private LogMaker mStatusBarStateLog;
+ private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
final int N = array.size();
@@ -625,6 +723,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private final View.OnClickListener mGoToLockedShadeListener = v -> {
if (mState == StatusBarState.KEYGUARD) {
+ wakeUpIfDozing(SystemClock.uptimeMillis(), v);
goToLockedShade(null);
}
};
@@ -655,16 +754,157 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mAssistManager = Dependency.get(AssistManager.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
+ mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ mDisplay = mWindowManager.getDefaultDisplay();
updateDisplaySize();
mScrimSrcModeEnabled = mContext.getResources().getBoolean(
R.bool.config_status_bar_scrim_behind_use_src);
DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
- putComponent(PhoneStatusBar.class, this);
+ putComponent(StatusBar.class, this);
+
+ // start old BaseStatusBar.start().
+ mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
+ mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+
+ mNotificationData = new NotificationData(this);
+ mMessagingUtil = new NotificationMessagingUtil(mContext);
+
+ mAccessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+
+ mDreamManager = IDreamManager.Stub.asInterface(
+ ServiceManager.checkService(DreamService.DREAM_SERVICE));
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
+ mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
+ mSettingsObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+ false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+
+ mRecents = getComponent(Recents.class);
+
+ final Configuration currentConfig = mContext.getResources().getConfiguration();
+ mLocale = currentConfig.locale;
+ mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
+ mFontScale = currentConfig.fontScale;
+ mDensity = currentConfig.densityDpi;
+
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mLockPatternUtils = new LockPatternUtils(mContext);
+
+ // Connect in to the status bar manager service
+ mCommandQueue = getComponent(CommandQueue.class);
+ mCommandQueue.addCallbacks(this);
+
+ int[] switches = new int[9];
+ ArrayList<IBinder> binders = new ArrayList<IBinder>();
+ ArrayList<String> iconSlots = new ArrayList<>();
+ ArrayList<StatusBarIcon> icons = new ArrayList<>();
+ Rect fullscreenStackBounds = new Rect();
+ Rect dockedStackBounds = new Rect();
+ try {
+ mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
+ fullscreenStackBounds, dockedStackBounds);
+ } catch (RemoteException ex) {
+ // If the system process isn't there we're doomed anyway.
+ }
+
+ createAndAddWindows();
+
+ mSettingsObserver.onChange(false); // set up
+ disable(switches[0], switches[6], false /* animate */);
+ setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
+ fullscreenStackBounds, dockedStackBounds);
+ topAppWindowChanged(switches[2] != 0);
+ // StatusBarManagerService has a back up of IME token and it's restored here.
+ setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
+
+ // Set up the initial icon state
+ int N = iconSlots.size();
+ int viewIndex = 0;
+ for (int i=0; i < N; i++) {
+ setIcon(iconSlots.get(i), icons.get(i));
+ }
+
+ // Set up the initial notification state.
+ try {
+ mNotificationListener.registerAsSystemService(mContext,
+ new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to register notification listener", e);
+ }
+
- super.start(); // calls createAndAddWindows()
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
+ icons.size(),
+ switches[0],
+ switches[1],
+ switches[2],
+ switches[3]
+ ));
+ }
+
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ setHeadsUpUser(mCurrentUserId);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
+ mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+
+ IntentFilter internalFilter = new IntentFilter();
+ internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+ internalFilter.addAction(BANNER_ACTION_CANCEL);
+ internalFilter.addAction(BANNER_ACTION_SETUP);
+ mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
+ IntentFilter allUsersFilter = new IntentFilter();
+ allUsersFilter.addAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+ mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
+ null, null);
+ updateCurrentProfilesCache();
+
+ IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
+
+ mNonBlockablePkgs = new HashSet<String>();
+ Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_nonBlockableNotificationPackages));
+ // end old BaseStatusBar.start().
mMediaSessionManager
= (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -715,19 +955,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
inflateStatusBarWindow(context);
mStatusBarWindow.setService(this);
- mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- checkUserAutohide(v, event);
- checkRemoteInputOutside(event);
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (mExpandedVisible) {
- animateCollapsePanels();
- }
- }
- return mStatusBarWindow.onTouchEvent(event);
- }
- });
+ mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
R.id.notification_panel);
@@ -777,7 +1005,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
R.id.notification_stack_scroller);
mStackScroller.setLongPressListener(getNotificationLongClicker());
- mStackScroller.setPhoneStatusBar(this);
+ mStackScroller.setStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setOnGroupChangeListener(mStackScroller);
@@ -801,7 +1029,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
(KeyguardStatusView) mStatusBarWindow.findViewById(R.id.keyguard_status_view);
mKeyguardBottomArea =
(KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
- mKeyguardIndicationController = new KeyguardIndicationController(mContext,
+ mKeyguardIndicationController =
+ SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
(ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
@@ -860,7 +1089,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
initEmergencyCryptkeeperText();
- mKeyguardBottomArea.setPhoneStatusBar(this);
+ mKeyguardBottomArea.setStatusBar(this);
mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
createUserSwitcher();
@@ -989,6 +1218,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ /**
+ * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the
+ * background window of the status bar is clicked.
+ */
+ protected View.OnTouchListener getStatusBarWindowTouchListener() {
+ return (v, event) -> {
+ checkUserAutohide(v, event);
+ checkRemoteInputOutside(event);
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mExpandedVisible) {
+ animateCollapsePanels();
+ }
+ }
+ return mStatusBarWindow.onTouchEvent(event);
+ };
+ }
+
private void inflateShelf() {
mNotificationShelf =
(NotificationShelf) LayoutInflater.from(mContext).inflate(
@@ -999,9 +1245,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNotificationShelf.setStatusBarState(mState);
}
- @Override
protected void onDensityOrFontScaleChanged() {
- super.onDensityOrFontScaleChanged();
+ // start old BaseStatusBar.onDensityOrFontScaleChanged().
+ ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
+ for (int i = 0; i < activeNotifications.size(); i++) {
+ Entry entry = activeNotifications.get(i);
+ boolean exposedGuts = mNotificationGutsExposed != null
+ && entry.row.getGuts() == mNotificationGutsExposed;
+ entry.row.reInflateViews();
+ if (exposedGuts) {
+ mNotificationGutsExposed = entry.row.getGuts();
+ bindGuts(entry.row, mGutsMenuItem);
+ }
+ inflateViews(entry, mStackScroller);
+ }
+ // end old BaseStatusBar.onDensityOrFontScaleChanged().
mScrimController.onDensityOrFontScaleChanged();
mStatusBarView.onDensityOrFontScaleChanged();
if (mBrightnessMirrorController != null) {
@@ -1014,7 +1272,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
inflateEmptyShadeView();
updateEmptyShadeView();
mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
- // TODO: Bring these out of PhoneStatusBar.
+ // TODO: Bring these out of StatusBar.
((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
.onDensityOrFontScaleChanged();
Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
@@ -1160,16 +1418,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected void setZenMode(int mode) {
- super.setZenMode(mode);
+ // start old BaseStatusBar.setZenMode().
+ if (isDeviceProvisioned()) {
+ mZenMode = mode;
+ updateNotifications();
+ }
+ // end old BaseStatusBar.setZenMode().
if (mIconPolicy != null) {
mIconPolicy.setZenMode(mode);
}
}
protected void startKeyguard() {
- Trace.beginSection("PhoneStatusBar#startKeyguard");
+ Trace.beginSection("StatusBar#startKeyguard");
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mFingerprintUnlockController = new FingerprintUnlockController(mContext,
mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
@@ -1179,6 +1441,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mFingerprintUnlockController);
mKeyguardIndicationController.setStatusBarKeyguardViewManager(
mStatusBarKeyguardViewManager);
+ mKeyguardIndicationController.setUserInfoController(
+ Dependency.get(UserInfoController.class));
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
@@ -1207,7 +1471,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Trace.endSection();
}
- @Override
protected View getStatusBarView() {
return mStatusBarView;
}
@@ -1229,7 +1492,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mNaturalBarHeight;
}
- @Override
protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
if (mRecents == null) {
return false;
@@ -1240,7 +1502,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
} else {
Divider divider = getComponent(Divider.class);
- if (divider != null && divider.isMinimized()) {
+ if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
// Undocking from the minimized state is not supported
return false;
} else {
@@ -1277,7 +1539,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return new UserHandle(mCurrentUserId);
}
- @Override
public void addNotification(StatusBarNotification notification, RankingMap ranking,
Entry oldEntry) {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
@@ -1340,20 +1601,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected void updateNotificationRanking(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
updateNotifications();
}
- @Override
public void removeNotification(String key, RankingMap ranking) {
boolean deferRemoval = false;
if (mHeadsUpManager.isHeadsUp(key)) {
// A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
// sending look longer than it takes.
+ // Also we should not defer the removal if reordering isn't allowed since otherwise
+ // some notifications can't disappear before the panel is closed.
boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
- && !FORCE_REMOTE_INPUT_HISTORY;
+ && !FORCE_REMOTE_INPUT_HISTORY
+ || !mVisualStabilityManager.isReorderingAllowed();
deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
}
if (key.equals(mMediaNotificationKey)) {
@@ -1477,13 +1739,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected void performRemoveNotification(StatusBarNotification n) {
Entry entry = mNotificationData.get(n.getKey());
if (mRemoteInputController.isRemoteInputActive(entry)) {
mRemoteInputController.removeRemoteInput(entry, null);
}
- super.performRemoveNotification(n);
+ // start old BaseStatusBar.performRemoveNotification.
+ final String pkg = n.getPackageName();
+ final String tag = n.getTag();
+ final int id = n.getId();
+ final int userId = n.getUserId();
+ try {
+ mBarService.onNotificationClear(pkg, tag, id, userId);
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
+ removeNotification(n.getKey(), null);
+
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ // end old BaseStatusBar.performRemoveNotification.
}
private void updateNotificationShade() {
@@ -1618,7 +1895,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateEmptyShadeView();
updateQsExpansionEnabled();
- mShadeUpdates.check();
// Let's also update the icons
mIconController.updateNotificationIcons(mNotificationData);
@@ -1712,17 +1988,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
public void addQsTile(ComponentName tile) {
mQSPanel.getHost().addTile(tile);
}
- @Override
public void remQsTile(ComponentName tile) {
mQSPanel.getHost().removeTile(tile);
}
- @Override
public void clickTile(ComponentName tile) {
mQSPanel.clickTile(tile);
}
@@ -1785,7 +2058,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return entry.row.getParent() instanceof NotificationStackScrollLayout;
}
- @Override
protected void updateNotifications() {
mNotificationData.filterAndSort();
@@ -1796,7 +2068,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateNotifications();
}
- @Override
protected void setAreThereNotifications() {
if (SPEW) {
@@ -1980,7 +2251,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
- Trace.beginSection("PhoneStatusBar#updateMediaMetaData");
+ Trace.beginSection("StatusBar#updateMediaMetaData");
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
Trace.endSection();
return;
@@ -2275,9 +2546,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
}
- @Override
- protected BaseStatusBar.H createHandler() {
- return new PhoneStatusBar.H();
+ protected H createHandler() {
+ return new StatusBar.H();
}
@Override
@@ -2314,7 +2584,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return getBarState() == StatusBarState.KEYGUARD;
}
- @Override
public boolean isDozing() {
return mDozing;
}
@@ -2408,7 +2677,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
- @Override
protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
boolean alertAgain) {
final boolean wasHeadsUp = isHeadsUp(key);
@@ -2425,7 +2693,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected void setHeadsUpUser(int newUserId) {
if (mHeadsUpManager != null) {
mHeadsUpManager.setUser(newUserId);
@@ -2436,7 +2703,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mHeadsUpManager.isHeadsUp(key);
}
- @Override
protected boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
@@ -2493,11 +2759,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
- private class H extends BaseStatusBar.H {
+ protected class H extends Handler {
@Override
public void handleMessage(Message m) {
- super.handleMessage(m);
switch (m.what) {
+ case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
+ toggleKeyboardShortcuts(m.arg1);
+ break;
+ case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
+ dismissKeyboardShortcuts();
+ break;
+ // End old BaseStatusBar.H handling.
case MSG_OPEN_NOTIFICATION_PANEL:
animateExpandNotificationsPanel();
break;
@@ -2514,7 +2786,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
public void maybeEscalateHeadsUp() {
Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
for (HeadsUpManager.HeadsUpEntry entry : entries) {
@@ -2614,12 +2885,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
1.0f /* speedUpFactor */);
}
- @Override
public void animateCollapsePanels(int flags, boolean force) {
animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
}
- @Override
public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
}
@@ -2802,24 +3071,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override // CommandQueue
- public void buzzBeepBlinked() {
- }
-
- @Override
- public void notificationLightOff() {
- if (mDozeServiceHost != null) {
- mDozeServiceHost.fireNotificationLight(false);
- }
- }
-
- @Override
- public void notificationLightPulse(int argb, int onMillis, int offMillis) {
- if (mDozeServiceHost != null) {
- mDozeServiceHost.fireNotificationLight(true);
- }
- }
-
- @Override // CommandQueue
public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
final int oldVal = mSystemUiVisibility;
@@ -2944,7 +3195,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
- @Override
public void setInteracting(int barWindow, boolean interacting) {
final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
mInteractingWindows = interacting
@@ -3148,6 +3398,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
pw.println(" mGroupManager: null");
}
+
+ mLightBarController.dump(fd, pw, args);
+
if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
}
@@ -3166,7 +3419,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
pw.println(BarTransitions.modeToString(transitions.getMode()));
}
- @Override
public void createAndAddWindows() {
addStatusBarWindow();
}
@@ -3349,7 +3601,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
@@ -3369,7 +3620,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
protected void onConfigurationChanged(Configuration newConfig) {
updateResources();
updateDisplaySize(); // populates mDisplayMetrics
- super.onConfigurationChanged(newConfig); // calls refreshLayout
+ // Begin old BaseStatusBar.onConfigurationChanged
+ final float fontScale = newConfig.fontScale;
+ final int density = newConfig.densityDpi;
+ if (density != mDensity || mFontScale != fontScale) {
+ onDensityOrFontScaleChanged();
+ mDensity = density;
+ mFontScale = fontScale;
+ }
+ // End old BaseStatusBar.onConfigurationChanged
if (DEBUG) {
Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
@@ -3379,9 +3638,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mScreenPinningRequest.onConfigurationChanged();
}
- @Override
public void userSwitched(int newUserId) {
- super.userSwitched(newUserId);
+ // Begin old BaseStatusBar.userSwitched
+ setHeadsUpUser(newUserId);
+ // End old BaseStatusBar.userSwitched
if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
animateCollapsePanels();
updatePublicMode();
@@ -3436,14 +3696,40 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Visibility reporting
- @Override
protected void handleVisibleToUserChanged(boolean visibleToUser) {
if (visibleToUser) {
- super.handleVisibleToUserChanged(visibleToUser);
+ handleVisibleToUserChangedImpl(visibleToUser);
startNotificationLogging();
} else {
stopNotificationLogging();
- super.handleVisibleToUserChanged(visibleToUser);
+ handleVisibleToUserChangedImpl(visibleToUser);
+ }
+ }
+
+ /**
+ * The LEDs are turned off when the notification panel is shown, even just a little bit.
+ * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
+ */
+ // Old BaseStatusBar.handleVisibileToUserChanged
+ private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
+ try {
+ if (visibleToUser) {
+ boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+ boolean clearNotificationEffects =
+ !isPanelFullyCollapsed() &&
+ (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
+ int notificationLoad = mNotificationData.getActiveNotifications().size();
+ if (pinnedHeadsUp && isPanelFullyCollapsed()) {
+ notificationLoad = 1;
+ } else {
+ MetricsLogger.histogram(mContext, "note_load", notificationLoad);
+ }
+ mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
+ } else {
+ mBarService.onPanelHidden();
+ }
+ } catch (RemoteException ex) {
+ // Won't fail unless the world has ended.
}
}
@@ -3516,6 +3802,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
isSecure,
canSkipBouncer);
if (stateFingerprint != mLastLoggedStateFingerprint) {
+ if (mStatusBarStateLog == null) {
+ mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
+ }
+ MetricsLogger.action(mStatusBarStateLog
+ .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN)
+ .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
+ .setSubtype(isSecure ? 1 : 0));
EventLogTags.writeSysuiStatusBarState(mState,
isShowing ? 1 : 0,
isOccluded ? 1 : 0,
@@ -3580,7 +3873,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
mHandler.post(() -> {
mLeaveOpenOnKeyguardHide = true;
- executeRunnableDismissingKeyguard(runnable, null, false, false, false);
+ executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
+ false);
});
}
@@ -3633,9 +3927,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
public void destroy() {
- super.destroy();
+ // Begin old BaseStatusBar.destroy().
+ mContext.unregisterReceiver(mBaseBroadcastReceiver);
+ try {
+ mNotificationListener.unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
+ // End old BaseStatusBar.destroy().
if (mStatusBarWindow != null) {
mWindowManager.removeViewImmediate(mStatusBarWindow);
mStatusBarWindow = null;
@@ -3740,7 +4041,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mState;
}
- @Override
public boolean isPanelFullyCollapsed() {
return mNotificationPanel.isFullyCollapsed();
}
@@ -3789,12 +4089,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateMediaMetaData(true /* metaDataChanged */, true);
}
- @Override
public boolean isCollapsing() {
return mNotificationPanel.isCollapsing();
}
- @Override
public void addPostCollapseAction(Runnable r) {
mPostCollapseRunnables.add(r);
}
@@ -3908,7 +4206,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
* @return true if we would like to stay in the shade, false if it should go away entirely
*/
public boolean hideKeyguard() {
- Trace.beginSection("PhoneStatusBar#hideKeyguard");
+ Trace.beginSection("StatusBar#hideKeyguard");
boolean staying = mLeaveOpenOnKeyguardHide;
setBarState(StatusBarState.SHADE);
View viewToClick = null;
@@ -4040,7 +4338,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
- Trace.beginSection("PhoneStatusBar#updateKeyguardState");
+ Trace.beginSection("StatusBar#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
mNotificationPanel.resetViews();
@@ -4077,7 +4375,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void updateDozingState() {
- Trace.beginSection("PhoneStatusBar#updateDozingState");
+ Trace.beginSection("StatusBar#updateDozingState");
boolean animate = !mDozing && mDozeScrimController.isPulsing();
mNotificationPanel.setDozing(mDozing, animate);
mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
@@ -4191,8 +4489,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void onActivated(ActivatableNotificationView view) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE,
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_NOTE,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
@@ -4283,7 +4581,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
protected int getMaxKeyguardNotifications(boolean recompute) {
if (recompute) {
mMaxKeyguardNotifications = Math.max(1,
@@ -4310,8 +4607,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
if (hasActiveNotifications() && (!isDozing() || isPulsing())) {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE,
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_SHADE,
(int) (dragLengthY / mDisplayMetrics.density),
0 /* velocityDp - N/A */);
@@ -4383,29 +4680,63 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- @Override
public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
mLeaveOpenOnKeyguardHide = true;
dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
}
- @Override
protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
mPendingRemoteInputView = clicked;
}
- @Override
+ protected void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
+ View clickedView) {
+ if (isKeyguardShowing()) {
+ onLockedRemoteInput(row, clickedView);
+ } else {
+ row.setUserExpanded(true);
+ row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
+ }
+ }
+
protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
String notificationKey) {
// Clear pending remote view, as we do not want to trigger pending remote input view when
// it's called by other code
mPendingWorkRemoteInputView = null;
- return super.startWorkChallengeIfNecessary(userId, intendSender, notificationKey);
+ // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
+ final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+ null, userId);
+ if (newIntent == null) {
+ return false;
+ }
+ final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+ callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
+ callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
+ callBackIntent.setPackage(mContext.getPackageName());
+
+ PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ callBackIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT |
+ PendingIntent.FLAG_ONE_SHOT |
+ PendingIntent.FLAG_IMMUTABLE);
+ newIntent.putExtra(
+ Intent.EXTRA_INTENT,
+ callBackPendingIntent.getIntentSender());
+ try {
+ ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
+ null /*options*/);
+ } catch (RemoteException ex) {
+ // ignore
+ }
+ return true;
+ // End old BaseStatusBar.startWorkChallengeIfNecessary.
}
- @Override
protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
View clicked) {
// Collapse notification and show work challenge
@@ -4425,7 +4756,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return false;
}
- @Override
protected void onWorkChallengeChanged() {
updatePublicMode();
updateNotifications();
@@ -4522,9 +4852,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mKeyguardFadingAwayDuration;
}
- @Override
public void setBouncerShowing(boolean bouncerShowing) {
- super.setBouncerShowing(bouncerShowing);
+ mBouncerShowing = bouncerShowing;
mStatusBarView.setBouncerShowing(bouncerShowing);
recomputeDisableFlags(true /* animate */);
}
@@ -4604,13 +4933,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return !mNotificationData.getActiveNotifications().isEmpty();
}
- @Override
- public void wakeUpIfDozing(long time, PointF where) {
+ public void wakeUpIfDozing(long time, View where) {
if (mDozing && mDozeScrimController.isPulsing()) {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(time, "com.android.systemui:NODOZE");
mWakeUpComingFromTouch = true;
- mWakeUpTouchLocation = where;
+ where.getLocationInWindow(mTmpInt2);
+ mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
+ mTmpInt2[1] + where.getHeight() / 2);
mNotificationPanel.setTouchDisabled(false);
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
mFalsingManager.onScreenOnFromTouch();
@@ -4698,7 +5028,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void updateDozing() {
- Trace.beginSection("PhoneStatusBar#updateDozing");
+ Trace.beginSection("StatusBar#updateDozing");
// When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
|| mFingerprintUnlockController.getMode()
@@ -4711,44 +5041,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mStatusBarKeyguardViewManager.isShowing();
}
- private final class ShadeUpdates {
- private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
- private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
-
- public void check() {
- mNewVisibleNotifications.clear();
- ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
- for (int i = 0; i < activeNotifications.size(); i++) {
- final Entry entry = activeNotifications.get(i);
- final boolean visible = entry.row != null
- && entry.row.getVisibility() == View.VISIBLE;
- if (visible) {
- mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime());
- }
- }
- final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications);
- mVisibleNotifications.clear();
- mVisibleNotifications.addAll(mNewVisibleNotifications);
-
- // We have new notifications
- if (updates && mDozeServiceHost != null) {
- mDozeServiceHost.fireNewNotifications();
- }
- }
- }
-
private final class DozeServiceHost implements DozeHost {
- // Amount of time to allow to update the time shown on the screen before releasing
- // the wakelock. This timeout is design to compensate for the fact that we don't
- // currently have a way to know when time display contents have actually been
- // refreshed once we've finished rendering a new frame.
- private static final long PROCESSING_TIME = 500;
-
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
- // Keeps the last reported state by fireNotificationLight.
- private boolean mNotificationLightOn;
-
@Override
public String toString() {
return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
@@ -4766,19 +5061,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- public void fireNotificationLight(boolean on) {
- mNotificationLightOn = on;
- for (Callback callback : mCallbacks) {
- callback.onNotificationLight(on);
- }
- }
-
- public void fireNewNotifications() {
- for (Callback callback : mCallbacks) {
- callback.onNewNotifications();
- }
- }
-
@Override
public void addCallback(@NonNull Callback callback) {
mCallbacks.add(callback);
@@ -4844,14 +5126,1969 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public boolean isNotificationLightOn() {
- return mNotificationLightOn;
+ public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
+ StatusBar.this.startPendingIntentDismissingKeyguard(intent);
}
+ }
+
+ public SnoozeListener getSnoozeListener() {
+ return this;
+ }
+
+ @Override
+ public void snoozeNotification(StatusBarNotification sbn, SnoozeOption snoozeOption) {
+ setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ // Begin Extra BaseStatusBar methods.
+
+ protected CommandQueue mCommandQueue;
+ protected IStatusBarService mBarService;
+
+ // all notifications
+ protected NotificationData mNotificationData;
+ protected NotificationStackScrollLayout mStackScroller;
+
+ protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
+
+ protected RemoteInputController mRemoteInputController;
+
+ // for heads up notifications
+ protected HeadsUpManager mHeadsUpManager;
+
+ // handling reordering
+ protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
+
+ protected int mCurrentUserId = 0;
+ final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+
+ protected int mLayoutDirection = -1; // invalid
+ protected AccessibilityManager mAccessibilityManager;
+
+ protected boolean mDeviceInteractive;
+
+ protected boolean mVisible;
+ protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
+ protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
+
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
+ // mScreenOnFromKeyguard && mVisible.
+ private boolean mVisibleToUser;
+
+ private Locale mLocale;
+ private float mFontScale;
+
+ protected boolean mUseHeadsUp = false;
+ protected boolean mHeadsUpTicker = false;
+ protected boolean mDisableNotificationAlerts = false;
+
+ protected DevicePolicyManager mDevicePolicyManager;
+ protected IDreamManager mDreamManager;
+ protected PowerManager mPowerManager;
+ protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+ // public mode, private notifications, etc
+ private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
+
+ private UserManager mUserManager;
+ private int mDensity;
+
+ protected KeyguardManager mKeyguardManager;
+ private LockPatternUtils mLockPatternUtils;
+ private DeviceProvisionedController mDeviceProvisionedController;
+
+ // UI-specific methods
+
+ protected WindowManager mWindowManager;
+ protected IWindowManager mWindowManagerService;
+
+ protected Display mDisplay;
+
+ protected RecentsComponent mRecents;
+
+ protected int mZenMode;
+
+ // which notification is currently being longpress-examined by the user
+ private NotificationGuts mNotificationGutsExposed;
+ private MenuItem mGutsMenuItem;
+
+ private KeyboardShortcuts mKeyboardShortcuts;
+
+ protected NotificationShelf mNotificationShelf;
+ protected DismissView mDismissView;
+ protected EmptyShadeView mEmptyShadeView;
+
+ private NotificationClicker mNotificationClicker = new NotificationClicker();
+
+ protected AssistManager mAssistManager;
+
+ protected boolean mVrMode;
+
+ private Set<String> mNonBlockablePkgs;
+
+ @Override // NotificationData.Environment
+ public boolean isDeviceProvisioned() {
+ return mDeviceProvisionedController.isDeviceProvisioned();
+ }
+
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
- public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
- PhoneStatusBar.this.startPendingIntentDismissingKeyguard(intent);
+ public void onVrStateChanged(boolean enabled) {
+ mVrMode = enabled;
+ }
+ };
+
+ public boolean isDeviceInVrMode() {
+ return mVrMode;
+ }
+
+ private final DeviceProvisionedListener mDeviceProvisionedListener =
+ new DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ updateNotifications();
+ }
+ };
+
+ protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+ setZenMode(mode);
+
+ updateLockscreenNotificationSetting();
+ }
+ };
+
+ private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
+ // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
+ mUsersAllowingPrivateNotifications.clear();
+ mUsersAllowingNotifications.clear();
+ // ... and refresh all the notifications
+ updateLockscreenNotificationSetting();
+ updateNotifications();
+ }
+ };
+
+ private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
+
+ @Override
+ public boolean onClickHandler(
+ final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
+ wakeUpIfDozing(SystemClock.uptimeMillis(), view);
+
+
+ if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
+ return true;
+ }
+
+ if (DEBUG) {
+ Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
+ }
+ logActionClick(view);
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ final boolean isActivity = pendingIntent.isActivity();
+ if (isActivity) {
+ final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+ final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+ mContext, pendingIntent.getIntent(), mCurrentUserId);
+ dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+
+ boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
+
+ // close the shade if it was open
+ if (handled) {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */);
+ visibilityChanged(false);
+ mAssistManager.hideAssist();
+ }
+
+ // Wait for activity start.
+ return handled;
+ }
+ }, afterKeyguardGone);
+ return true;
+ } else {
+ return superOnClickHandler(view, pendingIntent, fillInIntent);
+ }
+ }
+
+ private void logActionClick(View view) {
+ ViewParent parent = view.getParent();
+ String key = getNotificationKeyForParent(parent);
+ if (key == null) {
+ Log.w(TAG, "Couldn't determine notification for click.");
+ return;
+ }
+ int index = -1;
+ // If this is a default template, determine the index of the button.
+ if (view.getId() == com.android.internal.R.id.action0 &&
+ parent != null && parent instanceof ViewGroup) {
+ ViewGroup actionGroup = (ViewGroup) parent;
+ index = actionGroup.indexOfChild(view);
+ }
+ try {
+ mBarService.onNotificationActionClick(key, index);
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
+ private String getNotificationKeyForParent(ViewParent parent) {
+ while (parent != null) {
+ if (parent instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent) {
+ return super.onClickHandler(view, pendingIntent, fillInIntent,
+ StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ }
+
+ private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
+ Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
+ RemoteInput[] inputs = null;
+ if (tag instanceof RemoteInput[]) {
+ inputs = (RemoteInput[]) tag;
+ }
+
+ if (inputs == null) {
+ return false;
+ }
+
+ RemoteInput input = null;
+
+ for (RemoteInput i : inputs) {
+ if (i.getAllowFreeFormInput()) {
+ input = i;
+ }
+ }
+
+ if (input == null) {
+ return false;
+ }
+
+ ViewParent p = view.getParent();
+ RemoteInputView riv = null;
+ while (p != null) {
+ if (p instanceof View) {
+ View pv = (View) p;
+ if (pv.isRootNamespace()) {
+ riv = findRemoteInputView(pv);
+ break;
+ }
+ }
+ p = p.getParent();
+ }
+ ExpandableNotificationRow row = null;
+ while (p != null) {
+ if (p instanceof ExpandableNotificationRow) {
+ row = (ExpandableNotificationRow) p;
+ break;
+ }
+ p = p.getParent();
+ }
+
+ if (row == null) {
+ return false;
+ }
+
+ row.setUserExpanded(true);
+
+ if (!mAllowLockscreenRemoteInput) {
+ final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+ if (isLockscreenPublicMode(userId)) {
+ onLockedRemoteInput(row, view);
+ return true;
+ }
+ if (mUserManager.getUserInfo(userId).isManagedProfile()
+ && mKeyguardManager.isDeviceLocked(userId)) {
+ onLockedWorkRemoteInput(userId, row, view);
+ return true;
+ }
+ }
+
+ if (riv == null) {
+ riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
+ if (riv == null) {
+ return false;
+ }
+ if (!row.getPrivateLayout().getExpandedChild().isShown()) {
+ onMakeExpandedVisibleForRemoteInput(row, view);
+ return true;
+ }
+ }
+
+ int width = view.getWidth();
+ if (view instanceof TextView) {
+ // Center the reveal on the text which might be off-center from the TextView
+ TextView tv = (TextView) view;
+ if (tv.getLayout() != null) {
+ int innerWidth = (int) tv.getLayout().getLineWidth(0);
+ innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
+ width = Math.min(width, innerWidth);
+ }
+ }
+ int cx = view.getLeft() + width / 2;
+ int cy = view.getTop() + view.getHeight() / 2;
+ int w = riv.getWidth();
+ int h = riv.getHeight();
+ int r = Math.max(
+ Math.max(cx + cy, cx + (h - cy)),
+ Math.max((w - cx) + cy, (w - cx) + (h - cy)));
+
+ riv.setRevealParameters(cx, cy, r);
+ riv.setPendingIntent(pendingIntent);
+ riv.setRemoteInput(inputs, input);
+ riv.focusAnimated();
+
+ return true;
+ }
+
+ private RemoteInputView findRemoteInputView(View v) {
+ if (v == null) {
+ return null;
+ }
+ return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
+ }
+ };
+
+ private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ updateCurrentProfilesCache();
+ if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+ updateLockscreenNotificationSetting();
+
+ userSwitched(mCurrentUserId);
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ updateCurrentProfilesCache();
+ } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+ List<ActivityManager.RecentTaskInfo> recentTask = null;
+ try {
+ recentTask = ActivityManager.getService().getRecentTasks(1,
+ ActivityManager.RECENT_WITH_EXCLUDED
+ | ActivityManager.RECENT_INCLUDE_PROFILES,
+ mCurrentUserId).getList();
+ } catch (RemoteException e) {
+ // Abandon hope activity manager not running.
+ }
+ if (recentTask != null && recentTask.size() > 0) {
+ UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
+ if (user != null && user.isManagedProfile()) {
+ Toast toast = Toast.makeText(mContext,
+ R.string.managed_profile_foreground_toast,
+ Toast.LENGTH_SHORT);
+ TextView text = (TextView) toast.getView().findViewById(
+ android.R.id.message);
+ text.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
+ int paddingPx = mContext.getResources().getDimensionPixelSize(
+ R.dimen.managed_profile_toast_padding);
+ text.setCompoundDrawablePadding(paddingPx);
+ toast.show();
+ }
+ }
+ } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
+ NotificationManager noMan = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
+ if (BANNER_ACTION_SETUP.equals(action)) {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */);
+ mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ );
+ }
+ } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
+ final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ }
+ if (notificationKey != null) {
+ try {
+ mBarService.onNotificationClick(notificationKey);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+ isCurrentProfile(getSendingUserId())) {
+ mUsersAllowingPrivateNotifications.clear();
+ updateLockscreenNotificationSetting();
+ updateNotifications();
+ } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+ if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+ onWorkChallengeChanged();
+ }
+ }
}
+ };
+
+ private final NotificationListenerService mNotificationListener =
+ new NotificationListenerService() {
+ @Override
+ public void onListenerConnected() {
+ if (DEBUG) Log.d(TAG, "onListenerConnected");
+ final StatusBarNotification[] notifications = getActiveNotifications();
+ if (notifications == null) {
+ Log.w(TAG, "onListenerConnected unable to get active notifications.");
+ return;
+ }
+ final RankingMap currentRanking = getCurrentRanking();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (StatusBarNotification sbn : notifications) {
+ addNotification(sbn, currentRanking, null /* oldEntry */);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onNotificationPosted(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
+ if (sbn != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ processForRemoteInput(sbn.getNotification());
+ String key = sbn.getKey();
+ mKeysKeptForRemoteInput.remove(key);
+ boolean isUpdate = mNotificationData.get(key) != null;
+ // In case we don't allow child notifications, we ignore children of
+ // notifications that have a summary, since we're not going to show them
+ // anyway. This is true also when the summary is canceled,
+ // because children are automatically canceled by NoMan in that case.
+ if (!ENABLE_CHILD_NOTIFICATIONS
+ && mGroupManager.isChildInGroupWithSummary(sbn)) {
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
+ }
+
+ // Remove existing notification to avoid stale data.
+ if (isUpdate) {
+ removeNotification(key, rankingMap);
+ } else {
+ mNotificationData.updateRanking(rankingMap);
+ }
+ return;
+ }
+ if (isUpdate) {
+ updateNotification(sbn, rankingMap);
+ } else {
+ addNotification(sbn, rankingMap, null /* oldEntry */);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn,
+ final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
+ if (sbn != null) {
+ final String key = sbn.getKey();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ removeNotification(key, rankingMap);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onNotificationRankingUpdate(final RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onRankingUpdate");
+ if (rankingMap != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ updateNotificationRanking(rankingMap);
+ }
+ });
+ } }
+
+ };
+
+ private void updateCurrentProfilesCache() {
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ if (mUserManager != null) {
+ for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+ mCurrentProfiles.put(user.id, user);
+ }
+ }
+ }
+ }
+
+ protected void notifyUserAboutHiddenNotifications() {
+ if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
+ Log.d(TAG, "user hasn't seen notification about hidden notifications");
+ if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+ Log.d(TAG, "insecure lockscreen, skipping notification");
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
+ return;
+ }
+ Log.d(TAG, "disabling lockecreen notifications and alerting the user");
+ // disable lockscreen notifications until user acts on the banner.
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
+
+ final String packageName = mContext.getPackageName();
+ PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+
+ final int colorRes = com.android.internal.R.color.system_notification_accent_color;
+ Notification.Builder note =
+ new Notification.Builder(mContext, NotificationChannels.GENERAL)
+ .setSmallIcon(R.drawable.ic_android)
+ .setContentTitle(mContext.getString(
+ R.string.hidden_notifications_title))
+ .setContentText(mContext.getString(R.string.hidden_notifications_text))
+ .setOngoing(true)
+ .setColor(mContext.getColor(colorRes))
+ .setContentIntent(setupIntent)
+ .addAction(R.drawable.ic_close,
+ mContext.getString(R.string.hidden_notifications_cancel),
+ cancelIntent)
+ .addAction(R.drawable.ic_settings,
+ mContext.getString(R.string.hidden_notifications_setup),
+ setupIntent);
+ overrideNotificationAppName(mContext, note);
+
+ NotificationManager noMan =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
+ }
+ }
+
+ @Override // NotificationData.Environment
+ public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
+ final int thisUserId = mCurrentUserId;
+ final int notificationUserId = n.getUserId();
+ if (DEBUG && MULTIUSER_DEBUG) {
+ Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
+ n, thisUserId, notificationUserId));
+ }
+ return isCurrentProfile(notificationUserId);
+ }
+
+ protected void setNotificationShown(StatusBarNotification n) {
+ setNotificationsShown(new String[]{n.getKey()});
+ }
+
+ protected void setNotificationsShown(String[] keys) {
+ try {
+ mNotificationListener.setNotificationsShown(keys);
+ } catch (RuntimeException e) {
+ Log.d(TAG, "failed setNotificationsShown: ", e);
+ }
+ }
+
+ protected boolean isCurrentProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
+ }
+ }
+
+ @Override
+ public NotificationGroupManager getGroupManager() {
+ return mGroupManager;
+ }
+
+ protected void bindDismissRunnable(final ExpandableNotificationRow row) {
+ row.setOnDismissRunnable(() -> performRemoveNotification(row.getStatusBarNotification()));
+ }
+
+ protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
+ NotificationData.Entry entry) {
+
+ if (entry.getContentView().getId()
+ != com.android.internal.R.id.status_bar_latest_event_content) {
+ // Using custom RemoteViews
+ if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
+ && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
+ entry.row.setShowingLegacyBackground(true);
+ entry.legacy = true;
+ }
+ }
+
+ entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
+ }
+
+ public boolean isMediaNotification(NotificationData.Entry entry) {
+ // TODO: confirm that there's a valid media key
+ return entry.getExpandedContentView() != null &&
+ entry.getExpandedContentView()
+ .findViewById(com.android.internal.R.id.media_actions) != null;
+ }
+
+ // The (i) button in the guts that links to the system notification settings for that app
+ private void startAppNotificationSettingsActivity(String packageName, final int appUid,
+ final String channelId) {
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+ intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+ intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channelId);
+ startNotificationGutsIntent(intent, appUid);
+ }
+
+ private void startNotificationGutsIntent(final Intent intent, final int appUid) {
+ dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ TaskStackBuilder.create(mContext)
+ .addNextIntentWithParentStack(intent)
+ .startActivities(getActivityOptions(),
+ new UserHandle(UserHandle.getUserId(appUid)));
+ }
+ });
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ return true;
+ }
+ }, false /* afterKeyguardGone */);
+ }
+
+ protected void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
+ if (snoozeOption.criterion != null) {
+ mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
+ } else {
+ GregorianCalendar snoozeUntil = new GregorianCalendar();
+ snoozeUntil.add(Calendar.MINUTE, snoozeOption.snoozeForMinutes);
+ mNotificationListener.snoozeNotification(sbn.getKey(), snoozeUntil.getTimeInMillis());
+ }
+ }
+
+ private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
+ row.inflateGuts();
+ row.setGutsView(item);
+ final StatusBarNotification sbn = row.getStatusBarNotification();
+ row.setTag(sbn.getPackageName());
+ final NotificationGuts guts = row.getGuts();
+ guts.setClosedListener((NotificationGuts g) -> {
+ if (!row.isRemoved()) {
+ mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
+ }
+ mNotificationGutsExposed = null;
+ mGutsMenuItem = null;
+ });
+
+ if (item.gutsContent instanceof SnoozeGutsContent) {
+ ((SnoozeGutsContent) item.gutsContent).setSnoozeListener(getSnoozeListener());
+ ((SnoozeGutsContent) item.gutsContent).setStatusBarNotification(sbn);
+ ((NotificationSnooze) item.gutsContent).setSnoozeOptions(row.getEntry().snoozeCriteria);
+ }
+
+ if (item.gutsContent instanceof NotificationInfo) {
+ final NotificationChannel channel = row.getEntry().channel;
+ PackageManager pmUser = getPackageManagerForUser(mContext,
+ sbn.getUser().getIdentifier());
+ final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ final String pkg = sbn.getPackageName();
+ NotificationInfo info = (NotificationInfo) item.gutsContent;
+ final NotificationInfo.OnSettingsClickListener onSettingsClick = (View v,
+ int appUid) -> {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
+ guts.resetFalsingCheck();
+ startAppNotificationSettingsActivity(pkg, appUid, channel.getId());
+ };
+ final View.OnClickListener onDoneClick = (View v) -> {
+ // If the user has security enabled, show challenge if the setting is changed.
+ if (info.hasImportanceChanged()
+ && isLockscreenPublicMode(sbn.getUser().getIdentifier())
+ && (mState == StatusBarState.KEYGUARD
+ || mState == StatusBarState.SHADE_LOCKED)) {
+ OnDismissAction dismissAction = new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ saveAndCloseNotificationMenu(info, row, guts, v);
+ return true;
+ }
+ };
+ onLockedNotificationImportanceChange(dismissAction);
+ } else {
+ saveAndCloseNotificationMenu(info, row, guts, v);
+ }
+ };
+ info.bindNotification(pmUser, iNotificationManager, sbn, channel, onSettingsClick,
+ onDoneClick,
+ mNonBlockablePkgs);
+ }
+ }
+
+ private void saveAndCloseNotificationMenu(NotificationInfo info,
+ ExpandableNotificationRow row, NotificationGuts guts, View done) {
+ guts.resetFalsingCheck();
+ info.saveImportance();
+ int[] rowLocation = new int[2];
+ int[] doneLocation = new int[2];
+ row.getLocationOnScreen(rowLocation);
+ done.getLocationOnScreen(doneLocation);
+
+ final int centerX = done.getWidth() / 2;
+ final int centerY = done.getHeight() / 2;
+ final int x = doneLocation[0] - rowLocation[0] + centerX;
+ final int y = doneLocation[1] - rowLocation[1] + centerY;
+ dismissPopups(x, y);
+ }
+ protected SwipeHelper.LongPressListener getNotificationLongClicker() {
+ return new SwipeHelper.LongPressListener() {
+ @Override
+ public boolean onLongPress(View v, final int x, final int y,
+ MenuItem item) {
+ if (!(v instanceof ExpandableNotificationRow)) {
+ return false;
+ }
+ if (v.getWindowToken() == null) {
+ Log.e(TAG, "Trying to show notification guts, but not attached to window");
+ return false;
+ }
+
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ bindGuts(row, item);
+ NotificationGuts guts = row.getGuts();
+
+ // Assume we are a status_bar_notification_row
+ if (guts == null) {
+ // This view has no guts. Examples are the more card or the dismiss all view
+ return false;
+ }
+
+ // Already showing?
+ if (guts.getVisibility() == View.VISIBLE) {
+ dismissPopups(x, y);
+ return false;
+ }
+
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
+
+ // ensure that it's laid but not visible until actually laid out
+ guts.setVisibility(View.INVISIBLE);
+ // Post to ensure the the guts are properly laid out.
+ guts.post(new Runnable() {
+ @Override
+ public void run() {
+ if (row.getWindowToken() == null) {
+ Log.e(TAG, "Trying to show notification guts, but not attached to "
+ + "window");
+ return;
+ }
+ dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
+ false /* animate */);
+ guts.setVisibility(View.VISIBLE);
+ final double horz = Math.max(guts.getWidth() - x, x);
+ final double vert = Math.max(guts.getHeight() - y, y);
+ final float r = (float) Math.hypot(horz, vert);
+ final Animator a
+ = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ // Move the notification view back over the gear
+ row.resetTranslation();
+ }
+ });
+ a.start();
+ guts.setExposed(true /* exposed */,
+ mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
+ row.closeRemoteInput();
+ mStackScroller.onHeightChanged(row, true /* needsAnimation */);
+ mNotificationGutsExposed = guts;
+ mGutsMenuItem = item;
+ }
+ });
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Returns the exposed NotificationGuts or null if none are exposed.
+ */
+ public NotificationGuts getExposedGuts() {
+ return mNotificationGutsExposed;
+ }
+
+ public void dismissPopups() {
+ dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
+ }
+
+ private void dismissPopups(int x, int y) {
+ dismissPopups(x, y, true /* resetGear */, false /* animate */);
+ }
+
+ public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
+ if (mNotificationGutsExposed != null) {
+ mNotificationGutsExposed.closeControls(x, y, true /* save */);
+ }
+ if (resetGear) {
+ mStackScroller.resetExposedGearView(animate, true /* force */);
+ }
+ }
+
+ @Override
+ public void toggleSplitScreen() {
+ toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
+ }
+
+ @Override
+ public void preloadRecentApps() {
+ int msg = MSG_PRELOAD_RECENT_APPS;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ @Override
+ public void cancelPreloadRecentApps() {
+ int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ @Override
+ public void dismissKeyboardShortcutsMenu() {
+ int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ @Override
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
+ int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
+ mHandler.removeMessages(msg);
+ mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
+ }
+
+ protected void sendCloseSystemWindows(String reason) {
+ try {
+ ActivityManager.getService().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ protected void toggleKeyboardShortcuts(int deviceId) {
+ KeyboardShortcuts.toggle(mContext, deviceId);
+ }
+
+ protected void dismissKeyboardShortcuts() {
+ KeyboardShortcuts.dismiss();
+ }
+
+ /**
+ * Save the current "public" (locked and secure) state of the lockscreen.
+ */
+ public void setLockscreenPublicMode(boolean publicMode, int userId) {
+ mLockscreenPublicMode.put(userId, publicMode);
+ }
+
+ public boolean isLockscreenPublicMode(int userId) {
+ return mLockscreenPublicMode.get(userId, false);
+ }
+
+ /**
+ * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+ * "public" (secure & locked) mode?
+ */
+ public boolean userAllowsNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+ mUsersAllowingNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingNotifications.get(userHandle);
+ }
+
+ /**
+ * Has the given user chosen to allow their private (full) notifications to be shown even
+ * when the lockscreen is in "public" (secure & locked) mode?
+ */
+ public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+ final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
+ final boolean allowed = allowedByUser && allowedByDpm;
+ mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingPrivateNotifications.get(userHandle);
+ }
+
+ private boolean adminAllowsUnredactedNotifications(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
+ userHandle);
+ return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+ * If so, notifications should be hidden.
+ */
+ @Override // NotificationData.Environment
+ public boolean shouldHideNotifications(int userId) {
+ return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
+ || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+ * package-specific override.
+ */
+ @Override // NotificationDate.Environment
+ public boolean shouldHideNotifications(String key) {
+ return isLockscreenPublicMode(mCurrentUserId)
+ && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen.
+ */
+ @Override // NotificationData.Environment
+ public boolean isSecurelyLocked(int userId) {
+ return isLockscreenPublicMode(userId);
+ }
+
+ public void onNotificationClear(StatusBarNotification notification) {
+ try {
+ mBarService.onNotificationClear(
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUserId());
+ } catch (android.os.RemoteException ex) {
+ // oh well
+ }
+ }
+
+ /**
+ * Called when the notification panel layouts
+ */
+ public void onPanelLaidOut() {
+ if (mState == StatusBarState.KEYGUARD) {
+ // Since the number of notifications is determined based on the height of the view, we
+ // need to update them.
+ int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
+ int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
+ if (maxBefore != maxNotifications) {
+ updateRowStates();
+ }
+ }
+ }
+
+ protected boolean inflateViews(Entry entry, ViewGroup parent) {
+ PackageManager pmUser = getPackageManagerForUser(mContext,
+ entry.notification.getUser().getIdentifier());
+
+ final StatusBarNotification sbn = entry.notification;
+ boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
+ boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
+ mNotificationData.getImportance(sbn.getKey()));
+ try {
+ entry.cacheContentViews(mContext, null, isLowPriority, useIncreasedCollapsedHeight);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Unable to get notification remote views", e);
+ return false;
+ }
+
+ final RemoteViews contentView = entry.cachedContentView;
+ final RemoteViews bigContentView = entry.cachedBigContentView;
+ final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
+ final RemoteViews ambientContentView = entry.cachedAmbientContentView;
+
+ if (contentView == null) {
+ Log.v(TAG, "no contentView for: " + sbn.getNotification());
+ return false;
+ }
+
+ if (DEBUG) {
+ Log.v(TAG, "publicContentView: " + publicContentView);
+ }
+
+ ExpandableNotificationRow row;
+
+ // Stash away previous user expansion state so we can restore it at
+ // the end.
+ boolean hasUserChangedExpansion = false;
+ boolean userExpanded = false;
+ boolean userLocked = false;
+
+ if (entry.row != null) {
+ row = entry.row;
+ hasUserChangedExpansion = row.hasUserChangedExpansion();
+ userExpanded = row.isUserExpanded();
+ userLocked = row.isUserLocked();
+ entry.reset();
+ if (hasUserChangedExpansion) {
+ row.setUserExpanded(userExpanded);
+ }
+ } else {
+ // create the row view
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
+ parent, false);
+ row.setExpansionLogger(this, entry.notification.getKey());
+ row.setGroupManager(mGroupManager);
+ row.setHeadsUpManager(mHeadsUpManager);
+ row.setRemoteInputController(mRemoteInputController);
+ row.setOnExpandClickListener(this);
+
+ // Get the app name.
+ // Note that Notification.Builder#bindHeaderAppName has similar logic
+ // but since this field is used in the guts, it must be accurate.
+ // Therefore we will only show the application label, or, failing that, the
+ // package name. No substitutions.
+ final String pkg = sbn.getPackageName();
+ String appname = pkg;
+ try {
+ final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
+ if (info != null) {
+ appname = String.valueOf(pmUser.getApplicationLabel(info));
+ }
+ } catch (NameNotFoundException e) {
+ // Do nothing
+ }
+ row.setAppName(appname);
+ }
+
+ bindDismissRunnable(row);
+ row.setIsLowPriority(isLowPriority);
+
+ // NB: the large icon is now handled entirely by the template
+
+ // bind the click event to the content area
+ NotificationContentView contentContainer = row.getPrivateLayout();
+ NotificationContentView contentContainerPublic = row.getPublicLayout();
+
+ row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ if (ENABLE_REMOTE_INPUT) {
+ row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ }
+
+ mNotificationClicker.register(row, sbn);
+
+ // set up the adaptive layout
+ View contentViewLocal = null;
+ View bigContentViewLocal = null;
+ View headsUpContentViewLocal = null;
+ View publicViewLocal = null;
+ View ambientViewLocal = null;
+ try {
+ contentViewLocal = contentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainer,
+ mOnClickHandler);
+ if (bigContentView != null) {
+ bigContentViewLocal = bigContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainer,
+ mOnClickHandler);
+ }
+ if (headsUpContentView != null) {
+ headsUpContentViewLocal = headsUpContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainer,
+ mOnClickHandler);
+ }
+ if (publicContentView != null) {
+ publicViewLocal = publicContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainerPublic, mOnClickHandler);
+ }
+ if (ambientContentView != null) {
+ ambientViewLocal = ambientContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainer, mOnClickHandler);
+ }
+
+ if (contentViewLocal != null) {
+ contentViewLocal.setIsRootNamespace(true);
+ contentContainer.setContractedChild(contentViewLocal);
+ }
+ if (bigContentViewLocal != null) {
+ bigContentViewLocal.setIsRootNamespace(true);
+ contentContainer.setExpandedChild(bigContentViewLocal);
+ }
+ if (headsUpContentViewLocal != null) {
+ headsUpContentViewLocal.setIsRootNamespace(true);
+ contentContainer.setHeadsUpChild(headsUpContentViewLocal);
+ }
+ if (publicViewLocal != null) {
+ publicViewLocal.setIsRootNamespace(true);
+ contentContainerPublic.setContractedChild(publicViewLocal);
+ }
+
+ if (ambientViewLocal != null) {
+ ambientViewLocal.setIsRootNamespace(true);
+ contentContainer.setAmbientChild(ambientViewLocal);
+ }
+ }
+ catch (RuntimeException e) {
+ final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
+ Log.e(TAG, "couldn't inflate view for notification " + ident, e);
+ return false;
+ }
+
+ // Extract target SDK version.
+ try {
+ ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
+ entry.targetSdk = info.targetSdkVersion;
+ } catch (NameNotFoundException ex) {
+ Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+ }
+ entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
+
+ entry.row = row;
+ entry.row.setOnActivatedListener(this);
+ entry.row.setExpandable(bigContentViewLocal != null);
+
+ applyColorsAndBackgrounds(sbn, entry);
+
+ // Restore previous flags.
+ if (hasUserChangedExpansion) {
+ // Note: setUserExpanded() conveniently ignores calls with
+ // userExpanded=true if !isExpandable().
+ row.setUserExpanded(userExpanded);
+ }
+ row.setUserLocked(userLocked);
+ row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
+ row.onNotificationUpdated(entry);
+ return true;
+ }
+
+ /**
+ * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
+ * via first-class API.
+ *
+ * TODO: Remove once enough apps specify remote inputs on their own.
+ */
+ private void processForRemoteInput(Notification n) {
+ if (!ENABLE_REMOTE_INPUT) return;
+
+ if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
+ (n.actions == null || n.actions.length == 0)) {
+ Notification.Action viableAction = null;
+ Notification.WearableExtender we = new Notification.WearableExtender(n);
+
+ List<Notification.Action> actions = we.getActions();
+ final int numActions = actions.size();
+
+ for (int i = 0; i < numActions; i++) {
+ Notification.Action action = actions.get(i);
+ if (action == null) {
+ continue;
+ }
+ RemoteInput[] remoteInputs = action.getRemoteInputs();
+ if (remoteInputs == null) {
+ continue;
+ }
+ for (RemoteInput ri : remoteInputs) {
+ if (ri.getAllowFreeFormInput()) {
+ viableAction = action;
+ break;
+ }
+ }
+ if (viableAction != null) {
+ break;
+ }
+ }
+
+ if (viableAction != null) {
+ Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
+ rebuilder.setActions(viableAction);
+ rebuilder.build(); // will rewrite n
+ }
+ }
+ }
+
+ public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
+ if (!isDeviceProvisioned()) return;
+
+ final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+ final boolean afterKeyguardGone = intent.isActivity()
+ && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
+ mCurrentUserId);
+ dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ try {
+ intent.send(null, 0, null, null, null, null, getActivityOptions());
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending intent failed: " + e);
+
+ // TODO: Dismiss Keyguard.
+ }
+ if (intent.isActivity()) {
+ mAssistManager.hideAssist();
+ }
+ }
+ }.start();
+
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */, true /* delayed */);
+ visibilityChanged(false);
+
+ return true;
+ }
+ }, afterKeyguardGone);
+ }
+
+
+ private final class NotificationClicker implements View.OnClickListener {
+
+ @Override
+ public void onClick(final View v) {
+ if (!(v instanceof ExpandableNotificationRow)) {
+ Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
+ return;
+ }
+
+ wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ final StatusBarNotification sbn = row.getStatusBarNotification();
+ if (sbn == null) {
+ Log.e(TAG, "NotificationClicker called on an unclickable notification,");
+ return;
+ }
+
+ // Check if the notification is displaying the gear, if so slide notification back
+ if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
+ row.animateTranslateNotification(0);
+ return;
+ }
+
+ Notification notification = sbn.getNotification();
+ final PendingIntent intent = notification.contentIntent != null
+ ? notification.contentIntent
+ : notification.fullScreenIntent;
+ final String notificationKey = sbn.getKey();
+
+ // Mark notification for one frame.
+ row.setJustClicked(true);
+ DejankUtils.postAfterTraversal(new Runnable() {
+ @Override
+ public void run() {
+ row.setJustClicked(false);
+ }
+ });
+
+ final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+ final boolean afterKeyguardGone = intent.isActivity()
+ && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
+ mCurrentUserId);
+ dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
+ // Release the HUN notification to the shade.
+
+ if (isPanelFullyCollapsed()) {
+ HeadsUpManager.setIsClickedNotification(row, true);
+ }
+ //
+ // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
+ // become canceled shortly by NoMan, but we can't assume that.
+ mHeadsUpManager.releaseImmediately(notificationKey);
+ }
+ StatusBarNotification parentToCancel = null;
+ if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
+ StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
+ .getStatusBarNotification();
+ if (shouldAutoCancel(summarySbn)) {
+ parentToCancel = summarySbn;
+ }
+ }
+ final StatusBarNotification parentToCancelFinal = parentToCancel;
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ if (intent != null) {
+ // If we are launching a work activity and require to launch
+ // separate work challenge, we defer the activity action and cancel
+ // notification until work challenge is unlocked.
+ if (intent.isActivity()) {
+ final int userId = intent.getCreatorUserHandle()
+ .getIdentifier();
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+ && mKeyguardManager.isDeviceLocked(userId)) {
+ boolean canBypass = false;
+ try {
+ canBypass = ActivityManager.getService()
+ .canBypassWorkChallenge(intent);
+ } catch (RemoteException e) {
+ }
+ // For direct-boot aware activities, they can be shown when
+ // the device is still locked without triggering the work
+ // challenge.
+ if ((!canBypass) && startWorkChallengeIfNecessary(userId,
+ intent.getIntentSender(), notificationKey)) {
+ // Show work challenge, do not run PendingIntent and
+ // remove notification
+ return;
+ }
+ }
+ }
+ try {
+ intent.send(null, 0, null, null, null, null,
+ getActivityOptions());
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending contentIntent failed: " + e);
+
+ // TODO: Dismiss Keyguard.
+ }
+ if (intent.isActivity()) {
+ mAssistManager.hideAssist();
+ }
+ }
+
+ try {
+ mBarService.onNotificationClick(notificationKey);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ if (parentToCancelFinal != null) {
+ // We have to post it to the UI thread for synchronization
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Runnable removeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ performRemoveNotification(parentToCancelFinal);
+ }
+ };
+ if (isCollapsing()) {
+ // To avoid lags we're only performing the remove
+ // after the shade was collapsed
+ addPostCollapseAction(removeRunnable);
+ } else {
+ removeRunnable.run();
+ }
+ }
+ });
+ }
+ }
+ }.start();
+
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ true /* force */, true /* delayed */);
+ visibilityChanged(false);
+
+ return true;
+ }
+ }, afterKeyguardGone);
+ }
+
+ private boolean shouldAutoCancel(StatusBarNotification sbn) {
+ int flags = sbn.getNotification().flags;
+ if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
+ return false;
+ }
+ if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
+ Notification notification = sbn.getNotification();
+ if (notification.contentIntent != null || notification.fullScreenIntent != null) {
+ row.setOnClickListener(this);
+ } else {
+ row.setOnClickListener(null);
+ }
+ }
+ }
+
+ protected Bundle getActivityOptions() {
+ // Anything launched from the notification shade should always go into the
+ // fullscreen stack.
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ return options.toBundle();
+ }
+
+ protected void visibilityChanged(boolean visible) {
+ if (mVisible != visible) {
+ mVisible = visible;
+ if (!visible) {
+ dismissPopups();
+ }
+ }
+ updateVisibleToUser();
+ }
+
+ protected void updateVisibleToUser() {
+ boolean oldVisibleToUser = mVisibleToUser;
+ mVisibleToUser = mVisible && mDeviceInteractive;
+
+ if (oldVisibleToUser != mVisibleToUser) {
+ handleVisibleToUserChanged(mVisibleToUser);
+ }
+ }
+
+ /**
+ * Clear Buzz/Beep/Blink.
+ */
+ public void clearNotificationEffects() {
+ try {
+ mBarService.clearNotificationEffects();
+ } catch (RemoteException e) {
+ // Won't fail unless the world has ended.
+ }
+ }
+
+ /**
+ * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+ * about the failure.
+ *
+ * WARNING: this will call back into us. Don't hold any locks.
+ */
+ void handleNotificationError(StatusBarNotification n, String message) {
+ removeNotification(n.getKey(), null);
+ try {
+ mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
+ n.getInitialPid(), message, n.getUserId());
+ } catch (RemoteException ex) {
+ // The end is nigh.
+ }
+ }
+
+ protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
+ NotificationData.Entry entry = mNotificationData.remove(key, ranking);
+ if (entry == null) {
+ Log.w(TAG, "removeNotification for unknown key: " + key);
+ return null;
+ }
+ updateNotifications();
+ return entry.notification;
+ }
+
+ protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
+ if (DEBUG) {
+ Log.d(TAG, "createNotificationViews(notification=" + sbn);
+ }
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ try {
+ entry.createIcons(mContext, sbn);
+ } catch (NotificationData.IconException exception) {
+ handleNotificationError(sbn, exception.getMessage());
+ }
+
+ // Construct the expanded view.
+ if (!inflateViews(entry, mStackScroller)) {
+ handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
+ return null;
+ }
+ return entry;
+ }
+
+ protected void addNotificationViews(Entry entry, RankingMap ranking) {
+ if (entry == null) {
+ return;
+ }
+ // Add the expanded view and icon.
+ mNotificationData.add(entry, ranking);
+ updateNotifications();
+ }
+
+ /**
+ * Updates expanded, dimmed and locked states of notification rows.
+ */
+ protected void updateRowStates() {
+ final int N = mStackScroller.getChildCount();
+
+ int visibleNotifications = 0;
+ boolean onKeyguard = mState == StatusBarState.KEYGUARD;
+ int maxNotifications = -1;
+ if (onKeyguard) {
+ maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
+ }
+ mStackScroller.setMaxDisplayedNotifications(maxNotifications);
+ Stack<ExpandableNotificationRow> stack = new Stack<>();
+ for (int i = N - 1; i >= 0; i--) {
+ View child = mStackScroller.getChildAt(i);
+ if (!(child instanceof ExpandableNotificationRow)) {
+ continue;
+ }
+ stack.push((ExpandableNotificationRow) child);
+ }
+ while(!stack.isEmpty()) {
+ ExpandableNotificationRow row = stack.pop();
+ NotificationData.Entry entry = row.getEntry();
+ boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
+ if (onKeyguard) {
+ row.setOnKeyguard(true);
+ } else {
+ row.setOnKeyguard(false);
+ row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
+ }
+ entry.row.setShowAmbient(isDozing());
+ int userId = entry.notification.getUserId();
+ boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
+ entry.notification) && !entry.row.isRemoved();
+ boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
+ if (suppressedSummary
+ || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
+ || (onKeyguard && !showOnKeyguard)) {
+ entry.row.setVisibility(View.GONE);
+ } else {
+ boolean wasGone = entry.row.getVisibility() == View.GONE;
+ if (wasGone) {
+ entry.row.setVisibility(View.VISIBLE);
+ }
+ if (!childNotification && !entry.row.isRemoved()) {
+ if (wasGone) {
+ // notify the scroller of a child addition
+ mStackScroller.generateAddAnimation(entry.row,
+ !showOnKeyguard /* fromMoreCard */);
+ }
+ visibleNotifications++;
+ }
+ }
+ if (row.isSummaryWithChildren()) {
+ List<ExpandableNotificationRow> notificationChildren =
+ row.getNotificationChildren();
+ int size = notificationChildren.size();
+ for (int i = size - 1; i >= 0; i--) {
+ stack.push(notificationChildren.get(i));
+ }
+ }
+ }
+
+ mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
+ mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
+ mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
+ }
+
+ public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+ return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
+ }
+
+ // extended in StatusBar
+ protected void setShowLockscreenNotifications(boolean show) {
+ mShowLockscreenNotifications = show;
+ }
+
+ protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+ mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+ }
+
+ private void updateLockscreenNotificationSetting() {
+ final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ 1,
+ mCurrentUserId) != 0;
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
+ null /* admin */, mCurrentUserId);
+ final boolean allowedByDpm = (dpmFlags
+ & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+ setShowLockscreenNotifications(show && allowedByDpm);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+ final boolean remoteInputDpm =
+ (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+ setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ } else {
+ setLockScreenAllowRemoteInput(false);
+ }
+ }
+
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
+ if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
+
+ final String key = notification.getKey();
+ Entry entry = mNotificationData.get(key);
+ if (entry == null) {
+ return;
+ } else {
+ mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
+ mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
+ }
+
+ Notification n = notification.getNotification();
+ mNotificationData.updateRanking(ranking);
+
+ boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(notification,
+ mNotificationData.getImportance(notification.getKey()));
+ entry.row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
+ boolean applyInPlace;
+ try {
+ applyInPlace = entry.cacheContentViews(mContext, notification.getNotification(),
+ mNotificationData.isAmbient(key), useIncreasedCollapsedHeight);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Unable to get notification remote views", e);
+ applyInPlace = false;
+ }
+ boolean shouldPeek = shouldPeek(entry, notification);
+ boolean alertAgain = alertAgain(entry, n);
+ if (DEBUG) {
+ Log.d(TAG, "applyInPlace=" + applyInPlace
+ + " shouldPeek=" + shouldPeek
+ + " alertAgain=" + alertAgain);
+ }
+
+ final StatusBarNotification oldNotification = entry.notification;
+ entry.notification = notification;
+ mGroupManager.onEntryUpdated(entry, oldNotification);
+
+ boolean updateSuccessful = false;
+ try {
+ if (applyInPlace) {
+ if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
+ try {
+ entry.updateIcons(mContext, n);
+ updateNotificationViews(entry, notification);
+ updateSuccessful = true;
+ } catch (RuntimeException e) {
+ // It failed to apply cleanly.
+ Log.w(TAG, "Couldn't reapply views for package " +
+ notification.getPackageName(), e);
+ }
+ }
+ if (!updateSuccessful) {
+ entry.updateIcons(mContext, n);
+ if (!inflateViews(entry, mStackScroller)) {
+ handleNotificationError(notification, "Couldn't update remote views for: "
+ + notification);
+ }
+ }
+ } catch (NotificationData.IconException e) {
+ handleNotificationError(notification, e.getMessage());
+ }
+ updateHeadsUp(key, entry, shouldPeek, alertAgain);
+ updateNotifications();
+
+ if (!notification.isClearable()) {
+ // The user may have performed a dismiss action on the notification, since it's
+ // not clearable we should snap it back.
+ mStackScroller.snapViewIfNeeded(entry.row);
+ }
+
+ if (DEBUG) {
+ // Is this for you?
+ boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
+ Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+ }
+
+ setAreThereNotifications();
+ }
+
+ private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
+ final RemoteViews contentView = entry.cachedContentView;
+ final RemoteViews bigContentView = entry.cachedBigContentView;
+ final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
+ final RemoteViews ambientContentView = entry.cachedAmbientContentView;
+
+ // Reapply the RemoteViews
+ contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
+ if (bigContentView != null && entry.getExpandedContentView() != null) {
+ bigContentView.reapply(sbn.getPackageContext(mContext),
+ entry.getExpandedContentView(),
+ mOnClickHandler);
+ }
+ View headsUpChild = entry.getHeadsUpContentView();
+ if (headsUpContentView != null && headsUpChild != null) {
+ headsUpContentView.reapply(sbn.getPackageContext(mContext),
+ headsUpChild, mOnClickHandler);
+ }
+ if (publicContentView != null && entry.getPublicContentView() != null) {
+ publicContentView.reapply(sbn.getPackageContext(mContext),
+ entry.getPublicContentView(), mOnClickHandler);
+ }
+ if (ambientContentView != null && entry.getAmbientContentView() != null) {
+ ambientContentView.reapply(sbn.getPackageContext(mContext),
+ entry.getAmbientContentView(), mOnClickHandler);
+ }
+ // update the contentIntent
+ mNotificationClicker.register(entry.row, sbn);
+
+ entry.row.onNotificationUpdated(entry);
+ entry.row.resetHeight();
+ }
+
+ protected void updatePublicContentView(Entry entry,
+ StatusBarNotification sbn) {
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
+ View inflatedView = entry.getPublicContentView();
+ if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
+ final boolean disabledByPolicy =
+ !adminAllowsUnredactedNotifications(entry.notification.getUserId());
+ String notificationHiddenText = mContext.getString(disabledByPolicy
+ ? com.android.internal.R.string.notification_hidden_by_policy_text
+ : com.android.internal.R.string.notification_hidden_text);
+ TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
+ if (titleView != null
+ && !titleView.getText().toString().equals(notificationHiddenText)) {
+ publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
+ publicContentView.reapply(sbn.getPackageContext(mContext),
+ inflatedView, mOnClickHandler);
+ entry.row.onNotificationUpdated(entry);
+ }
+ }
+ }
+
+ protected void notifyHeadsUpScreenOff() {
+ maybeEscalateHeadsUp();
+ }
+
+ private boolean alertAgain(Entry oldEntry, Notification newNotification) {
+ return oldEntry == null || !oldEntry.hasInterrupted()
+ || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
+ }
+
+ protected boolean shouldPeek(Entry entry) {
+ return shouldPeek(entry, entry.notification);
+ }
+
+ protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
+ if (!mUseHeadsUp || isDeviceInVrMode()) {
+ return false;
+ }
+
+ if (mNotificationData.shouldFilterOut(sbn)) {
+ if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
+ return false;
+ }
+
+ boolean inUse = mPowerManager.isScreenOn();
+ try {
+ inUse = inUse && !mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.d(TAG, "failed to query dream manager", e);
+ }
+
+ if (!inUse && !isDozing()) {
+ if (DEBUG) {
+ Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+ if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ return false;
+ }
+
+ if (entry.hasJustLaunchedFullScreenIntent()) {
+ if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
+ return false;
+ }
+
+ if (isSnoozedPackage(sbn)) {
+ if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
+ return false;
+ }
+
+ if (mNotificationData.getImportance(sbn.getKey()) < NotificationManager.IMPORTANCE_HIGH) {
+ if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
+ return false;
+ }
+
+ if (sbn.getNotification().fullScreenIntent != null) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
+ return false;
+ } else {
+ // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
+ return !mStatusBarKeyguardViewManager.isShowing()
+ || mStatusBarKeyguardViewManager.isOccluded();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @return Whether the security bouncer from Keyguard is showing.
+ */
+ public boolean isBouncerShowing() {
+ return mBouncerShowing;
+ }
+
+ /**
+ * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
+ * return PackageManager for mContext
+ */
+ public static PackageManager getPackageManagerForUser(Context context, int userId) {
+ Context contextForUser = context;
+ // UserHandle defines special userId as negative values, e.g. USER_ALL
+ if (userId >= 0) {
+ try {
+ // Create a context for the correct user so if a package isn't installed
+ // for user 0 we can still load information about the package.
+ contextForUser =
+ context.createPackageContextAsUser(context.getPackageName(),
+ Context.CONTEXT_RESTRICTED,
+ new UserHandle(userId));
+ } catch (NameNotFoundException e) {
+ // Shouldn't fail to find the package name for system ui.
+ }
+ }
+ return contextForUser.getPackageManager();
+ }
+
+ @Override
+ public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
+ try {
+ mBarService.onNotificationExpansionChanged(key, userAction, expanded);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ public boolean isKeyguardSecure() {
+ if (mStatusBarKeyguardViewManager == null) {
+ // startKeyguard() hasn't been called yet, so we don't know.
+ // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
+ // value onVisibilityChanged().
+ Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
+ new Throwable());
+ return false;
+ }
+ return mStatusBarKeyguardViewManager.isSecure();
+ }
+
+ @Override
+ public void showAssistDisclosure() {
+ if (mAssistManager != null) {
+ mAssistManager.showDisclosure();
+ }
+ }
+
+ @Override
+ public void startAssist(Bundle args) {
+ if (mAssistManager != null) {
+ mAssistManager.startAssist(args);
+ }
}
+ // End Extra BaseStatusBarMethods.
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index a0425e6c00b5..41f8a91566a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -25,8 +24,6 @@ import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -39,6 +36,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -64,7 +62,7 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
public static final int DEFAULT_ICON_TINT = Color.WHITE;
private Context mContext;
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
private DemoStatusIcons mDemoStatusIcons;
private LinearLayout mSystemIconArea;
@@ -100,11 +98,11 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
private final ArraySet<String> mIconBlacklist = new ArraySet<>();
public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
- PhoneStatusBar phoneStatusBar) {
+ StatusBar phoneStatusBar) {
super(context.getResources().getStringArray(
com.android.internal.R.array.config_statusBarIcons));
mContext = context;
- mPhoneStatusBar = phoneStatusBar;
+ mStatusBar = phoneStatusBar;
mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
@@ -130,7 +128,7 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
loadDimens();
- TunerService.get(mContext).addTunable(this, ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
mTransitionsController = new LightBarTransitionsController(this::setIconTintInternal);
}
@@ -405,11 +403,11 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
.withEndAction(null);
// Synchronize the motion with the Keyguard fading if necessary.
- if (mPhoneStatusBar.isKeyguardFadingAway()) {
+ if (mStatusBar.isKeyguardFadingAway()) {
v.animate()
- .setDuration(mPhoneStatusBar.getKeyguardFadingAwayDuration())
+ .setDuration(mStatusBar.getKeyguardFadingAwayDuration())
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
- .setStartDelay(mPhoneStatusBar.getKeyguardFadingAwayDelay())
+ .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
.start();
}
}
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 7e5a7da8c7db..8d5d890b07ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -70,7 +70,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
- protected PhoneStatusBar mPhoneStatusBar;
+ protected StatusBar mStatusBar;
private ScrimController mScrimController;
private FingerprintUnlockController mFingerprintUnlockController;
@@ -103,12 +103,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLockPatternUtils = lockPatternUtils;
}
- public void registerStatusBar(PhoneStatusBar phoneStatusBar,
+ public void registerStatusBar(StatusBar statusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
- mPhoneStatusBar = phoneStatusBar;
+ mStatusBar = statusBar;
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
@@ -136,10 +136,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (mBouncer.needsFullscreenBouncer()) {
// The keyguard might be showing (already). So we need to hide it.
- mPhoneStatusBar.hideKeyguard();
+ mStatusBar.hideKeyguard();
mBouncer.show(true /* resetSecuritySelection */);
} else {
- mPhoneStatusBar.showKeyguard();
+ mStatusBar.showKeyguard();
if (hideBouncerWhenShowing) {
mBouncer.hide(false /* destroyView */);
mBouncer.prepare();
@@ -180,8 +180,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void reset(boolean hideBouncerWhenShowing) {
if (mShowing) {
if (mOccluded) {
- mPhoneStatusBar.hideKeyguard();
- mPhoneStatusBar.stopWaitingForKeyguardExit();
+ mStatusBar.hideKeyguard();
+ mStatusBar.stopWaitingForKeyguardExit();
mBouncer.hide(false /* destroyView */);
} else {
showBouncerOrKeyguard(hideBouncerWhenShowing);
@@ -192,12 +192,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public void onStartedGoingToSleep() {
- mPhoneStatusBar.onStartedGoingToSleep();
+ mStatusBar.onStartedGoingToSleep();
}
public void onFinishedGoingToSleep() {
mDeviceInteractive = false;
- mPhoneStatusBar.onFinishedGoingToSleep();
+ mStatusBar.onFinishedGoingToSleep();
mBouncer.onScreenTurnedOff();
}
@@ -205,13 +205,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
Trace.beginSection("StatusBarKeyguardViewManager#onStartedWakingUp");
mDeviceInteractive = true;
mDeviceWillWakeUp = false;
- mPhoneStatusBar.onStartedWakingUp();
+ mStatusBar.onStartedWakingUp();
Trace.endSection();
}
public void onScreenTurningOn() {
Trace.beginSection("StatusBarKeyguardViewManager#onScreenTurningOn");
- mPhoneStatusBar.onScreenTurningOn();
+ mStatusBar.onScreenTurningOn();
Trace.endSection();
}
@@ -228,7 +228,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
true /* skipFirstFrame */);
updateStates();
}
- mPhoneStatusBar.onScreenTurnedOn();
+ mStatusBar.onScreenTurnedOn();
Trace.endSection();
}
@@ -240,7 +240,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onScreenTurnedOff() {
mScreenTurnedOn = false;
- mPhoneStatusBar.onScreenTurnedOff();
+ mStatusBar.onScreenTurnedOff();
}
public void notifyDeviceWakeUpRequested() {
@@ -257,12 +257,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void setOccluded(boolean occluded, boolean animate) {
if (occluded != mOccluded) {
- mPhoneStatusBar.onKeyguardOccludedChanged(occluded);
+ mStatusBar.onKeyguardOccludedChanged(occluded);
}
if (occluded && !mOccluded && mShowing) {
- if (mPhoneStatusBar.isInLaunchTransition()) {
+ if (mStatusBar.isInLaunchTransition()) {
mOccluded = true;
- mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
+ mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
new Runnable() {
@Override
public void run() {
@@ -275,7 +275,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
mOccluded = occluded;
if (mShowing) {
- mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
+ mStatusBar.updateMediaMetaData(false, animate && !occluded);
}
mStatusBarWindowManager.setKeyguardOccluded(occluded);
@@ -283,7 +283,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// a FLAG_DISMISS_KEYGUARD_ACTIVITY.
reset(false /* hideBouncerWhenShowing*/);
if (animate && !occluded && mShowing) {
- mPhoneStatusBar.animateKeyguardUnoccluding();
+ mStatusBar.animateKeyguardUnoccluding();
}
}
@@ -318,8 +318,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
long uptimeMillis = SystemClock.uptimeMillis();
long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
- if (mPhoneStatusBar.isInLaunchTransition() ) {
- mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
+ if (mStatusBar.isInLaunchTransition() ) {
+ mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
@Override
public void run() {
mStatusBarWindowManager.setKeyguardShowing(false);
@@ -327,14 +327,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBouncer.hide(true /* destroyView */);
updateStates();
mScrimController.animateKeyguardFadingOut(
- PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
- PhoneStatusBar.FADE_KEYGUARD_DURATION, null,
+ StatusBar.FADE_KEYGUARD_START_DELAY,
+ StatusBar.FADE_KEYGUARD_DURATION, null,
false /* skipFirstFrame */);
}
}, new Runnable() {
@Override
public void run() {
- mPhoneStatusBar.hideKeyguard();
+ mStatusBar.hideKeyguard();
mStatusBarWindowManager.setKeyguardFadingAway(false);
mViewMediatorCallback.keyguardGone();
executeAfterKeyguardGoneAction();
@@ -348,19 +348,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
delay = 0;
fadeoutDuration = 240;
}
- mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+ mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
mFingerprintUnlockController.startKeyguardFadingAway();
mBouncer.hide(true /* destroyView */);
updateStates();
if (wakeUnlockPulsing) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
- mPhoneStatusBar.fadeKeyguardWhilePulsing();
+ mStatusBar.fadeKeyguardWhilePulsing();
animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
- mPhoneStatusBar::hideKeyguard, false /* skipFirstFrame */);
+ mStatusBar::hideKeyguard, false /* skipFirstFrame */);
} else {
mFingerprintUnlockController.startKeyguardFadingAway();
- mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
- boolean staying = mPhoneStatusBar.hideKeyguard();
+ mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+ boolean staying = mStatusBar.hideKeyguard();
if (!staying) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) {
@@ -379,7 +379,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
} else {
mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
- mPhoneStatusBar.finishKeyguardFadingAway();
+ mStatusBar.finishKeyguardFadingAway();
}
}
mStatusBarWindowManager.setKeyguardShowing(false);
@@ -408,7 +408,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false),
100);
- mPhoneStatusBar.finishKeyguardFadingAway();
+ mStatusBar.finishKeyguardFadingAway();
mFingerprintUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
@@ -438,7 +438,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* Dismisses the keyguard by going to the next screen or making it gone.
*/
public void dismissAndCollapse() {
- mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
+ mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
}
public void dismiss() {
@@ -466,7 +466,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
*/
public boolean onBackPressed() {
if (mBouncer.isShowing()) {
- mPhoneStatusBar.endAffordanceLaunch();
+ mStatusBar.endAffordanceLaunch();
reset(true /* hideBouncerWhenShowing */);
return true;
}
@@ -478,8 +478,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
private long getNavBarShowDelay() {
- if (mPhoneStatusBar.isKeyguardFadingAway()) {
- return mPhoneStatusBar.getKeyguardFadingAwayDelay();
+ if (mStatusBar.isKeyguardFadingAway()) {
+ return mStatusBar.getKeyguardFadingAwayDelay();
} else {
// Keyguard is not going away, thus we are showing the navigation bar because the
@@ -491,7 +491,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() {
@Override
public void run() {
- mPhoneStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE);
+ mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE);
}
};
@@ -516,7 +516,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean navBarVisible = isNavBarVisible();
boolean lastNavBarVisible = getLastNavBarVisible();
if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
- if (mPhoneStatusBar.getNavigationBarView() != null) {
+ if (mStatusBar.getNavigationBarView() != null) {
if (navBarVisible) {
long delay = getNavBarShowDelay();
if (delay == 0) {
@@ -527,14 +527,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
} else {
mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
- mPhoneStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE);
+ mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE);
}
}
}
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
- mPhoneStatusBar.setBouncerShowing(bouncerShowing);
+ mStatusBar.setBouncerShowing(bouncerShowing);
mScrimController.setBouncerShowing(bouncerShowing);
}
@@ -553,7 +553,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
- mPhoneStatusBar.onKeyguardViewManagerStatesUpdated();
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
}
/**
@@ -583,11 +583,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public boolean shouldDisableWindowAnimationsForUnlock() {
- return mPhoneStatusBar.isInLaunchTransition();
+ return mStatusBar.isInLaunchTransition();
}
public boolean isGoingToNotificationShade() {
- return mPhoneStatusBar.isGoingToNotificationShade();
+ return mStatusBar.isGoingToNotificationShade();
}
public boolean isSecure(int userId) {
@@ -595,11 +595,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public void keyguardGoingAway() {
- mPhoneStatusBar.keyguardGoingAway();
+ mStatusBar.keyguardGoingAway();
}
public void animateCollapsePanels(float speedUpFactor) {
- mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
+ mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
false /* delayed */, speedUpFactor);
}
@@ -616,6 +616,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public ViewRootImpl getViewRootImpl() {
- return mPhoneStatusBar.getStatusBarView().getViewRootImpl();
+ return mStatusBar.getStatusBarView().getViewRootImpl();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 06600541da71..16999b2f454f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -25,7 +25,6 @@ import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.os.Trace;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -34,7 +33,6 @@ import android.view.WindowManager;
import com.android.keyguard.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
@@ -140,7 +138,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback {
private void applyFocusableFlag(State state) {
boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
- || BaseStatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
+ || StatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
@@ -385,7 +383,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback {
boolean backdropShowing;
/**
- * The {@link BaseStatusBar} state from the status bar.
+ * The {@link StatusBar} state from the status bar.
*/
int statusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index aa29e43be467..7c42d00bae7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -29,11 +29,11 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.Trace;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.InputQueue;
@@ -55,7 +55,6 @@ import com.android.internal.view.FloatingActionMode;
import com.android.internal.widget.FloatingToolbar;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -63,7 +62,7 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "StatusBarWindowView";
- public static final boolean DEBUG = BaseStatusBar.DEBUG;
+ public static final boolean DEBUG = StatusBar.DEBUG;
private DragDownHelper mDragDownHelper;
private NotificationStackScrollLayout mStackScrollLayout;
@@ -73,7 +72,7 @@ public class StatusBarWindowView extends FrameLayout {
private int mRightInset = 0;
private int mLeftInset = 0;
- private PhoneStatusBar mService;
+ private StatusBar mService;
private final Paint mTransparentSrcPaint = new Paint();
private FalsingManager mFalsingManager;
@@ -172,7 +171,7 @@ public class StatusBarWindowView extends FrameLayout {
}
}
- public void setService(PhoneStatusBar service) {
+ public void setService(StatusBar service) {
mService = service;
mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
}
@@ -223,7 +222,8 @@ public class StatusBarWindowView extends FrameLayout {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
if (mService.isDozing()) {
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, true);
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
return true;
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index e7056a6367a8..5ab99e9e5bce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -125,14 +125,14 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
final int statusType, final int qsType,final boolean activityIn,
final boolean activityOut, final String typeContentDescription,
- final String description, final boolean isWide, final int subId) {
+ final String description, final boolean isWide, final int subId, boolean roaming) {
post(new Runnable() {
@Override
public void run() {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
activityIn, activityOut, typeContentDescription, description, isWide,
- subId);
+ subId, roaming);
}
}
});
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 9cc97492e22c..ffc0d9764966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -108,7 +108,7 @@ public class Clock extends TextView implements DemoMode, Tunable {
getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter,
null, Dependency.get(Dependency.TIME_TICK_HANDLER));
- TunerService.get(getContext()).addTunable(this, CLOCK_SECONDS,
+ Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
StatusBarIconController.ICON_BLACKLIST);
}
@@ -129,7 +129,7 @@ public class Clock extends TextView implements DemoMode, Tunable {
if (mAttached) {
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a8d8f6008fc3..8c805fec2910 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -37,7 +37,7 @@ import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -90,7 +90,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private final int mStatusBarHeight;
private final Context mContext;
private final NotificationGroupManager mGroupManager;
- private PhoneStatusBar mBar;
+ private StatusBar mBar;
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
@@ -162,7 +162,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
mIsObserving = shouldObserve;
}
- public void setBar(PhoneStatusBar bar) {
+ public void setBar(StatusBar bar) {
mBar = bar;
}
@@ -170,7 +170,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
mListeners.add(listener);
}
- public PhoneStatusBar getBar() {
+ public StatusBar getBar() {
return mBar;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 45cfbdcb0770..882902ee3713 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -116,18 +116,18 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
mOnClickListener = onClickListener;
}
- public void loadAsync(String uri) {
- new AsyncTask<String, Void, Drawable>() {
+ public void loadAsync(Icon icon) {
+ new AsyncTask<Icon, Void, Drawable>() {
@Override
- protected Drawable doInBackground(String... params) {
- return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
+ protected Drawable doInBackground(Icon... params) {
+ return params[0].loadDrawable(mContext);
}
@Override
protected void onPostExecute(Drawable drawable) {
setImageDrawable(drawable);
}
- }.execute(uri);
+ }.execute(icon);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 83463e29c080..03c46e8b3726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -226,10 +226,8 @@ public class MobileSignalController extends SignalController<
final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
&& mCurrentState.userSetup;
- // Show icon in QS when we are connected or need to show roaming or data is disabled.
- boolean showDataIcon = mCurrentState.dataConnected
- || mCurrentState.iconGroup == TelephonyIcons.ROAMING
- || dataDisabled;
+ // Show icon in QS when we are connected or data is disabled.
+ boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
getCurrentIconId(), contentDescription);
@@ -249,13 +247,11 @@ public class MobileSignalController extends SignalController<
boolean activityOut = mCurrentState.dataConnected
&& !mCurrentState.carrierNetworkChangeMode
&& mCurrentState.activityOut;
- showDataIcon &= mCurrentState.isDefault
- || mCurrentState.iconGroup == TelephonyIcons.ROAMING
- || dataDisabled;
+ showDataIcon &= mCurrentState.isDefault || dataDisabled;
int typeIcon = showDataIcon ? icons.mDataType : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
- mSubscriptionInfo.getSubscriptionId());
+ mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
}
@Override
@@ -405,10 +401,9 @@ public class MobileSignalController extends SignalController<
mCurrentState.dataConnected = mCurrentState.connected
&& mDataState == TelephonyManager.DATA_CONNECTED;
+ mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
- } else if (isRoaming()) {
- mCurrentState.iconGroup = TelephonyIcons.ROAMING;
} else if (isDataDisabled()) {
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
@@ -541,6 +536,7 @@ public class MobileSignalController extends SignalController<
boolean carrierNetworkChangeMode;
boolean isDefault;
boolean userSetup;
+ boolean roaming;
@Override
public void copyFrom(State s) {
@@ -555,6 +551,7 @@ public class MobileSignalController extends SignalController<
airplaneMode = state.airplaneMode;
carrierNetworkChangeMode = state.carrierNetworkChangeMode;
userSetup = state.userSetup;
+ roaming = state.roaming;
}
@Override
@@ -565,6 +562,7 @@ public class MobileSignalController extends SignalController<
builder.append("networkName=").append(networkName).append(',');
builder.append("networkNameData=").append(networkNameData).append(',');
builder.append("dataConnected=").append(dataConnected).append(',');
+ builder.append("roaming=").append(roaming).append(',');
builder.append("isDefault=").append(isDefault).append(',');
builder.append("isEmergency=").append(isEmergency).append(',');
builder.append("airplaneMode=").append(airplaneMode).append(',');
@@ -584,7 +582,8 @@ public class MobileSignalController extends SignalController<
&& ((MobileState) o).airplaneMode == airplaneMode
&& ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
&& ((MobileState) o).userSetup == userSetup
- && ((MobileState) o).isDefault == isDefault;
+ && ((MobileState) o).isDefault == isDefault
+ && ((MobileState) o).roaming == roaming;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index a22fc6b8b72d..eb47a3cf195d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.policy;
import android.content.Context;
import android.content.Intent;
import android.telephony.SubscriptionInfo;
+import android.view.View;
+
import com.android.settingslib.net.DataUsageController;
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.DemoMode;
@@ -51,7 +53,7 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {}
+ String description, boolean isWide, int subId, boolean roaming) {}
default void setSubs(List<SubscriptionInfo> subs) {}
default void setNoSims(boolean show) {}
@@ -68,15 +70,29 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
public static class IconState {
public final boolean visible;
+
public final int icon;
+
+ /**
+ * Optional iconOverlay resource id.
+ *
+ * <p>Set to -1 if not present.
+ */
+ public final int iconOverlay;
+
public final String contentDescription;
- public IconState(boolean visible, int icon, String contentDescription) {
+ public IconState(boolean visible, int icon, int iconOverlay, String contentDescription) {
this.visible = visible;
this.icon = icon;
+ this.iconOverlay = iconOverlay;
this.contentDescription = contentDescription;
}
+ public IconState(boolean visible, int icon, String contentDescription) {
+ this(visible, icon, -1 /* iconOverlay */, contentDescription);
+ }
+
public IconState(boolean visible, int icon, int contentDescription,
Context context) {
this(visible, icon, context.getString(contentDescription));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index edf2c8a93650..d7c919d9348c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -24,6 +24,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
+import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -88,6 +89,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private final DataSaverController mDataSaverController;
private final CurrentUserTracker mUserTracker;
private Config mConfig;
+ private final NetworkScoreManager mNetworkScoreManager;
// Subcontrollers.
@VisibleForTesting
@@ -145,9 +147,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
public NetworkControllerImpl(Context context, Looper bgLooper,
DeviceProvisionedController deviceProvisionedController) {
this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
+ context.getSystemService(NetworkScoreManager.class),
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
(WifiManager) context.getSystemService(Context.WIFI_SERVICE),
- SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
+ SubscriptionManager.from(context),
+ Config.readConfig(context),
+ bgLooper,
new CallbackHandler(),
new AccessPointControllerImpl(context, bgLooper),
new DataUsageController(context),
@@ -158,8 +163,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
@VisibleForTesting
NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
- TelephonyManager telephonyManager, WifiManager wifiManager,
- SubscriptionManager subManager, Config config, Looper bgLooper,
+ NetworkScoreManager networkScoreManager,
+ TelephonyManager telephonyManager,
+ WifiManager wifiManager,
+ SubscriptionManager subManager,
+ Config config,
+ Looper bgLooper,
CallbackHandler callbackHandler,
AccessPointControllerImpl accessPointController,
DataUsageController dataUsageController,
@@ -182,6 +191,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
// wifi
mWifiManager = wifiManager;
+ mNetworkScoreManager = networkScoreManager;
mLocale = mContext.getResources().getConfiguration().locale;
mAccessPoints = accessPointController;
@@ -195,7 +205,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
});
mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
- mCallbackHandler, this);
+ mCallbackHandler, this, mNetworkScoreManager);
mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
@@ -799,6 +809,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
MobileSignalController controller = mMobileSignalControllers
.values().toArray(new MobileSignalController[0])[slot];
controller.getState().dataSim = datatype != null;
+ controller.getState().isDefault = datatype != null;
+ controller.getState().dataConnected = datatype != null;
if (datatype != null) {
controller.getState().iconGroup =
datatype.equals("1x") ? TelephonyIcons.ONE_X :
@@ -810,9 +822,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
datatype.equals("h") ? TelephonyIcons.H :
datatype.equals("lte") ? TelephonyIcons.LTE :
datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
- datatype.equals("roam") ? TelephonyIcons.ROAMING :
+ datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
TelephonyIcons.UNKNOWN;
}
+ if (args.containsKey("roam")) {
+ controller.getState().roaming = "show".equals(args.getString("roam"));
+ }
int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
String level = args.getString("level");
if (level != null) {
@@ -820,6 +835,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
: Math.min(Integer.parseInt(level), icons[0].length - 1);
controller.getState().connected = controller.getState().level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ controller.setActivity(Integer.parseInt(activity));
+ }
controller.getState().enabled = show;
controller.notifyListeners();
}
@@ -836,9 +855,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
null, 0, 0, "");
- mMobileSignalControllers.put(id, new MobileSignalController(mContext,
+ MobileSignalController controller = new MobileSignalController(mContext,
mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
- mSubDefaults, mReceiverHandler.getLooper()));
+ mSubDefaults, mReceiverHandler.getLooper());
+ mMobileSignalControllers.put(id, controller);
+ controller.getState().userSetup = true;
return info;
}
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 44ec2831dd9b..784f25e25a56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -56,6 +56,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.stack.ScrollContainer;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -90,6 +91,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private int mRevealR;
private boolean mResetting;
+ private NotificationViewWrapper mWrapper;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -210,11 +212,17 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(INVISIBLE);
+ if (mWrapper != null) {
+ mWrapper.setRemoteInputVisible(false);
+ }
}
});
reveal.start();
} else {
setVisibility(INVISIBLE);
+ if (mWrapper != null) {
+ mWrapper.setRemoteInputVisible(false);
+ }
}
}
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
@@ -267,6 +275,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEntry.notification.getPackageName());
setVisibility(VISIBLE);
+ if (mWrapper != null) {
+ mWrapper.setRemoteInputVisible(true);
+ }
mController.addRemoteInput(mEntry, mToken);
mEditText.setInnerFocusable(true);
mEditText.mShowImeOnInputConnection = true;
@@ -283,6 +294,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
// Update came in after we sent the reply, time to reset.
reset();
}
+
+ if (isActive() && mWrapper != null) {
+ mWrapper.setRemoteInputVisible(true);
+ }
}
private void reset() {
@@ -452,6 +467,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
super.dispatchFinishTemporaryDetach();
}
+ public void setWrapper(NotificationViewWrapper wrapper) {
+ mWrapper = wrapper;
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
deleted file mode 100644
index dce889f831da..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.policy;
-
-import android.telephony.SubscriptionInfo;
-
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-
-import java.util.List;
-
-
-/**
- * Provides empty implementations of SignalCallback for those that only want some of
- * the callbacks.
- */
-public class SignalCallbackAdapter implements SignalCallback {
-
- @Override
- public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description) {
- }
-
- @Override
- public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId) {
- }
-
- @Override
- public void setSubs(List<SubscriptionInfo> subs) {
- }
-
- @Override
- public void setNoSims(boolean show) {
- }
-
- @Override
- public void setEthernetIndicators(IconState icon) {
- }
-
- @Override
- public void setIsAirplaneMode(IconState icon) {
- }
-
- @Override
- public void setMobileDataEnabled(boolean enabled) {
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index b59cf6862292..6b2361e64da0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -95,8 +95,6 @@ class TelephonyIcons {
R.drawable.ic_qs_signal_carrier_network_change_animation }
};
- static final int QS_DATA_R = R.drawable.ic_qs_signal_r;
-
//***** Data connection icons
//GSM/UMTS
@@ -211,7 +209,7 @@ class TelephonyIcons {
static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus;
static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
- static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam;
+ static final int ROAMING_ICON = R.drawable.stat_sys_roaming;
static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus;
static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
@@ -224,7 +222,7 @@ class TelephonyIcons {
static final int ICON_CARRIER_NETWORK_CHANGE =
R.drawable.stat_sys_signal_carrier_network_change_animation;
- static final int ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
+ static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
@@ -410,21 +408,6 @@ class TelephonyIcons {
TelephonyIcons.QS_DATA_LTE_PLUS
);
- static final MobileIconGroup ROAMING = new MobileIconGroup(
- "Roaming",
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
- AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
- 0, 0,
- TelephonyIcons.TELEPHONY_NO_NETWORK,
- TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
- AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_roaming,
- TelephonyIcons.ROAMING_ICON,
- false,
- TelephonyIcons.QS_DATA_R
- );
-
static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
"DataDisabled",
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index f71c5d1dc41c..7a32bf1c8d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -61,6 +61,7 @@ import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.util.NotificationChannels;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -559,18 +560,20 @@ public class UserSwitcherController {
private void showLogoutNotification(int userId) {
PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
- Notification.Builder builder = new Notification.Builder(mContext)
- .setVisibility(Notification.VISIBILITY_SECRET)
- .setPriority(Notification.PRIORITY_MIN)
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle(mContext.getString(R.string.user_logout_notification_title))
- .setContentText(mContext.getString(R.string.user_logout_notification_text))
- .setContentIntent(logoutPI)
- .setOngoing(true)
- .setShowWhen(false)
- .addAction(R.drawable.ic_delete,
- mContext.getString(R.string.user_logout_notification_action),
- logoutPI);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.GENERAL)
+ .setVisibility(Notification.VISIBILITY_SECRET)
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle(mContext.getString(
+ R.string.user_logout_notification_title))
+ .setContentText(mContext.getString(
+ R.string.user_logout_notification_text))
+ .setContentIntent(logoutPI)
+ .setOngoing(true)
+ .setShowWhen(false)
+ .addAction(R.drawable.ic_delete,
+ mContext.getString(R.string.user_logout_notification_action),
+ logoutPI);
SystemUI.overrideNotificationAppName(mContext, builder);
NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER,
SystemMessage.NOTE_LOGOUT_USER, builder.build(), new UserHandle(userId));
@@ -583,17 +586,17 @@ public class UserSwitcherController {
PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
- Notification.Builder builder = new Notification.Builder(mContext)
- .setVisibility(Notification.VISIBILITY_SECRET)
- .setPriority(Notification.PRIORITY_MIN)
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle(mContext.getString(R.string.guest_notification_title))
- .setContentText(mContext.getString(R.string.guest_notification_text))
- .setContentIntent(removeGuestPI)
- .setShowWhen(false)
- .addAction(R.drawable.ic_delete,
- mContext.getString(R.string.guest_notification_remove_action),
- removeGuestPI);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.GENERAL)
+ .setVisibility(Notification.VISIBILITY_SECRET)
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle(mContext.getString(R.string.guest_notification_title))
+ .setContentText(mContext.getString(R.string.guest_notification_text))
+ .setContentIntent(removeGuestPI)
+ .setShowWhen(false)
+ .addAction(R.drawable.ic_delete,
+ mContext.getString(R.string.guest_notification_remove_action),
+ removeGuestPI);
SystemUI.overrideNotificationAppName(mContext, builder);
NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST,
SystemMessage.NOTE_REMOVE_GUEST, builder.build(), new UserHandle(guestUserId));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index b1bc2f07a414..886b8bebac81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -15,18 +15,27 @@
*/
package com.android.systemui.statusbar.policy;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.NetworkCapabilities;
+import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
+import android.net.ScoredNetwork;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.WifiNetworkScoreCache.CacheListener;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
+import com.android.settingslib.Utils;
import com.android.settingslib.wifi.WifiStatusTracker;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -34,17 +43,24 @@ import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.R;
import java.util.Objects;
+import java.util.List;
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
+
private final WifiManager mWifiManager;
private final AsyncChannel mWifiChannel;
private final boolean mHasMobileData;
+ private final NetworkScoreManager mNetworkScoreManager;
+ private final WifiNetworkScoreCache mScoreCache;
private final WifiStatusTracker mWifiTracker;
+ private boolean mScoringUiEnabled = false;
+
public WifiSignalController(Context context, boolean hasMobileData,
- CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
+ CallbackHandler callbackHandler, NetworkControllerImpl networkController,
+ NetworkScoreManager networkScoreManager) {
super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
callbackHandler, networkController);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -68,6 +84,45 @@ public class WifiSignalController extends
WifiIcons.QS_WIFI_NO_NETWORK,
AccessibilityContentDescriptions.WIFI_NO_CONNECTION
);
+
+ mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(handler) {
+ @Override
+ public void networkCacheUpdated(List<ScoredNetwork> networks) {
+ mCurrentState.badgeEnum = getWifiBadgeEnum();
+ notifyListenersIfNecessary();
+ }
+ });
+
+ // Setup scoring
+ mNetworkScoreManager = networkScoreManager;
+ configureScoringGating();
+ registerScoreCache();
+ }
+
+ private void configureScoringGating() {
+ ContentObserver observer = new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mScoringUiEnabled =
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1;
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.NETWORK_SCORING_UI_ENABLED),
+ false /* notifyForDescendants */,
+ observer);
+
+ observer.onChange(false /* selfChange */); // Set the initial values
+ }
+
+ private void registerScoreCache() {
+ Log.d(mTag, "Registered score cache");
+ mNetworkScoreManager.registerNetworkScoreCache(
+ NetworkKey.TYPE_WIFI,
+ mScoreCache,
+ NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
}
@Override
@@ -88,27 +143,74 @@ public class WifiSignalController extends
("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
}
- IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
- IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
- contentDescription);
+ IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(),
+ Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription);
+ IconState qsIcon = new IconState(
+ mCurrentState.connected, getQsCurrentIconId(),
+ Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription);
callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
wifiDesc);
}
+ @Override
+ public int getCurrentIconId() {
+ if (mCurrentState.badgeEnum != ScoredNetwork.BADGING_NONE) {
+ return Utils.WIFI_PIE_FOR_BADGING[mCurrentState.level];
+ }
+ return super.getCurrentIconId();
+ }
+
/**
* Extract wifi state directly from broadcasts about changes in wifi state.
*/
public void handleBroadcast(Intent intent) {
+ // Update the WifiStatusTracker with the new information and update the score cache.
+ NetworkKey previousNetworkKey = mWifiTracker.networkKey;
mWifiTracker.handleBroadcast(intent);
+ updateScoreCacheIfNecessary(previousNetworkKey);
+
mCurrentState.enabled = mWifiTracker.enabled;
mCurrentState.connected = mWifiTracker.connected;
mCurrentState.ssid = mWifiTracker.ssid;
mCurrentState.rssi = mWifiTracker.rssi;
mCurrentState.level = mWifiTracker.level;
+ mCurrentState.badgeEnum = getWifiBadgeEnum();
notifyListenersIfNecessary();
}
+ /**
+ * Clears old scores out of the cache and requests new scores if the network key has changed.
+ *
+ * <p>New scores are requested asynchronously.
+ */
+ private void updateScoreCacheIfNecessary(NetworkKey previousNetworkKey) {
+ if (mWifiTracker.networkKey == null) {
+ return;
+ }
+ if ((previousNetworkKey == null) || !mWifiTracker.networkKey.equals(previousNetworkKey)) {
+ mScoreCache.clearScores();
+ mNetworkScoreManager.requestScores(new NetworkKey[]{mWifiTracker.networkKey});
+ }
+ }
+
+ /**
+ * Returns the wifi badge enum for the current {@link #mWifiTracker} state.
+ *
+ * <p>{@link #updateScoreCacheIfNecessary} should be called prior to this method.
+ */
+ private int getWifiBadgeEnum() {
+ if (!mScoringUiEnabled || mWifiTracker.networkKey == null) {
+ return ScoredNetwork.BADGING_NONE;
+ }
+ ScoredNetwork score = mScoreCache.getScoredNetwork(mWifiTracker.networkKey);
+
+ if (score != null) {
+ return score.calculateBadge(mWifiTracker.rssi);
+ }
+ return ScoredNetwork.BADGING_NONE;
+ }
+
@VisibleForTesting
void setActivity(int wifiActivity) {
mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
@@ -149,12 +251,14 @@ public class WifiSignalController extends
static class WifiState extends SignalController.State {
String ssid;
+ int badgeEnum;
@Override
public void copyFrom(State s) {
super.copyFrom(s);
WifiState state = (WifiState) s;
ssid = state.ssid;
+ badgeEnum = state.badgeEnum;
}
@Override
@@ -166,7 +270,8 @@ public class WifiSignalController extends
@Override
public boolean equals(Object o) {
return super.equals(o)
- && Objects.equals(((WifiState) o).ssid, ssid);
+ && Objects.equals(((WifiState) o).ssid, ssid)
+ && (((WifiState) o).badgeEnum == badgeEnum);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 1a2d778d206b..e6a3add627f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -78,6 +78,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
private int mClipBottomAmount;
+ private boolean mIsLowPriority;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -246,10 +247,13 @@ public class NotificationChildrenContainer extends ViewGroup {
return mChildren.size();
}
- public void recreateNotificationHeader(OnClickListener listener, StatusBarNotification notification) {
+ public void recreateNotificationHeader(OnClickListener listener,
+ StatusBarNotification notification) {
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
mNotificationParent.getStatusBarNotification().getNotification());
- final RemoteViews header = builder.makeNotificationHeader();
+ final RemoteViews header = mIsLowPriority
+ ? builder.makeLowPriorityContentView(true /* useRegularSubtext */)
+ : builder.makeNotificationHeader();
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
@@ -262,7 +266,7 @@ public class NotificationChildrenContainer extends ViewGroup {
invalidate();
} else {
header.reapply(getContext(), mNotificationHeader);
- mNotificationHeaderWrapper.notifyContentUpdated(notification);
+ mNotificationHeaderWrapper.notifyContentUpdated(notification, mIsLowPriority);
}
updateChildrenHeaderAppearance();
}
@@ -367,6 +371,9 @@ public class NotificationChildrenContainer extends ViewGroup {
* @return the intrinsic size of this children container, i.e the natural fully expanded state
*/
public int getIntrinsicHeight() {
+ if (mIsLowPriority && !mChildrenExpanded) {
+ return mNotificationHeader.getHeight();
+ }
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
return getIntrinsicHeight(maxAllowedVisibleChildren);
}
@@ -480,7 +487,7 @@ public class NotificationChildrenContainer extends ViewGroup {
childState.clipTopAmount = 0;
childState.alpha = 0;
if (i < firstOverflowIndex) {
- childState.alpha = 1;
+ childState.alpha = mIsLowPriority && !mChildrenExpanded ? expandFactor : 1.0f;
} else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
@@ -828,6 +835,9 @@ public class NotificationChildrenContainer extends ViewGroup {
}
private int getMinHeight(int maxAllowedVisibleChildren) {
+ if (mIsLowPriority && !mChildrenExpanded) {
+ return mNotificationHeader.getHeight();
+ }
int minExpandHeight = mNotificationHeaderMargin;
int visibleChildren = 0;
boolean firstChild = true;
@@ -922,4 +932,8 @@ public class NotificationChildrenContainer extends ViewGroup {
mClipBottomAmount = clipBottomAmount;
updateChildrenClipping();
}
+
+ public void setIsLowPriority(boolean isLowPriority) {
+ mIsLowPriority = isLowPriority;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 395e8f2a1d56..11927729d472 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -27,6 +27,7 @@ import android.annotation.FloatRange;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -55,7 +56,6 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.OverScroller;
import android.widget.ScrollView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.ExpandHelper;
@@ -63,14 +63,15 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationGuts;
-import com.android.systemui.statusbar.NotificationSettingsIconRow;
-import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
+import com.android.systemui.statusbar.NotificationMenuRow;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
@@ -78,7 +79,7 @@ import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -94,7 +95,8 @@ import java.util.HashSet;
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- SettingsIconRowListener, ScrollContainer, VisibilityLocationProvider {
+ NotificationMenuRowProvider.OnMenuClickListener, ScrollContainer,
+ VisibilityLocationProvider {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -112,6 +114,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
+ private boolean mShouldDrawNotificationBackground;
private float mExpandedHeight;
private int mOwnScrollY;
@@ -224,9 +227,10 @@ public class NotificationStackScrollLayout extends ViewGroup
private int mMaxScrollAfterExpand;
private SwipeHelper.LongPressListener mLongPressListener;
- private NotificationSettingsIconRow mCurrIconRow;
+ private NotificationMenuRow mCurrIconRow;
private View mTranslatingParentView;
private View mGearExposedView;
+ private boolean mShouldShowGear;
/**
* Should in this touch motion only be scrolling allowed? It's true when the scroller was
@@ -249,7 +253,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return true;
}
};
- private PhoneStatusBar mPhoneStatusBar;
+ private StatusBar mStatusBar;
private int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
private HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
@@ -376,10 +380,12 @@ public class NotificationStackScrollLayout extends ViewGroup
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ Resources res = getResources();
+
mAmbientState = new AmbientState(context);
mBgColor = context.getColor(R.color.notification_shade_background_color);
- int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
- int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
+ int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
mExpandHelper = new ExpandHelper(getContext(), this,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
@@ -388,27 +394,35 @@ public class NotificationStackScrollLayout extends ViewGroup
mSwipeHelper.setLongPressListener(mLongPressListener);
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
initView(context);
- setWillNotDraw(false);
+ mFalsingManager = FalsingManager.getInstance(context);
+ mShouldShowGear = res.getBoolean(R.bool.config_showNotificationGear);
+ mShouldDrawNotificationBackground =
+ res.getBoolean(R.bool.config_drawNotificationBackground);
+
+ updateWillNotDraw();
if (DEBUG) {
mDebugPaint = new Paint();
mDebugPaint.setColor(0xffff0000);
mDebugPaint.setStrokeWidth(2);
mDebugPaint.setStyle(Paint.Style.STROKE);
}
- mFalsingManager = FalsingManager.getInstance(context);
}
@Override
- public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
- if (mLongPressListener != null) {
+ public void onMenuClicked(View view, int x, int y, MenuItem item) {
+ if (mLongPressListener == null) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
row.getStatusBarNotification().getPackageName());
- mLongPressListener.onLongPress(row, x, y);
}
+ mLongPressListener.onLongPress(view, x, y, item);
}
@Override
- public void onSettingsIconRowReset(ExpandableNotificationRow row) {
+ public void onMenuReset(View row) {
if (mTranslatingParentView != null && row == mTranslatingParentView) {
mSwipeHelper.setSnappedToGear(false);
mGearExposedView = null;
@@ -418,14 +432,15 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
protected void onDraw(Canvas canvas) {
- if (mCurrentBounds.top < mCurrentBounds.bottom) {
+ if (mShouldDrawNotificationBackground && mCurrentBounds.top < mCurrentBounds.bottom) {
canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom,
mBackgroundPaint);
}
+
if (DEBUG) {
int y = mTopPadding;
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- y = (int) getLayoutHeight();
+ y = getLayoutHeight();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
y = getHeight() - getEmptyBottomMargin();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -433,6 +448,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateBackgroundDimming() {
+ // No need to update the background color if it's not being drawn.
+ if (!mShouldDrawNotificationBackground) {
+ return;
+ }
+
float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
alpha *= mBackgroundFadeAmount;
// We need to manually blend in the background color
@@ -481,6 +501,10 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateSrcDrawing() {
+ if (!mShouldDrawNotificationBackground) {
+ return;
+ }
+
mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadingOut && !mParentNotFullyVisible
? mSrcMode : null);
invalidate();
@@ -606,9 +630,9 @@ public class NotificationStackScrollLayout extends ViewGroup
ExpandableView child = (ExpandableView) getChildAt(i);
if (mChildrenToAddAnimated.contains(child)) {
int startingPosition = getPositionInLinearLayout(child);
- int padding = child.getIncreasedPaddingAmount() == 1.0f
- ? mIncreasedPaddingBetweenElements :
- mPaddingBetweenElements;
+ float increasedPaddingAmount = child.getIncreasedPaddingAmount();
+ int padding = increasedPaddingAmount == 1.0f ? mIncreasedPaddingBetweenElements
+ : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
int childHeight = getIntrinsicHeight(child) + padding;
if (startingPosition < mOwnScrollY) {
// This child starts off screen, so let's keep it offscreen to keep the others visible
@@ -871,7 +895,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mFalsingManager.onNotificationDismissed();
if (mFalsingManager.shouldEnforceBouncer()) {
- mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
+ mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
}
@@ -911,7 +935,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDragAnimPendingChildren.remove(animView);
}
if (mCurrIconRow != null && targetLeft == 0) {
- mCurrIconRow.resetState();
+ mCurrIconRow.resetState(true /* notify */);
mCurrIconRow = null;
}
}
@@ -962,7 +986,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public float getFalsingThresholdFactor() {
- return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
@@ -1880,7 +1904,8 @@ public class NotificationStackScrollLayout extends ViewGroup
private void updateContentHeight() {
int height = 0;
- float previousIncreasedAmount = 0.0f;
+ float previousPaddingRequest = mPaddingBetweenElements;
+ float previousPaddingAmount = 0.0f;
int numShownItems = 0;
boolean finish = false;
int maxDisplayedNotifications = mAmbientState.isDark()
@@ -1897,13 +1922,35 @@ public class NotificationStackScrollLayout extends ViewGroup
finish = true;
}
float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
- if (height != 0) {
- height += (int) NotificationUtils.interpolate(
+ float padding;
+ if (increasedPaddingAmount >= 0.0f) {
+ padding = (int) NotificationUtils.interpolate(
+ previousPaddingRequest,
+ mIncreasedPaddingBetweenElements,
+ increasedPaddingAmount);
+ previousPaddingRequest = (int) NotificationUtils.interpolate(
mPaddingBetweenElements,
mIncreasedPaddingBetweenElements,
- Math.max(previousIncreasedAmount, increasedPaddingAmount));
+ 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;
}
- previousIncreasedAmount = increasedPaddingAmount;
+ previousPaddingAmount = increasedPaddingAmount;
height += expandableView.getIntrinsicHeight();
numShownItems++;
if (finish) {
@@ -1938,9 +1985,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateBackground() {
- if (mAmbientState.isDark()) {
+ // No need to update the background color if it's not being drawn.
+ if (!mShouldDrawNotificationBackground || mAmbientState.isDark()) {
return;
}
+
updateBackgroundBounds();
if (!mCurrentBounds.equals(mBackgroundBounds)) {
boolean animate = mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom
@@ -2090,6 +2139,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void applyCurrentBackgroundBounds() {
+ // If the background of the notification is not being drawn, then there is no need to
+ // exclude an area in the scrim. Rather, the scrim's color should serve as the background.
+ if (!mShouldDrawNotificationBackground) {
+ return;
+ }
+
mScrimController.setExcludedBackgroundArea(
mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null
: mCurrentBounds);
@@ -2566,10 +2621,19 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
- int padding = (int) NotificationUtils.interpolate(
- mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- removedChild.getIncreasedPaddingAmount());
+ 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;
if (endPosition <= mOwnScrollY) {
@@ -2601,19 +2665,42 @@ public class NotificationStackScrollLayout extends ViewGroup
requestedView = requestedRow = childInGroup.getNotificationParent();
}
int position = 0;
- float previousIncreasedAmount = 0.0f;
+ 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();
- if (position != 0) {
- position += (int) NotificationUtils.interpolate(
+ float padding;
+ if (increasedPaddingAmount >= 0.0f) {
+ padding = (int) NotificationUtils.interpolate(
+ previousPaddingRequest,
+ mIncreasedPaddingBetweenElements,
+ increasedPaddingAmount);
+ previousPaddingRequest = (int) NotificationUtils.interpolate(
mPaddingBetweenElements,
mIncreasedPaddingBetweenElements,
- Math.max(previousIncreasedAmount, increasedPaddingAmount));
+ 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;
}
- previousIncreasedAmount = increasedPaddingAmount;
+ previousPaddingAmount = increasedPaddingAmount;
}
if (child == requestedView) {
if (requestedRow != null) {
@@ -2679,6 +2766,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private void updateNotificationAnimationStates() {
boolean running = mAnimationsEnabled || mPulsing;
+ mShelf.setAnimationsEnabled(running);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
@@ -3161,7 +3249,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mAmbientState.setExpansionChanging(false);
if (!mIsExpanded) {
setOwnScrollY(0);
- mPhoneStatusBar.resetUserExpandedStates();
+ mStatusBar.resetUserExpandedStates();
// lets make sure nothing is in the overlay / transient anymore
clearTemporaryViews(this);
@@ -3484,16 +3572,29 @@ public class NotificationStackScrollLayout extends ViewGroup
}
requestChildrenUpdate();
if (dark) {
- setWillNotDraw(!DEBUG);
mScrimController.setExcludedBackgroundArea(null);
} else {
updateBackground();
- setWillNotDraw(false);
}
+
+ updateWillNotDraw();
updateContentHeight();
notifyHeightChangeListener(mShelf);
}
+ /**
+ * Updates whether or not this Layout will perform its own custom drawing (i.e. whether or
+ * not {@link #onDraw(Canvas)} is called). This method should be called whenever the
+ * {@link #mAmbientState}'s dark mode is toggled.
+ */
+ private void updateWillNotDraw() {
+ if (mAmbientState.isDark()) {
+ setWillNotDraw(!DEBUG);
+ } else {
+ setWillNotDraw(!mShouldDrawNotificationBackground && !DEBUG);
+ }
+ }
+
private void setBackgroundFadeAmount(float fadeAmount) {
mBackgroundFadeAmount = fadeAmount;
updateBackgroundDimming();
@@ -3696,8 +3797,8 @@ public class NotificationStackScrollLayout extends ViewGroup
return max + getStackTranslation();
}
- public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
- this.mPhoneStatusBar = phoneStatusBar;
+ public void setStatusBar(StatusBar statusBar) {
+ this.mStatusBar = statusBar;
}
public void setGroupManager(NotificationGroupManager groupManager) {
@@ -3768,7 +3869,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
- mPhoneStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate();
}
/** @hide */
@@ -3836,7 +3937,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public void onGroupsChanged() {
- mPhoneStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate();
}
public void generateChildOrderChangedEvent() {
@@ -4045,14 +4146,14 @@ public class NotificationStackScrollLayout extends ViewGroup
* A listener that is notified when some child locations might have changed.
*/
public interface OnChildLocationsChangedListener {
- public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
+ void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
}
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
public interface OnEmptySpaceClickListener {
- public void onEmptySpaceClicked(float x, float y);
+ void onEmptySpaceClicked(float x, float y);
}
/**
@@ -4068,7 +4169,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* unrubberbanded motion to directly expand overscroll view (e.g expand
* QS)
*/
- public void onOverscrollTopChanged(float amount, boolean isRubberbanded);
+ void onOverscrollTopChanged(float amount, boolean isRubberbanded);
/**
* Notify a listener that the scroller wants to escape from the scrolling motion and
@@ -4077,7 +4178,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param velocity The velocity that the Scroller had when over flinging
* @param open Should the fling open or close the overscroll view.
*/
- public void flingTopOverscroll(float velocity, boolean open);
+ void flingTopOverscroll(float velocity, boolean open);
}
private class NotificationSwipeHelper extends SwipeHelper {
@@ -4121,7 +4222,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (currView instanceof ExpandableNotificationRow) {
// Set the listener for the current row's gear
mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
- mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
+ mCurrIconRow.setMenuClickListener(NotificationStackScrollLayout.this);
}
}
@@ -4133,9 +4234,9 @@ public class NotificationStackScrollLayout extends ViewGroup
mCurrIconRow.setSnapping(false); // If we're moving, we're not snapping.
// If the gear is visible and the movement is towards it it's not a location change.
- boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isIconOnLeft();
+ boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isMenuOnLeft();
boolean locationChange = isTowardsGear(translation, onLeft)
- ? false : mCurrIconRow.isIconLocationChange(translation);
+ ? false : mCurrIconRow.isMenuLocationChange(translation);
if (locationChange) {
// Don't consider it "snapped" if location has changed.
setSnappedToGear(false);
@@ -4146,8 +4247,8 @@ public class NotificationStackScrollLayout extends ViewGroup
mCheckForDrag = null;
} else {
// Check scheduled, reset alpha and update location; check will fade it in
- mCurrIconRow.setGearAlpha(0f);
- mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
+ mCurrIconRow.setMenuAlpha(0f);
+ mCurrIconRow.setMenuLocation((int) translation);
}
}
}
@@ -4155,7 +4256,7 @@ public class NotificationStackScrollLayout extends ViewGroup
final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
&& ((ExpandableNotificationRow) view).areGutsExposed();
- if (!isPinnedHeadsUp(view) && !gutsExposed) {
+ if (mShouldShowGear && !isPinnedHeadsUp(view) && !gutsExposed) {
// Only show the gear if we're not a heads up view and guts aren't exposed.
checkForDrag();
}
@@ -4198,14 +4299,22 @@ public class NotificationStackScrollLayout extends ViewGroup
return false; // Let SwipeHelper handle it.
}
- boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
+ // If the gear icon should not be shown, then there is no need to check if the a swipe
+ // should result in a snapping to the gear icon. As a result, just check if the swipe
+ // was enough to dismiss the notification.
+ if (!mShouldShowGear) {
+ dismissOrSnapBack(animView, velocity, ev);
+ return true;
+ }
+
+ boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isMenuOnLeft());
boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
final double timeForGesture = ev.getEventTime() - ev.getDownTime();
final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView)
- && timeForGesture >= SWIPE_GEAR_TIMING;
+ && timeForGesture >= SWIPE_GEAR_TIMING;
if (mGearSnappedTo && mCurrIconRow.isVisible()) {
- if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
+ if (mGearSnappedOnLeft == mCurrIconRow.isMenuOnLeft()) {
boolean coveringGear =
Math.abs(getTranslation(animView)) <= getSpaceForGear(animView) * 0.6f;
if (gestureTowardsGear || coveringGear) {
@@ -4249,7 +4358,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private void snapToGear(View animView, float velocity) {
final float snapBackThreshold = getSpaceForGear(animView);
- final float target = mCurrIconRow.isIconOnLeft() ? snapBackThreshold
+ final float target = mCurrIconRow.isMenuOnLeft() ? snapBackThreshold
: -snapBackThreshold;
mGearExposedView = mTranslatingParentView;
if (animView instanceof ExpandableNotificationRow) {
@@ -4280,7 +4389,7 @@ public class NotificationStackScrollLayout extends ViewGroup
final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
final float snapBackThreshold = getSpaceForGear(animView) * multiplier;
final float translation = getTranslation(animView);
- return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
+ return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isMenuOnLeft()
? translation > snapBackThreshold
: translation < -snapBackThreshold);
}
@@ -4306,7 +4415,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mPhoneStatusBar.getExposedGuts();
+ NotificationGuts guts = mStatusBar.getExposedGuts();
View view = null;
int height = 0;
if (guts != null) {
@@ -4329,7 +4438,7 @@ public class NotificationStackScrollLayout extends ViewGroup
Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
if (!rect.contains(rx, ry)) {
// Touch was outside visible guts / gear notification, close what's visible
- mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
+ mStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
}
}
}
@@ -4349,7 +4458,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* Indicates the the gear has been snapped to.
*/
private void setSnappedToGear(boolean snapped) {
- mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isIconOnLeft() : false;
+ mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isMenuOnLeft() : false;
mGearSnappedTo = snapped && mCurrIconRow != null;
}
@@ -4389,11 +4498,11 @@ public class NotificationStackScrollLayout extends ViewGroup
final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
if ((mCurrIconRow != null && (!mCurrIconRow.isVisible()
- || mCurrIconRow.isIconLocationChange(translation)))
+ || mCurrIconRow.isMenuLocationChange(translation)))
&& absTransX >= bounceBackToGearWidth * 0.4
&& absTransX < notiThreshold) {
// Fade in the gear
- mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
+ mCurrIconRow.fadeInMenu(translation > 0 /* fromLeft */, translation,
notiThreshold);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 7ff100081677..ba91ffd04c0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -27,7 +27,6 @@ import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import java.util.ArrayList;
@@ -244,7 +243,7 @@ public class StackScrollAlgorithm {
int childCount = hostView.getChildCount();
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
- state.increasedPaddingMap.clear();
+ state.paddingMap.clear();
int notGoneIndex = 0;
ExpandableView lastView = null;
for (int i = 0; i < childCount; i++) {
@@ -254,16 +253,31 @@ public class StackScrollAlgorithm {
continue;
}
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
- float increasedPadding = v.getIncreasedPaddingAmount();
+ float increasedPadding = v.getIncreasedPaddingAmount();;
if (increasedPadding != 0.0f) {
- state.increasedPaddingMap.put(v, increasedPadding);
+ state.paddingMap.put(v, increasedPadding);
if (lastView != null) {
- Float prevValue = state.increasedPaddingMap.get(lastView);
- float newValue = prevValue != null
- ? Math.max(prevValue, increasedPadding)
- : increasedPadding;
- state.increasedPaddingMap.put(lastView, newValue);
+ 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) {
+ float newValue = getPaddingForValue(state.paddingMap.get(lastView));
+ state.paddingMap.put(lastView, newValue);
}
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -287,6 +301,22 @@ public class StackScrollAlgorithm {
}
}
+ 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(StackScrollState resultState,
StackScrollAlgorithmState state, int notGoneIndex,
ExpandableView v) {
@@ -527,18 +557,17 @@ public class StackScrollAlgorithm {
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
/**
- * The children from the host that need an increased padding after them. A value of 0 means
- * no increased padding, a value of 1 means full padding.
+ * The padding after each child measured in pixels.
*/
- public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
+ public final HashMap<ExpandableView, Float> paddingMap = new HashMap<>();
public int getPaddingAfterChild(ExpandableView child) {
- Float paddingValue = increasedPaddingMap.get(child);
- return paddingValue == null
- ? mPaddingBetweenElements
- : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- paddingValue);
+ Float padding = paddingMap.get(child);
+ if (padding == null) {
+ // Should only happen for the last view
+ return mPaddingBetweenElements;
+ }
+ return (int) padding.floatValue();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 9b8183be06de..5d11ef34bf1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,157 +17,29 @@
package com.android.systemui.statusbar.tv;
import android.content.ComponentName;
+import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.StatusBarNotification;
-import android.view.View;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.statusbar.ActivatableNotificationView;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.SystemUI;
import com.android.systemui.pip.tv.PipManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+
+import java.util.ArrayList;
/**
* Status bar implementation for "large screen" products that mostly present no on-screen nav
*/
-public class TvStatusBar extends BaseStatusBar {
-
- @Override
- public void setIcon(String slot, StatusBarIcon icon) {
- }
-
- @Override
- public void removeIcon(String slot) {
- }
-
- @Override
- public void addNotification(StatusBarNotification notification, RankingMap ranking,
- NotificationData.Entry entry) {
- }
-
- @Override
- protected void updateNotificationRanking(RankingMap ranking) {
- }
-
- @Override
- public void removeNotification(String key, RankingMap ranking) {
- }
-
- @Override
- public void disable(int state1, int state2, boolean animate) {
- }
-
- @Override
- public void animateExpandNotificationsPanel() {
- }
-
- @Override
- public void animateCollapsePanels(int flags) {
- }
-
- @Override
- public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
- }
-
- @Override
- public void topAppWindowChanged(boolean visible) {
- }
-
- @Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
- }
-
- @Override // CommandQueue
- public void setWindowState(int window, int state) {
- }
-
- @Override // CommandQueue
- public void buzzBeepBlinked() {
- }
-
- @Override // CommandQueue
- public void notificationLightOff() {
- }
-
- @Override // CommandQueue
- public void notificationLightPulse(int argb, int onMillis, int offMillis) {
- }
-
- @Override
- protected void setAreThereNotifications() {
- }
-
- @Override
- protected void updateNotifications() {
- }
-
- public View getStatusBarView() {
- return null;
- }
-
- @Override
- protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
- return false;
- }
-
- @Override
- public void maybeEscalateHeadsUp() {
- }
-
- @Override
- public boolean isPanelFullyCollapsed() {
- return false;
- }
-
- @Override
- protected int getMaxKeyguardNotifications(boolean recompute) {
- return 0;
- }
-
- @Override
- public void animateExpandSettingsPanel(String subPanel) {
- }
-
- @Override
- protected void createAndAddWindows() {
- }
-
- @Override
- public void onActivated(ActivatableNotificationView view) {
- }
-
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- }
-
- @Override
- public void showScreenPinningRequest(int taskId) {
- }
+public class TvStatusBar extends SystemUI implements Callbacks {
- @Override
- public void appTransitionPending() {
- }
-
- @Override
- public void appTransitionCancelled() {
- }
-
- @Override
- public void appTransitionStarting(long startTime, long duration) {
- }
-
- @Override
- public void appTransitionFinished() {
- }
-
- @Override
- public void onCameraLaunchGestureDetected(int source) {
- }
+ private IStatusBarService mBarService;
@Override
public void showTvPictureInPictureMenu() {
@@ -175,38 +47,24 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldPeek,
- boolean alertAgain) {
- }
-
- @Override
- protected void setHeadsUpUser(int newUserId) {
- }
-
- protected boolean isSnoozedPackage(StatusBarNotification sbn) {
- return false;
- }
-
- @Override
- public void addQsTile(ComponentName tile) {
- }
-
- @Override
- public void remQsTile(ComponentName tile) {
- }
-
- @Override
- public void clickTile(ComponentName tile) {
- }
-
- @Override
public void start() {
- super.start();
putComponent(TvStatusBar.class, this);
+ CommandQueue commandQueue = getComponent(CommandQueue.class);
+ commandQueue.addCallbacks(this);
+ int[] switches = new int[9];
+ ArrayList<IBinder> binders = new ArrayList<>();
+ ArrayList<String> iconSlots = new ArrayList<>();
+ ArrayList<StatusBarIcon> icons = new ArrayList<>();
+ Rect fullscreenStackBounds = new Rect();
+ Rect dockedStackBounds = new Rect();
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ try {
+ mBarService.registerStatusBar(commandQueue, iconSlots, icons, switches, binders,
+ fullscreenStackBounds, dockedStackBounds);
+ } catch (RemoteException ex) {
+ // If the system process isn't there we're doomed anyway.
+ }
}
- @Override
- public void handleSystemNavigationKey(int arg1) {
- // Not implemented
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index 9998283e1a05..ee0116ec7dc6 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -22,9 +22,10 @@ import android.util.ArraySet;
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
+import static com.android.settingslib.graph.BatteryMeterDrawableBase.SHOW_PERCENT_SETTING;
public class BatteryPreference extends DropDownPreference implements TunerService.Tunable {
@@ -49,12 +50,12 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
super.onAttached();
mHasPercentage = Settings.System.getInt(getContext().getContentResolver(),
SHOW_PERCENT_SETTING, 0) != 0;
- TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
}
@Override
public void onDetached() {
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
super.onDetached();
}
@@ -89,7 +90,7 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
} else {
mBlacklist.remove(mBattery);
}
- TunerService.get(getContext()).setValue(StatusBarIconController.ICON_BLACKLIST,
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
TextUtils.join(",", mBlacklist));
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BetterListPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BetterListPreference.java
new file mode 100644
index 000000000000..c9c780aa6a70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BetterListPreference.java
@@ -0,0 +1,39 @@
+/*
+ * 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.tuner;
+
+import android.content.Context;
+import android.support.v7.preference.ListPreference;
+import android.util.AttributeSet;
+
+public class BetterListPreference extends ListPreference {
+
+ private CharSequence mSummary;
+
+ public BetterListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void setSummary(CharSequence summary) {
+ super.setSummary(summary);
+ mSummary = summary;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mSummary;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
index caa0527625d9..014ec9279395 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -18,6 +18,8 @@ import android.support.v7.preference.DropDownPreference;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
+
+import com.android.systemui.Dependency;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
@@ -44,13 +46,13 @@ public class ClockPreference extends DropDownPreference implements TunerService.
@Override
public void onAttached() {
super.onAttached();
- TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
Clock.CLOCK_SECONDS);
}
@Override
public void onDetached() {
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
super.onDetached();
}
@@ -81,13 +83,14 @@ public class ClockPreference extends DropDownPreference implements TunerService.
@Override
protected boolean persistString(String value) {
- TunerService.get(getContext()).setValue(Clock.CLOCK_SECONDS, SECONDS.equals(value) ? 1 : 0);
+ Dependency.get(TunerService.class).setValue(Clock.CLOCK_SECONDS, SECONDS.equals(value) ? 1
+ : 0);
if (DISABLED.equals(value)) {
mBlacklist.add(mClock);
} else {
mBlacklist.remove(mClock);
}
- TunerService.get(getContext()).setValue(StatusBarIconController.ICON_BLACKLIST,
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
TextUtils.join(",", mBlacklist));
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
deleted file mode 100644
index 096ecc0b8bae..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.tuner;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.view.KeyEvent;
-
-import com.android.systemui.R;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-
-public class KeycodeSelectionHelper {
-
- private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
- private static final ArrayList<Integer> mKeycodes = new ArrayList<>();
-
- private static final String KEYCODE_STRING = "KEYCODE_";
-
- static {
- Class<KeyEvent> cls = KeyEvent.class;
- for (Field field : cls.getDeclaredFields()) {
- if (Modifier.isStatic(field.getModifiers())
- && field.getName().startsWith(KEYCODE_STRING)
- && field.getType().equals(int.class)) {
- try {
- mKeycodeStrings.add(formatString(field.getName()));
- mKeycodes.add((Integer) field.get(null));
- } catch (IllegalAccessException e) {
- }
- }
- }
- }
-
- // Force the string into something somewhat readable.
- private static String formatString(String name) {
- StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
- .toLowerCase());
- for (int i = 0; i < str.length(); i++) {
- if (i == 0 || str.charAt(i - 1) == ' ') {
- str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
- }
- }
- return str.toString();
- }
-
- public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
- new AlertDialog.Builder(context)
- .setTitle(R.string.select_keycode)
- .setItems(mKeycodeStrings.toArray(new String[0]),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- listener.onSelectionComplete(mKeycodes.get(which));
- }
- }).show();
- }
-
- public static Intent getSelectImageIntent() {
- return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
- .setType("image/*");
- }
-
- public interface OnSelectionComplete {
- void onSelectionComplete(int code);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
new file mode 100644
index 000000000000..9d579f561ea8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -0,0 +1,405 @@
+/*
+ * 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.tuner;
+
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
+import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.tuner.ShortcutParser.Shortcut;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+public class LockscreenFragment extends PreferenceFragment {
+
+ private static final String KEY_LEFT = "left";
+ private static final String KEY_RIGHT = "right";
+ private static final String KEY_CUSTOMIZE = "customize";
+ private static final String KEY_SHORTCUT = "shortcut";
+
+ public static final String LOCKSCREEN_LEFT_BUTTON = "sysui_keyguard_left";
+ public static final String LOCKSCREEN_LEFT_UNLOCK = "sysui_keyguard_left_unlock";
+ public static final String LOCKSCREEN_RIGHT_BUTTON = "sysui_keyguard_right";
+ public static final String LOCKSCREEN_RIGHT_UNLOCK = "sysui_keyguard_right_unlock";
+
+ private final ArrayList<Tunable> mTunables = new ArrayList<>();
+ private TunerService mTunerService;
+ private Handler mHandler;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ mTunerService = Dependency.get(TunerService.class);
+ mHandler = new Handler();
+ addPreferencesFromResource(R.xml.lockscreen_settings);
+ setupGroup((PreferenceGroup) findPreference(KEY_LEFT), LOCKSCREEN_LEFT_BUTTON,
+ LOCKSCREEN_LEFT_UNLOCK);
+ setupGroup((PreferenceGroup) findPreference(KEY_RIGHT), LOCKSCREEN_RIGHT_BUTTON,
+ LOCKSCREEN_RIGHT_UNLOCK);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mTunables.forEach(t -> mTunerService.removeTunable(t));
+ }
+
+ private void setupGroup(PreferenceGroup group, String buttonSetting, String unlockKey) {
+ SwitchPreference customize = (SwitchPreference) group.findPreference(KEY_CUSTOMIZE);
+ Preference shortcut = group.findPreference(KEY_SHORTCUT);
+ SwitchPreference unlock = (SwitchPreference) group.findPreference(unlockKey);
+ addTunable((k, v) -> {
+ boolean visible = v != null;
+ customize.setChecked(visible);
+ shortcut.setVisible(visible);
+ unlock.setVisible(visible);
+ if (visible) {
+ setSummary(shortcut, v);
+ }
+ }, buttonSetting);
+ customize.setOnPreferenceChangeListener((preference, newValue) -> {
+ boolean hasSetting = mTunerService.getValue(buttonSetting) != null;
+ if (hasSetting != (boolean) newValue) {
+ mHandler.post(() -> mTunerService.setValue(buttonSetting, hasSetting ? null : ""));
+ }
+ return true;
+ });
+ shortcut.setOnPreferenceClickListener(preference -> {
+ showSelectDialog(buttonSetting);
+ return true;
+ });
+ }
+
+ private void showSelectDialog(String buttonSetting) {
+ RecyclerView v = (RecyclerView) LayoutInflater.from(getContext())
+ .inflate(R.layout.tuner_shortcut_list, null);
+ v.setLayoutManager(new LinearLayoutManager(getContext()));
+ AlertDialog dialog = new Builder(getContext())
+ .setView(v)
+ .show();
+ Adapter adapter = new Adapter(getContext(), item -> {
+ mTunerService.setValue(buttonSetting, item.getSettingValue());
+ dialog.dismiss();
+ });
+ LauncherApps apps = getContext().getSystemService(LauncherApps.class);
+ List<LauncherActivityInfo> activities = apps.getActivityList(null,
+ Process.myUserHandle());
+
+ activities.forEach(info -> {
+ App app = new App(getContext(), info);
+ try {
+ new ShortcutParser(getContext(), info.getComponentName()).getShortcuts().forEach(
+ shortcut -> app.addChild(new StaticShortcut(getContext(), shortcut)));
+ } catch (NameNotFoundException e) {
+ }
+ adapter.addItem(app);
+ });
+
+ v.setAdapter(adapter);
+ }
+
+ private void setSummary(Preference shortcut, String value) {
+ if (value.contains("::")) {
+ Shortcut info = getShortcutInfo(getContext(), value);
+ shortcut.setSummary(info != null ? info.label : null);
+ } else if (value.contains("/")) {
+ ActivityInfo info = getActivityinfo(getContext(), value);
+ shortcut.setSummary(info != null ? info.loadLabel(getContext().getPackageManager())
+ : null);
+ } else {
+ shortcut.setSummary(null);
+ }
+ }
+
+ private void addTunable(Tunable t, String... keys) {
+ mTunables.add(t);
+ mTunerService.addTunable(t, keys);
+ }
+
+ public static ActivityInfo getActivityinfo(Context context, String value) {
+ ComponentName component = ComponentName.unflattenFromString(value);
+ try {
+ return context.getPackageManager().getActivityInfo(component, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ public static Shortcut getShortcutInfo(Context context, String value) {
+ return Shortcut.create(context, value);
+ }
+
+ public static class Holder extends ViewHolder {
+ public final ImageView icon;
+ public final TextView title;
+ public final ExpandableIndicator expand;
+
+ public Holder(View itemView) {
+ super(itemView);
+ icon = (ImageView) itemView.findViewById(android.R.id.icon);
+ title = (TextView) itemView.findViewById(android.R.id.title);
+ expand = (ExpandableIndicator) itemView.findViewById(R.id.expand);
+ }
+ }
+
+ private static class StaticShortcut extends Item {
+
+ private final Context mContext;
+ private final Shortcut mShortcut;
+
+
+ public StaticShortcut(Context context, Shortcut shortcut) {
+ mContext = context;
+ mShortcut = shortcut;
+ }
+
+ @Override
+ public Drawable getDrawable() {
+ return mShortcut.icon.loadDrawable(mContext);
+ }
+
+ @Override
+ public String getLabel() {
+ return mShortcut.label;
+ }
+
+ @Override
+ public String getSettingValue() {
+ return mShortcut.toString();
+ }
+
+ @Override
+ public Boolean getExpando() {
+ return null;
+ }
+ }
+
+ private static class App extends Item {
+
+ private final Context mContext;
+ private final LauncherActivityInfo mInfo;
+ private final ArrayList<Item> mChildren = new ArrayList<>();
+ private boolean mExpanded;
+
+ public App(Context context, LauncherActivityInfo info) {
+ mContext = context;
+ mInfo = info;
+ mExpanded = false;
+ }
+
+ public void addChild(Item child) {
+ mChildren.add(child);
+ }
+
+ @Override
+ public Drawable getDrawable() {
+ return mInfo.getBadgedIcon(mContext.getResources().getConfiguration().densityDpi);
+ }
+
+ @Override
+ public String getLabel() {
+ return mInfo.getLabel().toString();
+ }
+
+ @Override
+ public String getSettingValue() {
+ return mInfo.getComponentName().flattenToString();
+ }
+
+ @Override
+ public Boolean getExpando() {
+ return mChildren.size() != 0 ? mExpanded : null;
+ }
+
+ @Override
+ public void toggleExpando(Adapter adapter) {
+ mExpanded = !mExpanded;
+ if (mExpanded) {
+ mChildren.forEach(child -> adapter.addItem(this, child));
+ } else {
+ mChildren.forEach(child -> adapter.remItem(child));
+ }
+ }
+ }
+
+ private abstract static class Item {
+ public abstract Drawable getDrawable();
+
+ public abstract String getLabel();
+
+ public abstract String getSettingValue();
+
+ public abstract Boolean getExpando();
+
+ public void toggleExpando(Adapter adapter) {
+ }
+ }
+
+ public static class Adapter extends RecyclerView.Adapter<Holder> {
+ private ArrayList<Item> mItems = new ArrayList<>();
+ private final Context mContext;
+ private final Consumer<Item> mCallback;
+
+ public Adapter(Context context, Consumer<Item> callback) {
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new Holder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.tuner_shortcut_item, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(Holder holder, int position) {
+ Item item = mItems.get(position);
+ holder.icon.setImageDrawable(item.getDrawable());
+ holder.title.setText(item.getLabel());
+ holder.itemView.setOnClickListener(
+ v -> mCallback.accept(mItems.get(holder.getAdapterPosition())));
+ Boolean expando = item.getExpando();
+ if (expando != null) {
+ holder.expand.setVisibility(View.VISIBLE);
+ holder.expand.setExpanded(expando);
+ holder.expand.setOnClickListener(
+ v -> mItems.get(holder.getAdapterPosition()).toggleExpando(Adapter.this));
+ } else {
+ holder.expand.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItems.size();
+ }
+
+ public void addItem(Item item) {
+ mItems.add(item);
+ notifyDataSetChanged();
+ }
+
+ public void remItem(Item item) {
+ int index = mItems.indexOf(item);
+ mItems.remove(item);
+ notifyItemRemoved(index);
+ }
+
+ public void addItem(Item parent, Item child) {
+ int index = mItems.indexOf(parent);
+ mItems.add(index + 1, child);
+ notifyItemInserted(index + 1);
+ }
+ }
+
+ public static IntentButton getIntentButton(Context context, String buttonStr,
+ IntentButton plugin, IntentButton def) {
+ // Plugin wins.
+ if (plugin != null) return plugin;
+ // Then tuner options.
+ if (!TextUtils.isEmpty(buttonStr)) {
+ if (buttonStr.contains("::")) {
+ Shortcut shortcut = getShortcutInfo(context, buttonStr);
+ if (shortcut != null) {
+ return new ShortcutButton(context, shortcut);
+ }
+ } else if (buttonStr.contains("/")) {
+ ActivityInfo info = getActivityinfo(context, buttonStr);
+ if (info != null) {
+ return new ActivityButton(context, info);
+ }
+ }
+ }
+ // Then default.
+ return def;
+ }
+
+ private static class ShortcutButton implements IntentButton {
+ private final Shortcut mShortcut;
+ private final IconState mIconState;
+
+ public ShortcutButton(Context context, Shortcut shortcut) {
+ mShortcut = shortcut;
+ mIconState = new IconState();
+ mIconState.isVisible = true;
+ mIconState.drawable = shortcut.icon.loadDrawable(context);
+ mIconState.contentDescription = mShortcut.label;
+ }
+
+ @Override
+ public IconState getIcon() {
+ return mIconState;
+ }
+
+ @Override
+ public Intent getIntent() {
+ return mShortcut.intent;
+ }
+ }
+
+ private static class ActivityButton implements IntentButton {
+ private final Intent mIntent;
+ private final IconState mIconState;
+
+ public ActivityButton(Context context, ActivityInfo info) {
+ mIntent = new Intent().setComponent(new ComponentName(info.packageName, info.name));
+ mIconState = new IconState();
+ mIconState.isVisible = true;
+ mIconState.drawable = info.loadIcon(context.getPackageManager());
+ mIconState.contentDescription = info.loadLabel(context.getPackageManager());
+ }
+
+ @Override
+ public IconState getIcon() {
+ return mIconState;
+ }
+
+ @Override
+ public Intent getIntent() {
+ return mIntent;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index ad424590f663..28a00570a019 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
@@ -14,590 +14,228 @@
package com.android.systemui.tuner;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Fragment;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.CLIPBOARD;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_LEFT;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_RIGHT;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.RECENT;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractImage;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractKeycode;
-public class NavBarTuner extends Fragment implements TunerService.Tunable {
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
+import android.support.v7.preference.PreferenceCategory;
+import android.text.SpannableStringBuilder;
+import android.text.style.ImageSpan;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+import android.widget.EditText;
- private static final int SAVE = Menu.FIRST + 1;
- private static final int RESET = Menu.FIRST + 2;
- private static final int READ_REQUEST = 42;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
+import com.android.systemui.tuner.TunerService.Tunable;
- private static final float PREVIEW_SCALE = .95f;
- private static final float PREVIEW_SCALE_LANDSCAPE = .75f;
+import java.util.ArrayList;
- private NavBarAdapter mNavBarAdapter;
- private PreviewNavInflater mPreview;
+public class NavBarTuner extends PreferenceFragment {
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
- Bundle savedInstanceState) {
- final View view = inflater.inflate(R.layout.nav_bar_tuner, container, false);
- inflatePreview((ViewGroup) view.findViewById(R.id.nav_preview_frame));
- return view;
- }
+ private static final String LAYOUT = "layout";
+ private static final String LEFT = "left";
+ private static final String RIGHT = "right";
- private void inflatePreview(ViewGroup view) {
- Display display = getActivity().getWindowManager().getDefaultDisplay();
- boolean isRotated = display.getRotation() == Surface.ROTATION_90
- || display.getRotation() == Surface.ROTATION_270;
+ private static final String TYPE = "type";
+ private static final String KEYCODE = "keycode";
+ private static final String ICON = "icon";
- Configuration config = new Configuration(getContext().getResources().getConfiguration());
- boolean isPhoneLandscape = isRotated && (config.smallestScreenWidthDp < 600);
- final float scale = isPhoneLandscape ? PREVIEW_SCALE_LANDSCAPE : PREVIEW_SCALE;
- config.densityDpi = (int) (config.densityDpi * scale);
+ private static final int[] ICONS = new int[]{
+ R.drawable.ic_qs_circle,
+ R.drawable.ic_add,
+ R.drawable.ic_remove,
+ R.drawable.ic_left,
+ R.drawable.ic_right,
+ R.drawable.ic_menu,
+ };
- mPreview = (PreviewNavInflater) LayoutInflater.from(getContext().createConfigurationContext(
- config)).inflate(R.layout.nav_bar_tuner_inflater, view, false);
- final ViewGroup.LayoutParams layoutParams = mPreview.getLayoutParams();
- layoutParams.width = (int) ((isPhoneLandscape ? display.getHeight() : display.getWidth())
- * scale);
- // Not sure why, but the height dimen is not being scaled with the dp, set it manually
- // for now.
- layoutParams.height = (int) (layoutParams.height * scale);
- if (isPhoneLandscape) {
- int width = layoutParams.width;
- layoutParams.width = layoutParams.height;
- layoutParams.height = width;
- }
- view.addView(mPreview);
+ private final ArrayList<Tunable> mTunables = new ArrayList<>();
+ private Handler mHandler;
- if (isRotated) {
- mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
- final View rot90 = mPreview.findViewById(R.id.rot90);
- } else {
- mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
- final View rot0 = mPreview.findViewById(R.id.rot0);
- }
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ mHandler = new Handler();
+ super.onCreate(savedInstanceState);
}
- private void notifyChanged() {
- mPreview.onTuningChanged(NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- RecyclerView recyclerView = (RecyclerView) view.findViewById(android.R.id.list);
- final Context context = getContext();
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- mNavBarAdapter = new NavBarAdapter(context);
- recyclerView.setAdapter(mNavBarAdapter);
- recyclerView.addItemDecoration(new Dividers(context));
- final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mNavBarAdapter.mCallbacks);
- mNavBarAdapter.setTouchHelper(itemTouchHelper);
- itemTouchHelper.attachToRecyclerView(recyclerView);
-
- TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.nav_bar_tuner);
+ bindLayout((ListPreference) findPreference(LAYOUT));
+ bindButton((PreferenceCategory) findPreference(LEFT),
+ NAV_BAR_LEFT, NAVSPACE);
+ bindButton((PreferenceCategory) findPreference(RIGHT),
+ NAV_BAR_RIGHT, MENU_IME);
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
- TunerService.get(getContext()).removeTunable(this);
+ public void onDestroy() {
+ super.onDestroy();
+ mTunables.forEach(t -> Dependency.get(TunerService.class).removeTunable(t));
}
- @Override
- public void onTuningChanged(String key, String navLayout) {
- if (!NAV_BAR_VIEWS.equals(key)) return;
- Context context = getContext();
- if (navLayout == null) {
- navLayout = context.getString(R.string.config_navBarLayout);
- }
- String[] views = navLayout.split(GRAVITY_SEPARATOR);
- String[] groups = new String[] { NavBarAdapter.START, NavBarAdapter.CENTER,
- NavBarAdapter.END};
- CharSequence[] groupLabels = new String[] { getString(R.string.start),
- getString(R.string.center), getString(R.string.end) };
- mNavBarAdapter.clear();
- for (int i = 0; i < 3; i++) {
- mNavBarAdapter.addButton(groups[i], groupLabels[i]);
- for (String button : views[i].split(BUTTON_SEPARATOR)) {
- mNavBarAdapter.addButton(button, getLabel(button, context));
- }
- }
- mNavBarAdapter.addButton(NavBarAdapter.ADD, getString(R.string.add_button));
- setHasOptionsMenu(true);
+ private void addTunable(Tunable tunable, String... keys) {
+ mTunables.add(tunable);
+ Dependency.get(TunerService.class).addTunable(tunable, keys);
}
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- // TODO: Show save button conditionally, only when there are changes.
- menu.add(Menu.NONE, SAVE, Menu.NONE, getString(R.string.save))
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- menu.add(Menu.NONE, RESET, Menu.NONE, getString(R.string.reset));
+ private void bindLayout(ListPreference preference) {
+ addTunable((key, newValue) -> mHandler.post(() -> {
+ String val = newValue;
+ if (val == null) {
+ val = "default";
+ }
+ preference.setValue(val);
+ }), NAV_BAR_VIEWS);
+ preference.setOnPreferenceChangeListener((preference1, newValue) -> {
+ String val = (String) newValue;
+ if ("default".equals(val)) val = null;
+ Dependency.get(TunerService.class).setValue(NAV_BAR_VIEWS, val);
+ return true;
+ });
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == SAVE) {
- if (!mNavBarAdapter.hasHomeButton()) {
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.no_home_title)
- .setMessage(R.string.no_home_message)
- .setPositiveButton(android.R.string.ok, null)
- .show();
+ private void bindButton(PreferenceCategory parent, String setting, String def) {
+ String k = parent.getKey();
+ DropDownPreference type = (DropDownPreference) findPreference(TYPE + "_" + k);
+ Preference keycode = findPreference(KEYCODE + "_" + k);
+ ListPreference icon = (ListPreference) findPreference(ICON + "_" + k);
+ setupIcons(icon);
+ addTunable((key, newValue) -> mHandler.post(() -> {
+ String val = newValue;
+ if (val == null) {
+ val = def;
+ }
+ String button = extractButton(val);
+ if (button.startsWith(KEY)) {
+ type.setValue(KEY);
+ String uri = extractImage(button);
+ int code = extractKeycode(button);
+ icon.setValue(uri);
+ updateSummary(icon);
+ keycode.setSummary(code + "");
+ keycode.setVisible(true);
+ icon.setVisible(true);
} else {
- Settings.Secure.putString(getContext().getContentResolver(),
- NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
- }
+ type.setValue(button);
+ keycode.setVisible(false);
+ icon.setVisible(false);
+ }
+ }), setting);
+ OnPreferenceChangeListener listener = (preference, newValue) -> {
+ mHandler.post(() -> {
+ setValue(setting, type, keycode, icon);
+ updateSummary(icon);
+ });
return true;
- } else if (item.getItemId() == RESET) {
- Settings.Secure.putString(getContext().getContentResolver(),
- NAV_BAR_VIEWS, null);
+ };
+ type.setOnPreferenceChangeListener(listener);
+ icon.setOnPreferenceChangeListener(listener);
+ keycode.setOnPreferenceClickListener(preference -> {
+ EditText editText = new EditText(getContext());
+ new AlertDialog.Builder(getContext())
+ .setTitle(preference.getTitle())
+ .setView(editText)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ int code = KeyEvent.KEYCODE_ENTER;
+ try {
+ code = Integer.parseInt(editText.getText().toString());
+ } catch (Exception e) {
+ }
+ keycode.setSummary(code + "");
+ setValue(setting, type, keycode, icon);
+ }).show();
return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private static CharSequence getLabel(String button, Context context) {
- if (button.startsWith(HOME)) {
- return context.getString(R.string.accessibility_home);
- } else if (button.startsWith(BACK)) {
- return context.getString(R.string.accessibility_back);
- } else if (button.startsWith(RECENT)) {
- return context.getString(R.string.accessibility_recent);
- } else if (button.startsWith(NAVSPACE)) {
- return context.getString(R.string.space);
- } else if (button.startsWith(MENU_IME)) {
- return context.getString(R.string.menu_ime);
- } else if (button.startsWith(CLIPBOARD)) {
- return context.getString(R.string.clipboard);
- } else if (button.startsWith(KEY)) {
- return context.getString(R.string.keycode);
- }
- return button;
+ });
}
- private static class Holder extends RecyclerView.ViewHolder {
- private TextView title;
-
- public Holder(View itemView) {
- super(itemView);
- title = (TextView) itemView.findViewById(android.R.id.title);
+ private void updateSummary(ListPreference icon) {
+ try {
+ int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14,
+ getContext().getResources().getDisplayMetrics());
+ String pkg = icon.getValue().split("/")[0];
+ int id = Integer.parseInt(icon.getValue().split("/")[1]);
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ Drawable d = Icon.createWithResource(pkg, id)
+ .loadDrawable(getContext());
+ d.setTint(Color.BLACK);
+ d.setBounds(0, 0, size, size);
+ ImageSpan span = new ImageSpan(d);
+ builder.append(" ", span, 0);
+ icon.setSummary(builder);
+ } catch (Exception e) {
+ Log.d("NavButton", "Problem with summary", e);
+ icon.setSummary(null);
}
}
- private static class Dividers extends RecyclerView.ItemDecoration {
- private final Drawable mDivider;
-
- public Dividers(Context context) {
- TypedValue value = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.listDivider, value, true);
- mDivider = context.getDrawable(value.resourceId);
- }
-
- @Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
- super.onDraw(c, parent, state);
- final int left = parent.getPaddingLeft();
- final int right = parent.getWidth() - parent.getPaddingRight();
-
- final int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = parent.getChildAt(i);
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
- .getLayoutParams();
- final int top = child.getBottom() + params.bottomMargin;
- final int bottom = top + mDivider.getIntrinsicHeight();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
+ private void setValue(String setting, DropDownPreference type, Preference keycode,
+ ListPreference icon) {
+ String button = type.getValue();
+ if (KEY.equals(button)) {
+ String uri = icon.getValue();
+ int code = KeyEvent.KEYCODE_ENTER;
+ try {
+ code = Integer.parseInt(keycode.getSummary().toString());
+ } catch (Exception e) {
}
+ button = button + KEY_CODE_START + code + KEY_IMAGE_DELIM + uri + KEY_CODE_END;
}
+ Dependency.get(TunerService.class).setValue(setting, button);
}
- private void selectImage() {
- startActivityForResult(KeycodeSelectionHelper.getSelectImageIntent(), READ_REQUEST);
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == READ_REQUEST && resultCode == Activity.RESULT_OK && data != null) {
- final Uri uri = data.getData();
- final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
- getContext().getContentResolver().takePersistableUriPermission(uri, takeFlags);
- mNavBarAdapter.onImageSelected(uri);
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- private class NavBarAdapter extends RecyclerView.Adapter<Holder>
- implements View.OnClickListener {
-
- private static final String START = "start";
- private static final String CENTER = "center";
- private static final String END = "end";
- private static final String ADD = "add";
-
- private static final int ADD_ID = 0;
- private static final int BUTTON_ID = 1;
- private static final int CATEGORY_ID = 2;
-
- private List<String> mButtons = new ArrayList<>();
- private List<CharSequence> mLabels = new ArrayList<>();
- private int mCategoryLayout;
- private int mButtonLayout;
- private ItemTouchHelper mTouchHelper;
-
- // Stored keycode while we wait for image selection on a KEY.
- private int mKeycode;
-
- public NavBarAdapter(Context context) {
- TypedArray attrs = context.getTheme().obtainStyledAttributes(null,
- android.R.styleable.Preference, android.R.attr.preferenceStyle, 0);
- mButtonLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
- attrs = context.getTheme().obtainStyledAttributes(null,
- android.R.styleable.Preference, android.R.attr.preferenceCategoryStyle, 0);
- mCategoryLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
- }
-
- public void setTouchHelper(ItemTouchHelper itemTouchHelper) {
- mTouchHelper = itemTouchHelper;
- }
-
- public void clear() {
- mButtons.clear();
- mLabels.clear();
- notifyDataSetChanged();
- }
-
- public void addButton(String button, CharSequence label) {
- mButtons.add(button);
- mLabels.add(label);
- notifyItemInserted(mLabels.size() - 1);
- notifyChanged();
- }
-
- public boolean hasHomeButton() {
- final int N = mButtons.size();
- for (int i = 0; i < N; i++) {
- if (mButtons.get(i).startsWith(HOME)) {
- return true;
- }
- }
- return false;
- }
-
- public String getNavString() {
- StringBuilder builder = new StringBuilder();
- for (int i = 1; i < mButtons.size() - 1; i++) {
- String button = mButtons.get(i);
- if (button.equals(CENTER) || button.equals(END)) {
- if (builder.length() == 0 || builder.toString().endsWith(GRAVITY_SEPARATOR)) {
- // No start or center buttons, fill with a space.
- builder.append(NAVSPACE);
- }
- builder.append(GRAVITY_SEPARATOR);
- continue;
- } else if (builder.length() != 0 && !builder.toString().endsWith(
- GRAVITY_SEPARATOR)) {
- builder.append(BUTTON_SEPARATOR);
- }
- builder.append(button);
- }
- if (builder.toString().endsWith(GRAVITY_SEPARATOR)) {
- // No end buttons, fill with space.
- builder.append(NAVSPACE);
- }
- return builder.toString();
- }
-
- @Override
- public int getItemViewType(int position) {
- String button = mButtons.get(position);
- if (button.equals(START) || button.equals(CENTER) || button.equals(END)) {
- return CATEGORY_ID;
- }
- if (button.equals(ADD)) {
- return ADD_ID;
- }
- return BUTTON_ID;
- }
-
- @Override
- public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
- final Context context = parent.getContext();
- final LayoutInflater inflater = LayoutInflater.from(context);
- final View view = inflater.inflate(getLayoutId(viewType), parent, false);
- if (viewType == BUTTON_ID) {
- inflater.inflate(R.layout.nav_control_widget,
- (ViewGroup) view.findViewById(android.R.id.widget_frame));
- }
- return new Holder(view);
- }
-
- private int getLayoutId(int viewType) {
- if (viewType == CATEGORY_ID) {
- return mCategoryLayout;
- }
- return mButtonLayout;
- }
-
- @Override
- public void onBindViewHolder(Holder holder, int position) {
- holder.title.setText(mLabels.get(position));
- if (holder.getItemViewType() == BUTTON_ID) {
- bindButton(holder, position);
- } else if (holder.getItemViewType() == ADD_ID) {
- bindAdd(holder);
- }
- }
-
- private void bindAdd(Holder holder) {
- TypedValue value = new TypedValue();
- final Context context = holder.itemView.getContext();
- context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
- final ImageView icon = (ImageView) holder.itemView.findViewById(android.R.id.icon);
- icon.setImageResource(R.drawable.ic_add);
- icon.setImageTintList(ColorStateList.valueOf(context.getColor(value.resourceId)));
- holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
- holder.itemView.setClickable(true);
- holder.itemView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showAddDialog(v.getContext());
- }
- });
- }
-
- private void bindButton(final Holder holder, int position) {
- holder.itemView.findViewById(android.R.id.icon_frame).setVisibility(View.GONE);
- holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
- bindClick(holder.itemView.findViewById(R.id.close), holder);
- bindClick(holder.itemView.findViewById(R.id.width), holder);
- holder.itemView.findViewById(R.id.drag).setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mTouchHelper.startDrag(holder);
- return true;
- }
- });
- }
-
- private void showAddDialog(final Context context) {
- final String[] options = new String[] {
- BACK, HOME, RECENT, MENU_IME, NAVSPACE, CLIPBOARD, KEY,
- };
- final CharSequence[] labels = new CharSequence[options.length];
- for (int i = 0; i < options.length; i++) {
- labels[i] = getLabel(options[i], context);
- }
- new AlertDialog.Builder(context)
- .setTitle(R.string.select_button)
- .setItems(labels, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (KEY.equals(options[which])) {
- showKeyDialogs(context);
- } else {
- int index = mButtons.size() - 1;
- showAddedMessage(context, options[which]);
- mButtons.add(index, options[which]);
- mLabels.add(index, labels[which]);
-
- notifyItemInserted(index);
- notifyChanged();
- }
- }
- }).setNegativeButton(android.R.string.cancel, null)
- .show();
- }
-
- private void onImageSelected(Uri uri) {
- int index = mButtons.size() - 1;
- mButtons.add(index, KEY + KEY_CODE_START + mKeycode + KEY_IMAGE_DELIM + uri.toString()
- + KEY_CODE_END);
- mLabels.add(index, getLabel(KEY, getContext()));
-
- notifyItemInserted(index);
- notifyChanged();
- }
-
- private void showKeyDialogs(final Context context) {
- final KeycodeSelectionHelper.OnSelectionComplete listener =
- new KeycodeSelectionHelper.OnSelectionComplete() {
- @Override
- public void onSelectionComplete(int code) {
- mKeycode = code;
- selectImage();
- }
- };
- new AlertDialog.Builder(context)
- .setTitle(R.string.keycode)
- .setMessage(R.string.keycode_description)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- KeycodeSelectionHelper.showKeycodeSelect(context, listener);
- }
- }).show();
- }
-
- private void showAddedMessage(Context context, String button) {
- if (CLIPBOARD.equals(button)) {
- new AlertDialog.Builder(context)
- .setTitle(R.string.clipboard)
- .setMessage(R.string.clipboard_description)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- }
- }
-
- private void bindClick(View view, Holder holder) {
- view.setOnClickListener(this);
- view.setTag(holder);
- }
-
- @Override
- public void onClick(View v) {
- Holder holder = (Holder) v.getTag();
- if (v.getId() == R.id.width) {
- showWidthDialog(holder, v.getContext());
- } else if (v.getId() == R.id.close) {
- int position = holder.getAdapterPosition();
- mButtons.remove(position);
- mLabels.remove(position);
- notifyItemRemoved(position);
- notifyChanged();
- }
- }
-
- private void showWidthDialog(final Holder holder, Context context) {
- final String buttonSpec = mButtons.get(holder.getAdapterPosition());
- float amount = extractSize(buttonSpec);
- final AlertDialog dialog = new AlertDialog.Builder(context)
- .setTitle(R.string.adjust_button_width)
- .setView(R.layout.nav_width_view)
- .setNegativeButton(android.R.string.cancel, null).create();
- dialog.setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface d, int which) {
- final String button = extractButton(buttonSpec);
- SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
- if (seekBar.getProgress() == 75) {
- mButtons.set(holder.getAdapterPosition(), button);
- } else {
- float amount = (seekBar.getProgress() + 25) / 100f;
- mButtons.set(holder.getAdapterPosition(), button
- + SIZE_MOD_START + amount + SIZE_MOD_END);
- }
- notifyChanged();
- }
- });
- dialog.show();
- SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
- // Range is .25 - 1.75.
- seekBar.setMax(150);
- seekBar.setProgress((int) ((amount - .25f) * 100));
- }
-
- @Override
- public int getItemCount() {
- return mButtons.size();
- }
-
- private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
- @Override
- public boolean isLongPressDragEnabled() {
- return false;
- }
-
- @Override
- public boolean isItemViewSwipeEnabled() {
- return false;
- }
-
- @Override
- public int getMovementFlags(RecyclerView recyclerView,
- RecyclerView.ViewHolder viewHolder) {
- if (viewHolder.getItemViewType() != BUTTON_ID) {
- return makeMovementFlags(0, 0);
- }
- int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
- return makeMovementFlags(dragFlags, 0);
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
- RecyclerView.ViewHolder target) {
- int from = viewHolder.getAdapterPosition();
- int to = target.getAdapterPosition();
- if (to == 0) {
- // Can't go above the top.
- return false;
- }
- move(from, to, mButtons);
- move(from, to, mLabels);
- notifyChanged();
- notifyItemMoved(from, to);
- return true;
- }
-
- private <T> void move(int from, int to, List<T> list) {
- list.add(from > to ? to : to + 1, list.get(from));
- list.remove(from > to ? from + 1 : from);
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- // Don't care.
- }
- };
+ private void setupIcons(ListPreference icon) {
+ CharSequence[] labels = new CharSequence[ICONS.length];
+ CharSequence[] values = new CharSequence[ICONS.length];
+ int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14,
+ getContext().getResources().getDisplayMetrics());
+ for (int i = 0; i < ICONS.length; i++) {
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ Drawable d = Icon.createWithResource(getContext().getPackageName(), ICONS[i])
+ .loadDrawable(getContext());
+ d.setTint(Color.BLACK);
+ d.setBounds(0, 0, size, size);
+ ImageSpan span = new ImageSpan(d);
+ builder.append(" ", span, 0);
+ labels[i] = builder;
+ values[i] = getContext().getPackageName() + "/" + ICONS[i];
+ }
+ icon.setEntries(labels);
+ icon.setEntryValues(values);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
index e6e8f4e0a100..e7a695fc3efd 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
@@ -18,6 +18,7 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
public class PreviewNavInflater extends NavigationBarInflaterView {
@@ -31,7 +32,7 @@ public class PreviewNavInflater extends NavigationBarInflaterView {
super.onAttachedToWindow();
// Immediately remove tuner listening, since this is a preview, all values will be injected
// manually.
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ShortcutParser.java b/packages/SystemUI/src/com/android/systemui/tuner/ShortcutParser.java
new file mode 100644
index 000000000000..2aa51b3f787c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ShortcutParser.java
@@ -0,0 +1,162 @@
+/*
+ * 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.tuner;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ShortcutParser {
+ private static final String SHORTCUTS = "android.app.shortcuts";
+ private static final String SHORTCUT = "shortcut";
+ private static final String INTENT = "intent";
+
+ private final Context mContext;
+ private final String mPkg;
+ private final int mResId;
+ private final String mName;
+ private Resources mResources;
+ private AttributeSet mAttrs;
+
+ public ShortcutParser(Context context, ComponentName component) throws NameNotFoundException {
+ this(context, component.getPackageName(), component.getClassName(),
+ getResId(context, component));
+ }
+
+ private static int getResId(Context context, ComponentName component)
+ throws NameNotFoundException {
+ ActivityInfo i = context.getPackageManager().getActivityInfo(
+ component, PackageManager.GET_META_DATA);
+ int resId = 0;
+ if (i.metaData != null && i.metaData.containsKey(SHORTCUTS)) {
+ resId = i.metaData.getInt(SHORTCUTS);
+ }
+ return resId;
+ }
+
+ public ShortcutParser(Context context, String pkg, String name, int resId) {
+ mContext = context;
+ mPkg = pkg;
+ mResId = resId;
+ mName = name;
+ }
+
+ public List<Shortcut> getShortcuts() {
+ List<Shortcut> list = new ArrayList<>();
+ if (mResId != 0) {
+ try {
+ mResources = mContext.getPackageManager().getResourcesForApplication(mPkg);
+ XmlResourceParser parser = mResources.getXml(mResId);
+ mAttrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (parser.getName().equals(SHORTCUT)) {
+ Shortcut c = parseShortcut(parser);
+ if (c != null) {
+ list.add(c);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ return list;
+ }
+
+ private Shortcut parseShortcut(XmlResourceParser parser)
+ throws IOException, XmlPullParserException {
+ final TypedArray sa = mResources.obtainAttributes(mAttrs, R.styleable.Shortcut);
+ Shortcut c = new Shortcut();
+
+ final boolean enabled = sa.getBoolean(R.styleable.Shortcut_enabled, true);
+ if (!enabled) return null;
+ final String id = sa.getString(R.styleable.Shortcut_shortcutId);
+ final int iconResId = sa.getResourceId(R.styleable.Shortcut_icon, 0);
+ final int titleResId = sa.getResourceId(R.styleable.Shortcut_shortcutShortLabel, 0);
+
+ c.pkg = mPkg;
+ c.icon = Icon.createWithResource(mPkg, iconResId);
+ c.id = id;
+ c.label = mResources.getString(titleResId);
+ c.name = mName;
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_TAG) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (parser.getName().equals(INTENT)) {
+ c.intent = Intent.parseIntent(mResources, parser, mAttrs);
+ }
+ }
+ return c.intent != null ? c : null;
+ }
+
+ public static class Shortcut {
+ public Intent intent;
+ public String label;
+ public Icon icon;
+ public String pkg;
+ public String id;
+ public String name;
+
+ public static Shortcut create(Context context, String value) {
+ String[] sp = value.split("::");
+ try {
+ for (Shortcut shortcut : new ShortcutParser(context,
+ new ComponentName(sp[0], sp[1])).getShortcuts()) {
+ if (shortcut.id.equals(sp[2])) {
+ return shortcut;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(pkg);
+ builder.append("::");
+ builder.append(name);
+ builder.append("::");
+ builder.append(id);
+ return builder.toString();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index dea2f5060c3a..8a2407ac1d08 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -25,6 +25,7 @@ import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -41,12 +42,12 @@ public class StatusBarSwitch extends SwitchPreference implements Tunable {
@Override
public void onAttached() {
super.onAttached();
- TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
}
@Override
public void onDetached() {
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
super.onDetached();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
deleted file mode 100644
index a068172a2dd3..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.tuner;
-
-import android.app.AlertDialog;
-import android.app.UiModeManager;
-import android.content.Context;
-import android.os.SystemProperties;
-import android.support.v7.preference.ListPreference;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-
-import com.android.systemui.R;
-
-import libcore.util.Objects;
-
-import com.google.android.collect.Lists;
-
-import java.io.File;
-import java.util.ArrayList;
-
-public class ThemePreference extends ListPreference {
-
- public ThemePreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public void onAttached() {
- super.onAttached();
- String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
- if (TextUtils.isEmpty(def)) {
- def = getContext().getString(R.string.default_theme);
- }
- String[] fileList = new File("/vendor/overlay").list();
- ArrayList<String> options = fileList != null
- ? Lists.newArrayList(fileList) : new ArrayList<>();
- if (!options.contains(def)) {
- options.add(0, def);
- }
- String[] list = options.toArray(new String[options.size()]);
- setVisible(options.size() > 1);
- setEntries(list);
- setEntryValues(list);
- updateValue();
- }
-
- private void updateValue() {
- setValue(getContext().getSystemService(UiModeManager.class).getTheme());
- }
-
- @Override
- protected void notifyChanged() {
- super.notifyChanged();
- if (!Objects.equal(getValue(),
- getContext().getSystemService(UiModeManager.class).getTheme())) {
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.change_theme_reboot)
- .setPositiveButton(com.android.internal.R.string.global_action_restart, (d, i)
- -> getContext().getSystemService(UiModeManager.class)
- .setTheme(getValue()))
- .setNegativeButton(android.R.string.cancel, (d, i) -> updateValue())
- .show();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 3b14e6069360..74280a315e67 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -24,6 +24,7 @@ import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
import com.android.settingslib.drawer.SettingsDrawerActivity;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
public class TunerActivity extends SettingsDrawerActivity implements
@@ -36,6 +37,7 @@ public class TunerActivity extends SettingsDrawerActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Dependency.initDependencies(this);
if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
final String action = getIntent().getAction();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 565ac08f92ee..7acd888483ab 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -33,12 +33,14 @@ import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.systemui.BatteryMeterDrawable;
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.DemoMode;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
@@ -50,7 +52,7 @@ import java.util.HashMap;
import java.util.Set;
-public class TunerService extends SystemUI {
+public class TunerService {
public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER";
@@ -63,13 +65,14 @@ public class TunerService extends SystemUI {
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
+ private final Context mContext;
private ContentResolver mContentResolver;
private int mCurrentUser;
private CurrentUserTracker mUserTracker;
- @Override
- public void start() {
+ public TunerService(Context context) {
+ mContext = context;
mContentResolver = mContext.getContentResolver();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
@@ -78,7 +81,6 @@ public class TunerService extends SystemUI {
upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION);
}
}
- putComponent(TunerService.class, this);
mCurrentUser = ActivityManager.getCurrentUser();
mUserTracker = new CurrentUserTracker(mContext) {
@@ -126,6 +128,12 @@ public class TunerService extends SystemUI {
return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
}
+ public String getValue(String setting, String def) {
+ String ret = Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
+ if (ret == null) return def;
+ return ret;
+ }
+
public void setValue(String setting, int value) {
Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
}
@@ -192,7 +200,8 @@ public class TunerService extends SystemUI {
public void clearAll() {
// A couple special cases.
Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
- Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
+ Settings.System.putString(mContentResolver,
+ BatteryMeterDrawableBase.SHOW_PERCENT_SETTING, null);
Intent intent = new Intent(DemoMode.ACTION_DEMO);
intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
mContext.sendBroadcast(intent);
@@ -202,32 +211,6 @@ public class TunerService extends SystemUI {
}
}
- // Only used in other processes, such as the tuner.
- private static TunerService sInstance;
-
- public static TunerService get(Context context) {
- TunerService service = null;
- if (context.getApplicationContext() instanceof SystemUIApplication) {
- SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
- service = sysUi.getComponent(TunerService.class);
- }
- if (service == null) {
- // Can't get it as a component, must in the tuner, lets just create one for now.
- return getStaticService(context);
- }
- return service;
- }
-
- private static TunerService getStaticService(Context context) {
- if (sInstance == null) {
- sInstance = new TunerService();
- sInstance.mContext = context.getApplicationContext();
- sInstance.mComponents = new HashMap<>();
- sInstance.start();
- }
- return sInstance;
- }
-
public static final void showResetRequest(final Context context, final Runnable onDisabled) {
SystemUIDialog dialog = new SystemUIDialog(context);
dialog.setShowForAllUsers(true);
@@ -303,7 +286,7 @@ public class TunerService extends SystemUI {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CLEAR.equals(intent.getAction())) {
- get(context).clearAll();
+ Dependency.get(TunerService.class).clearAll();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 5b9ebd7722c6..d5b6ccdeb320 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -7,6 +7,7 @@ import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -26,12 +27,12 @@ public class TunerSwitch extends SwitchPreference implements Tunable {
@Override
public void onAttached() {
super.onAttached();
- TunerService.get(getContext()).addTunable(this, getKey().split(","));
+ Dependency.get(TunerService.class).addTunable(this, getKey().split(","));
}
@Override
public void onDetached() {
- TunerService.get(getContext()).removeTunable(this);
+ Dependency.get(TunerService.class).removeTunable(this);
super.onDetached();
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 2c90e62d3a1b..43727e07c712 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -43,6 +43,7 @@ import android.util.SparseArray;
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SystemUI;
+import com.android.systemui.util.NotificationChannels;
import java.util.List;
@@ -197,17 +198,19 @@ public class StorageNotification extends SystemUI {
rec.getNickname());
final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_sd_card_48dp)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(buildForgetPendingIntent(rec))
- .setStyle(new Notification.BigTextStyle().bigText(text))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setLocalOnly(true)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setDeleteIntent(buildSnoozeIntent(fsUuid));
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.STORAGE)
+ .setSmallIcon(R.drawable.ic_sd_card_48dp)
+ .setColor(mContext.getColor(
+ R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(buildForgetPendingIntent(rec))
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setDeleteIntent(buildSnoozeIntent(fsUuid));
SystemUI.overrideNotificationAppName(mContext, builder);
mNotificationManager.notifyAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
@@ -224,16 +227,17 @@ public class StorageNotification extends SystemUI {
final CharSequence text = mContext.getString(
R.string.ext_media_unsupported_notification_message, disk.getDescription());
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(buildInitPendingIntent(disk))
- .setStyle(new Notification.BigTextStyle().bigText(text))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setLocalOnly(true)
- .setCategory(Notification.CATEGORY_ERROR);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.STORAGE)
+ .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(buildInitPendingIntent(disk))
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_ERROR);
SystemUI.overrideNotificationAppName(mContext, builder);
mNotificationManager.notifyAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
@@ -331,7 +335,6 @@ public class StorageNotification extends SystemUI {
return buildNotificationBuilder(vol, title, text)
.setCategory(Notification.CATEGORY_PROGRESS)
- .setPriority(Notification.PRIORITY_LOW)
.setOngoing(true)
.build();
}
@@ -360,7 +363,6 @@ public class StorageNotification extends SystemUI {
buildUnmountPendingIntent(vol)))
.setContentIntent(initIntent)
.setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()))
- .setCategory(Notification.CATEGORY_SYSTEM)
.build();
} else {
@@ -377,8 +379,7 @@ public class StorageNotification extends SystemUI {
mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
.setContentIntent(browseIntent)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW);
+ .setCategory(Notification.CATEGORY_SYSTEM);
// Non-adoptable disks can't be snoozed.
if (disk.isAdoptable()) {
builder.setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()));
@@ -402,7 +403,6 @@ public class StorageNotification extends SystemUI {
return buildNotificationBuilder(vol, title, text)
.setCategory(Notification.CATEGORY_PROGRESS)
- .setPriority(Notification.PRIORITY_LOW)
.setOngoing(true)
.build();
}
@@ -476,19 +476,19 @@ public class StorageNotification extends SystemUI {
intent = buildWizardMigratePendingIntent(move);
}
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_sd_card_48dp)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(intent)
- .setStyle(new Notification.BigTextStyle().bigText(text))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setLocalOnly(true)
- .setCategory(Notification.CATEGORY_PROGRESS)
- .setPriority(Notification.PRIORITY_LOW)
- .setProgress(100, status, false)
- .setOngoing(true);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.STORAGE)
+ .setSmallIcon(R.drawable.ic_sd_card_48dp)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(intent)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setProgress(100, status, false)
+ .setOngoing(true);
SystemUI.overrideNotificationAppName(mContext, builder);
mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
@@ -527,18 +527,18 @@ public class StorageNotification extends SystemUI {
intent = null;
}
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_sd_card_48dp)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(intent)
- .setStyle(new Notification.BigTextStyle().bigText(text))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setLocalOnly(true)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .setAutoCancel(true);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.STORAGE)
+ .setSmallIcon(R.drawable.ic_sd_card_48dp)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(intent)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setAutoCancel(true);
SystemUI.overrideNotificationAppName(mContext, builder);
mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
@@ -563,14 +563,15 @@ public class StorageNotification extends SystemUI {
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(text)
- .setStyle(new Notification.BigTextStyle().bigText(text))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setLocalOnly(true);
+ Notification.Builder builder =
+ new Notification.Builder(mContext, NotificationChannels.STORAGE)
+ .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true);
overrideNotificationAppName(mContext, builder);
return builder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
new file mode 100644
index 000000000000..15ad0ce5b51b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -0,0 +1,60 @@
+/*
+ * 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.util;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+
+import android.content.Context;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.util.Arrays;
+
+public class NotificationChannels extends SystemUI {
+ public static String ALERTS = "ALR";
+ public static String SCREENSHOTS = "SCN";
+ public static String GENERAL = "GEN";
+ public static String STORAGE = "DSK";
+
+ @VisibleForTesting
+ static void createAll(Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ nm.createNotificationChannels(Arrays.asList(
+ new NotificationChannel(
+ ALERTS,
+ context.getString(R.string.notification_channel_alerts),
+ NotificationManager.IMPORTANCE_HIGH),
+ new NotificationChannel(
+ SCREENSHOTS,
+ context.getString(R.string.notification_channel_screenshot),
+ NotificationManager.IMPORTANCE_LOW),
+ new NotificationChannel(
+ GENERAL,
+ context.getString(R.string.notification_channel_general),
+ NotificationManager.IMPORTANCE_MIN),
+ new NotificationChannel(
+ STORAGE,
+ context.getString(R.string.notification_channel_storage),
+ NotificationManager.IMPORTANCE_LOW)
+ ));
+ }
+
+ @Override
+ public void start() {
+ createAll(mContext);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index d057d863e9ef..b9cb5750e333 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -69,6 +69,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -165,7 +166,7 @@ public class VolumeDialog implements TunerService.Tunable {
controller.addCallback(mControllerCallbackH, mHandler);
controller.getState();
- TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
+ Dependency.get(TunerService.class).addTunable(this, SHOW_FULL_ZEN);
final Configuration currentConfig = mContext.getResources().getConfiguration();
mDensity = currentConfig.densityDpi;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 137a12fbdfa3..0a1d34ff701e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -31,7 +31,6 @@ import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -73,7 +72,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY,
mController, mZenModeController, mVolumeDialogCallback);
applyConfiguration();
- TunerService.get(mContext).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
+ Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
VOLUME_SILENT_DO_NOT_DISTURB);
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index c627e224dee8..cefade086795 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -43,6 +43,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v17-leanback
LOCAL_STATIC_JAVA_LIBRARIES := \
+ metrics-helper-lib \
android-support-test \
mockito-updated-target-minus-junit4 \
SystemUI-proto \
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 6516369d0e2e..6d6243520b5b 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.systemui.tests">
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -30,6 +31,10 @@
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/res/layout/custom_view_dark.xml b/packages/SystemUI/tests/res/layout/custom_view_dark.xml
new file mode 100644
index 000000000000..9e460a5819a9
--- /dev/null
+++ b/packages/SystemUI/tests/res/layout/custom_view_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#ff000000"
+ />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
index cb0f7a388d01..09808d47a995 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
@@ -51,24 +50,6 @@ public class BatteryMeterDrawableTest extends SysuiTestCase {
}
@Test
- public void testGetIntrinsicSize() {
- assertEquals(
- mResources.getDimensionPixelSize(R.dimen.battery_width),
- mBatteryMeter.getIntrinsicWidth());
- assertEquals(
- mResources.getDimensionPixelSize(R.dimen.battery_height),
- mBatteryMeter.getIntrinsicHeight());
- }
-
- @Test
- public void testDrawNothingBeforeOnBatteryLevelChanged() {
- final Canvas canvas = mock(Canvas.class);
- mBatteryMeter.draw(canvas);
- verify(canvas, never()).drawPath(any(), any());
- verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
- }
-
- @Test
public void testDrawImageButNoTextIfPluggedIn() {
mBatteryMeter.onBatteryLevelChanged(0, true, true);
final Canvas canvas = mock(Canvas.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 973f1f26033c..fb4b6bdf3f1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -15,6 +15,7 @@
package com.android.systemui;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -25,6 +26,8 @@ import com.android.systemui.statusbar.policy.FlashlightController;
import org.junit.Test;
+import java.io.PrintWriter;
+
public class DependencyTest extends SysuiTestCase {
@Test
@@ -46,8 +49,8 @@ public class DependencyTest extends SysuiTestCase {
Dumpable d = mock(Dumpable.class);
injectTestDependency("test", d);
Dependency.get("test");
- mDependency.dump(null, null, null);
- verify(d).dump(eq(null), eq(null), eq(null));
+ mDependency.dump(null, mock(PrintWriter.class), null);
+ verify(d).dump(eq(null), any(), eq(null));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
index 447edace3028..f8f67bb15c29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
@@ -19,13 +19,17 @@ import android.app.Fragment;
import android.app.FragmentController;
import android.app.FragmentHostCallback;
import android.app.FragmentManagerNonConfig;
+import android.graphics.PixelFormat;
import android.os.Handler;
-import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Parcelable;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
+import com.android.systemui.utils.ViewUtils;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.After;
@@ -45,7 +49,6 @@ public abstract class FragmentTestCase extends LeakCheckedTest {
private static final int VIEW_ID = 42;
private final Class<? extends Fragment> mCls;
- private HandlerThread mHandlerThread;
private Handler mHandler;
private FrameLayout mView;
protected FragmentController mFragments;
@@ -59,9 +62,7 @@ public abstract class FragmentTestCase extends LeakCheckedTest {
public void setupFragment() throws IllegalAccessException, InstantiationException {
mView = new FrameLayout(mContext);
mView.setId(VIEW_ID);
- mHandlerThread = new HandlerThread("FragmentTestThread");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler(Looper.getMainLooper());
mFragment = mCls.newInstance();
postAndWait(() -> {
mFragments = FragmentController.createController(new HostCallbacks());
@@ -78,7 +79,6 @@ public abstract class FragmentTestCase extends LeakCheckedTest {
// Set mFragments to null to let it know not to destroy.
postAndWait(() -> mFragments.dispatchDestroy());
}
- mHandlerThread.quit();
}
@Test
@@ -100,6 +100,26 @@ public abstract class FragmentTestCase extends LeakCheckedTest {
}
@Test
+ public void testAttachDetach() {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_SYSTEM_ALERT,
+ 0, PixelFormat.TRANSLUCENT);
+ postAndWait(() -> mFragments.dispatchResume());
+ attachFragmentToWindow();
+ detachFragmentToWindow();
+ postAndWait(() -> mFragments.dispatchPause());
+ }
+
+ protected void attachFragmentToWindow() {
+ ViewUtils.attachView(mView);
+ }
+
+ protected void detachFragmentToWindow() {
+ ViewUtils.detachView(mView);
+ }
+
+ @Test
public void testRecreate() {
postAndWait(() -> mFragments.dispatchResume());
postAndWait(() -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 5fe5174c3d27..81a50d9fca58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -43,6 +43,7 @@ public abstract class SysuiTestCase {
public void SysuiSetup() throws Exception {
System.setProperty("dexmaker.share_classloader", "true");
mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
+ SystemUIFactory.createFromConfig(mContext);
mDependency = new TestDependency();
mDependency.mContext = mContext;
mDependency.start();
@@ -64,7 +65,7 @@ public abstract class SysuiTestCase {
waitForIdleSync(mHandler);
}
- protected void waitForIdleSync(Handler h) {
+ public static void waitForIdleSync(Handler h) {
validateThread(h.getLooper());
Idler idler = new Idler(null);
h.getLooper().getQueue().addIdleHandler(idler);
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 e3ee8514fe3b..f22c1af23efa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -15,11 +15,6 @@
package com.android.systemui.qs;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
import com.android.systemui.Dependency;
import com.android.systemui.FragmentTestCase;
@@ -27,27 +22,16 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
@RunWith(AndroidJUnit4.class)
public class QSFragmentTest extends FragmentTestCase {
@@ -58,12 +42,9 @@ public class QSFragmentTest extends FragmentTestCase {
@Before
public void addLeakCheckDependencies() {
+ injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
injectMockDependency(UserSwitcherController.class);
- injectLeakCheckedDependencies(BluetoothController.class, LocationController.class,
- RotationLockController.class, NetworkController.class, ZenModeController.class,
- HotspotController.class, CastController.class, FlashlightController.class,
- UserInfoController.class, KeyguardMonitor.class, SecurityController.class,
- BatteryController.class, NextAlarmController.class);
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
}
@Test
@@ -87,6 +68,6 @@ public class QSFragmentTest extends FragmentTestCase {
host.destroy();
// Ensure the tuner cleans up its persistent listeners.
- TunerService.get(mContext).destroy();
+ Dependency.get(TunerService.class).destroy();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 5401c30def54..95190e331d64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -161,4 +161,10 @@ public class TileLayoutTest extends SysuiTestCase {
assertEquals(top1.getValue().intValue(), top2.getValue().intValue());
assertEquals(bottom1.getValue().intValue(), bottom2.getValue().intValue());
}
+
+ @Test
+ public void testEmptyHeight() {
+ mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+ assertEquals(0, mTileLayout.getMeasuredHeight());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 43f8629b2945..5b22986f6961 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -171,27 +171,6 @@ public class CommandQueueTest extends SysuiTestCase {
}
@Test
- public void testBuzzBeepBlink() {
- mCommandQueue.buzzBeepBlinked();
- waitForIdleSync();
- verify(mCallbacks).buzzBeepBlinked();
- }
-
- @Test
- public void testNotificationLightOff() {
- mCommandQueue.notificationLightOff();
- waitForIdleSync();
- verify(mCallbacks).notificationLightOff();
- }
-
- @Test
- public void testNotificationLightPulse() {
- mCommandQueue.notificationLightPulse(1, 2, 3);
- waitForIdleSync();
- verify(mCallbacks).notificationLightPulse(eq(1), eq(2), eq(3));
- }
-
- @Test
public void testScreenPinRequest() {
mCommandQueue.showScreenPinningRequest(1);
waitForIdleSync();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
index 3bb9f5fe8546..77f96b8a7b19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
@@ -31,6 +28,11 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationContentViewTest {
@@ -39,13 +41,16 @@ public class NotificationContentViewTest {
Context mContext;
@Before
+ @UiThreadTest
public void setup() {
- ExpandableNotificationRow rowMock = mock(ExpandableNotificationRow.class);
- when(rowMock.getIntrinsicHeight()).thenReturn(10);
-
mContext = InstrumentationRegistry.getTargetContext();
mView = new NotificationContentView(mContext, null);
- mView.setContainingNotification(rowMock);
+ ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
+ ExpandableNotificationRow mockRow = spy(row);
+ doNothing().when(mockRow).updateBackgroundAlpha(anyFloat());
+ doReturn(10).when(mockRow).getIntrinsicHeight();
+
+ mView.setContainingNotification(mockRow);
mView.setHeights(10, 20, 30, 40);
mView.setContractedChild(createViewWithHeight(10));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
new file mode 100644
index 000000000000..d07cea1dca0e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationCustomViewWrapperTest {
+
+ private Context mContext;
+ private ExpandableNotificationRow mRow;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mRow = new ExpandableNotificationRow(mContext, null);
+ }
+
+ @Test
+ public void testBackgroundPersists() {
+ RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.custom_view_dark);
+ View v = views.apply(mContext, null);
+ NotificationViewWrapper wrap = NotificationCustomViewWrapper.wrap(mContext, v, mRow);
+ wrap.notifyContentUpdated(null, false /* isLowPriority */);
+ Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
+ views.reapply(mContext, v);
+ wrap.notifyContentUpdated(null, false /* isLowPriority */);
+ Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
+ }
+
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
index cac0806e0f15..3e0d15d3cb69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
@@ -64,6 +64,7 @@ public class NotificationGutsTest {
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
private NotificationGuts mNotificationGuts;
+ private NotificationInfo mNotificationInfo;
private final INotificationManager mMockINotificationManager = mock(INotificationManager.class);
private final PackageManager mMockPackageManager = mock(PackageManager.class);
private NotificationChannel mNotificationChannel;
@@ -76,8 +77,11 @@ public class NotificationGutsTest {
// Inflate the layout
final LayoutInflater layoutInflater =
LayoutInflater.from(InstrumentationRegistry.getTargetContext());
+ mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
+ null);
mNotificationGuts = (NotificationGuts) layoutInflater.inflate(R.layout.notification_guts,
null);
+ mNotificationInfo.setInteractionListener(mNotificationGuts);
// PackageManager must return a packageInfo and applicationInfo.
final PackageInfo packageInfo = new PackageInfo();
@@ -98,18 +102,18 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.pkgname);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
}
@Test
@UiThreadTest
public void testBindNotification_SetsTextChannelName() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.channel_name);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -117,12 +121,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel,
(View v, int appUid) -> { latch.countDown(); }, null, null);
- final TextView settingsButton =
- (TextView) mNotificationGuts.findViewById(R.id.more_settings);
+ final TextView settingsButton =
+ (TextView) mNotificationInfo.findViewById(R.id.more_settings);
settingsButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -132,12 +136,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForDone() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null,
(View v) -> { latch.countDown(); },
null);
- final TextView doneButton = (TextView) mNotificationGuts.findViewById(R.id.done);
+ final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done);
doneButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -146,38 +150,38 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
public void testHasImportanceChanged_DefaultsToFalse() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- assertFalse(mNotificationGuts.hasImportanceChanged());
+ assertFalse(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testHasImportanceChanged_ReturnsTrueAfterButtonChecked() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
// Find the high button and check it.
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
- assertTrue(mNotificationGuts.hasImportanceChanged());
+ assertTrue(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testImportanceButtonCheckedBasedOnInitialImportance() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
assertTrue(highButton.isChecked());
}
@Test
@UiThreadTest
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -187,10 +191,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -198,37 +202,38 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
- public void testCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ public void testSaveImportance_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.saveImportance();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@Test
@UiThreadTest
- public void testCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() throws Exception {
+ public void testSaveImportance_DoesNotUpdateNotificationChannelIfUnspecified()
+ throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.saveImportance();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@Test
@UiThreadTest
- public void testCloseControls_CallsUpdateNotificationChannelIfChanged() throws Exception {
+ public void testSaveImportance_CallsUpdateNotificationChannelIfChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.saveImportance();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
assertEquals(NotificationManager.IMPORTANCE_HIGH, mNotificationChannel.getImportance());
@@ -236,26 +241,12 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
- public void testCloseControls_DoesNotUpdateNotificationChannelIfSaveFalse() throws Exception {
- mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
- mMockStatusBarNotification, mNotificationChannel, null, null, null);
-
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
- highButton.setChecked(true);
- mNotificationGuts.closeControls(-1, -1, false);
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
- }
-
- @Test
- @UiThreadTest
public void testEnabledSwitchOnByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertTrue(enabledSwitch.isChecked());
}
@@ -263,10 +254,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchVisibleByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
}
@@ -274,11 +265,11 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@@ -286,13 +277,13 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.saveImportance();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
}
@@ -301,14 +292,14 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchOverridesOtherButtons() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
- RadioButton lowButton = (RadioButton) mNotificationGuts.findViewById(R.id.low_importance);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
+ RadioButton lowButton = (RadioButton) mNotificationInfo.findViewById(R.id.low_importance);
lowButton.setChecked(true);
enabledSwitch.setChecked(false);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.saveImportance();
assertEquals(NotificationManager.IMPORTANCE_NONE, mNotificationChannel.getImportance());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
new file mode 100644
index 000000000000..71411706c4a9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.systemui.utils.ViewUtils;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class NotificationMenuRowTest extends LeakCheckedTest {
+
+ @Before
+ public void setup() {
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ }
+
+ @Test
+ public void testAttachDetach() {
+ NotificationMenuRow row = new NotificationMenuRow(mContext);
+ ViewUtils.attachView(row);
+ ViewUtils.detachView(row);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 7d9e0736fdad..68f9cb05ecaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,36 +16,74 @@
package com.android.systemui.statusbar;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+
+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.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.drawable.Icon;
-import android.os.Debug;
import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.mockito.ArgumentMatcher;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StatusBarIconViewTest extends SysuiTestCase {
+ @Rule
+ public ExpectedException mThrown = ExpectedException.none();
+
private StatusBarIconView mIconView;
private StatusBarIcon mStatusBarIcon = mock(StatusBarIcon.class);
+ private PackageManager mPackageManagerSpy;
+ private Context mContext;
+ private Resources mMockResources;
+
@Before
- public void setUp() {
- mIconView = new StatusBarIconView(getContext(), "slot", null);
- mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, getContext().getPackageName(),
- Icon.createWithResource(getContext(), R.drawable.ic_android), 0, 0, "");
+ public void setUp() throws Exception {
+ // Set up context such that asking for "mockPackage" resources returns mMockResources.
+ mMockResources = mock(Resources.class);
+ mPackageManagerSpy = spy(getContext().getPackageManager());
+ doReturn(mMockResources).when(mPackageManagerSpy)
+ .getResourcesForApplicationAsUser(eq("mockPackage"), anyInt());
+ doReturn(mMockResources).when(mPackageManagerSpy)
+ .getResourcesForApplication(eq("mockPackage"));
+ doReturn(mMockResources).when(mPackageManagerSpy).getResourcesForApplication(argThat(
+ (ArgumentMatcher<ApplicationInfo>) o -> "mockPackage".equals(o.packageName)));
+ mContext = new ContextWrapper(getContext()) {
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManagerSpy;
+ }
+ };
+
+ mIconView = new StatusBarIconView(mContext, "test_slot", null);
+ mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ Icon.createWithResource(mContext, R.drawable.ic_android), 0, 0, "");
}
@Test
@@ -55,4 +93,11 @@ public class StatusBarIconViewTest extends SysuiTestCase {
assertNull(mIconView.getTag(R.id.icon_is_grayscale));
}
+ @Test
+ public void testSettingOomingIconDoesNotThrowOom() {
+ when(mMockResources.getDrawable(anyInt(), any())).thenThrow(new OutOfMemoryError("mocked"));
+ mStatusBarIcon.icon = Icon.createWithResource("mockPackage", R.drawable.ic_android);
+
+ assertFalse(mIconView.set(mStatusBarIcon));
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 9fcb5f75ff22..a9d6df768fa9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.view.WindowManager;
import com.android.systemui.FragmentTestCase;
-import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
@@ -37,9 +36,11 @@ public class NavigationBarFragmentTest extends FragmentTestCase {
@Before
public void setup() {
mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
- mContext.putComponent(PhoneStatusBar.class, mock(PhoneStatusBar.class));
+ mContext.putComponent(StatusBar.class, mock(StatusBar.class));
mContext.putComponent(Recents.class, mock(Recents.class));
mContext.putComponent(Divider.class, mock(Divider.class));
+ mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class));
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
deleted file mode 100644
index d82566f0bb46..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
+++ /dev/null
@@ -1,95 +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.statusbar.phone;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.BaseStatusBar;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class PhoneStatusBarTest extends SysuiTestCase {
-
- StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- PhoneStatusBar mPhoneStatusBar;
-
- @Before
- public void setup() {
- mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class);
- mPhoneStatusBar = new TestablePhoneStatusBar(mStatusBarKeyguardViewManager);
-
- doAnswer(invocation -> {
- OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
- onDismissAction.onDismiss();
- return null;
- }).when(mStatusBarKeyguardViewManager).dismissWithAction(any(), any(), anyBoolean());
-
- doAnswer(invocation -> {
- Runnable runnable = (Runnable) invocation.getArguments()[0];
- runnable.run();
- return null;
- }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- }
-
- @Test
- public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() {
- when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
- when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true);
-
- mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
- }
-
- @Test
- public void executeRunnableDismissingKeyguard_nullRunnable_showing() {
- when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
- when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
-
- mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
- }
-
- @Test
- public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() {
- when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
- when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
-
- mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
- }
-
- static class TestablePhoneStatusBar extends PhoneStatusBar {
- public TestablePhoneStatusBar(StatusBarKeyguardViewManager man) {
- mStatusBarKeyguardViewManager = man;
- }
-
- @Override
- protected BaseStatusBar.H createHandler() {
- return null;
- }
- }
-} \ No newline at end of file
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
new file mode 100644
index 000000000000..21c7fce44579
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.metrics.LogMaker;
+import android.metrics.MetricsReader;
+import android.support.test.filters.SmallTest;
+import android.support.test.metricshelper.MetricsAsserts;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.DisplayMetrics;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StatusBarTest extends SysuiTestCase {
+
+ StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ UnlockMethodCache mUnlockMethodCache;
+ KeyguardIndicationController mKeyguardIndicationController;
+ NotificationStackScrollLayout mStackScroller;
+ StatusBar mStatusBar;
+
+ private MetricsReader mMetricsReader;
+ private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+
+ @Before
+ public void setup() {
+ mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class);
+ mUnlockMethodCache = mock(UnlockMethodCache.class);
+ mKeyguardIndicationController = mock(KeyguardIndicationController.class);
+ mStackScroller = mock(NotificationStackScrollLayout.class);
+ mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
+ mKeyguardIndicationController, mStackScroller);
+
+ doAnswer(invocation -> {
+ OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
+ onDismissAction.onDismiss();
+ return null;
+ }).when(mStatusBarKeyguardViewManager).dismissWithAction(any(), any(), anyBoolean());
+
+ doAnswer(invocation -> {
+ Runnable runnable = (Runnable) invocation.getArguments()[0];
+ runnable.run();
+ return null;
+ }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
+
+ when(mStackScroller.getActivatedChild()).thenReturn(null);
+
+ mMetricsReader = new MetricsReader();
+ mMetricsReader.checkpoint(); // clear out old logs
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true);
+
+ mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_showing() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+ mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+ mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ @Test
+ public void lockscreenStateMetrics_notShowing() {
+ // uninteresting state, except that fingerprint must be non-zero
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mUnlockMethodCache.canSkipBouncer()).thenReturn(true);
+ // interesting state
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+ when(mUnlockMethodCache.isMethodSecure()).thenReturn(false);
+
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
+
+ MetricsAsserts.assertHasLog("missing hidden insecure lockscreen log", mMetricsReader,
+ new LogMaker(MetricsEvent.LOCKSCREEN)
+ .setType(MetricsEvent.TYPE_CLOSE)
+ .setSubtype(0));
+ }
+
+ @Test
+ public void lockscreenStateMetrics_notShowing_secure() {
+ // uninteresting state, except that fingerprint must be non-zero
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mUnlockMethodCache.canSkipBouncer()).thenReturn(true);
+ // interesting state
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+ when(mUnlockMethodCache.isMethodSecure()).thenReturn(true);
+
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
+
+ MetricsAsserts.assertHasLog("missing hidden secure lockscreen log", mMetricsReader,
+ new LogMaker(MetricsEvent.LOCKSCREEN)
+ .setType(MetricsEvent.TYPE_CLOSE)
+ .setSubtype(1));
+ }
+
+ @Test
+ public void lockscreenStateMetrics_isShowing() {
+ // uninteresting state, except that fingerprint must be non-zero
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mUnlockMethodCache.canSkipBouncer()).thenReturn(true);
+ // interesting state
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+ when(mUnlockMethodCache.isMethodSecure()).thenReturn(false);
+
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
+
+ MetricsAsserts.assertHasLog("missing insecure lockscreen showing", mMetricsReader,
+ new LogMaker(MetricsEvent.LOCKSCREEN)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype(0));
+ }
+
+ @Test
+ public void lockscreenStateMetrics_isShowing_secure() {
+ // uninteresting state, except that fingerprint must be non-zero
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mUnlockMethodCache.canSkipBouncer()).thenReturn(true);
+ // interesting state
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+ when(mUnlockMethodCache.isMethodSecure()).thenReturn(true);
+
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
+
+ MetricsAsserts.assertHasLog("missing secure lockscreen showing log", mMetricsReader,
+ new LogMaker(MetricsEvent.LOCKSCREEN)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype(1));
+ }
+
+ @Test
+ public void lockscreenStateMetrics_isShowingBouncer() {
+ // uninteresting state, except that fingerprint must be non-zero
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mUnlockMethodCache.canSkipBouncer()).thenReturn(true);
+ // interesting state
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mUnlockMethodCache.isMethodSecure()).thenReturn(true);
+
+ mStatusBar.onKeyguardViewManagerStatesUpdated();
+
+ MetricsAsserts.assertHasLog("missing bouncer log", mMetricsReader,
+ new LogMaker(MetricsEvent.BOUNCER)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype(1));
+ }
+
+ @Test
+ public void onActivatedMetrics() {
+ ActivatableNotificationView view = mock(ActivatableNotificationView.class);
+ mStatusBar.onActivated(view);
+
+ MetricsAsserts.assertHasLog("missing lockscreen note tap log", mMetricsReader,
+ new LogMaker(MetricsEvent.ACTION_LS_NOTE)
+ .setType(MetricsEvent.TYPE_ACTION));
+ }
+
+ static class TestableStatusBar extends StatusBar {
+ public TestableStatusBar(StatusBarKeyguardViewManager man,
+ UnlockMethodCache unlock, KeyguardIndicationController key,
+ NotificationStackScrollLayout stack) {
+ mStatusBarKeyguardViewManager = man;
+ mUnlockMethodCache = unlock;
+ mKeyguardIndicationController = key;
+ mStackScroller = stack;
+ }
+
+ @Override
+ protected H createHandler() {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 7b56ea39137d..b544d9df1292 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy;
import android.os.HandlerThread;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.SubscriptionInfo;
-import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
@@ -37,6 +36,8 @@ import org.mockito.MockitoAnnotations;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class CallbackHandlerTest {
@@ -110,8 +111,9 @@ public class CallbackHandlerTest {
int qsType = R.drawable.ic_qs_signal_1x;
boolean wide = true;
int subId = 5;
+ boolean roaming = true;
mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription,
- description, wide, subId);
+ description, wide, subId, roaming);
waitForCallbacks();
ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
@@ -127,7 +129,7 @@ public class CallbackHandlerTest {
Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(),
qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(),
outArg.capture(), typeContentArg.capture(), descArg.capture(), wideArg.capture(),
- subIdArg.capture());
+ subIdArg.capture(), eq(roaming));
assertEquals(status, statusArg.getValue());
assertEquals(qs, qsArg.getValue());
assertEquals(type, (int) typeIconArg.getValue());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 23c635c3e93f..0e5f51313b7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
+import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.Looper;
import android.telephony.PhoneStateListener;
@@ -54,6 +55,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -79,6 +81,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected Config mConfig;
protected CallbackHandler mCallbackHandler;
protected SubscriptionDefaults mMockSubDefaults;
+ protected NetworkScoreManager mMockNetworkScoreManager;
protected int mSubId;
@@ -105,6 +108,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mMockCm = mock(ConnectivityManager.class);
mMockSubDefaults = mock(SubscriptionDefaults.class);
mNetCapabilities = new NetworkCapabilities();
+ mMockNetworkScoreManager = mock(NetworkScoreManager.class);
+
when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn(
new NetworkCapabilities[] { mNetCapabilities });
@@ -115,7 +120,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mConfig = new Config();
mConfig.hspaDataDistinguishable = true;
mCallbackHandler = mock(CallbackHandler.class);
- mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
+ mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager,
+ mMockTm, mMockWm, mMockSm,
mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class));
@@ -157,8 +163,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected NetworkControllerImpl setUpNoMobileData() {
when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
NetworkControllerImpl networkControllerNoMobile
- = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, mContext.getMainLooper(), mCallbackHandler,
+ = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm,
+ mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
mock(DeviceProvisionedController.class));
@@ -292,7 +298,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
iconArg.capture(),
anyInt(),
typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
- anyString(), anyString(), anyBoolean(), anyInt());
+ anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean());
IconState iconState = iconArg.getValue();
assertEquals("Visibility in, quick settings", visible, iconState.visible);
assertEquals("Signal icon in, quick settings", icon, iconState.icon);
@@ -304,6 +310,11 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
}
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon) {
+ verifyLastMobileDataIndicators(visible, icon, typeIcon, false);
+ }
+
+ protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
+ boolean roaming) {
ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
@@ -313,9 +324,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
any(),
typeIconArg.capture(),
anyInt(), anyBoolean(), anyBoolean(), anyString(), anyString(), anyBoolean(),
- anyInt());
+ anyInt(), eq(roaming));
IconState iconState = iconArg.getValue();
+ assertEquals("Signal icon in status bar", icon, iconState.icon);
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
assertEquals("Visibility in status bar", visible, iconState.visible);
}
@@ -336,7 +348,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
qsTypeIconArg.capture(),
dataInArg.capture(),
dataOutArg.capture(),
- anyString(), anyString(), anyBoolean(), anyInt());
+ anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean());
IconState iconState = iconArg.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 1f7ec1aecd16..d7f961cb0738 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -25,19 +25,6 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
}
@Test
- public void testRoamingDataIcon() {
- setupDefaultSignal();
- setGsmRoaming(true);
-
- verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
- TelephonyIcons.ROAMING_ICON,
- true,
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL],
- TelephonyIcons.QS_DATA_R, false, false);
- }
-
- @Test
public void test2gDataIcon() {
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -100,7 +87,8 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
public void test4gDataIcon() {
// Switch to showing 4g icon and re-initialize the NetworkController.
mConfig.show4gForLte = true;
- mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
+ mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager,
+ mMockTm, mMockWm, mMockSm,
mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 1a61d80e24f1..2c0f9c93d353 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -53,7 +53,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Turn off mobile network support.
Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
- mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
+ mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager,
+ mMockTm, mMockWm, mMockSm,
mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class));
@@ -107,7 +108,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Turn off mobile network support.
Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
- mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
+ mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager,
+ mMockTm, mMockWm, mMockSm,
mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class));
@@ -156,13 +158,12 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
setupDefaultSignal();
- setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
setGsmRoaming(true);
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
- TelephonyIcons.ROAMING_ICON);
+ DEFAULT_ICON, true);
}
}
@@ -177,7 +178,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
verifyLastMobileDataIndicators(true,
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
- TelephonyIcons.ROAMING_ICON);
+ TelephonyIcons.DATA_1X[1][0 /* No direction */], true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index ed32f65179c6..9b382f6165a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -3,22 +3,46 @@ package com.android.systemui.statusbar.policy;
import android.content.Intent;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkKey;
+import android.net.RssiCurve;
+import android.net.ScoredNetwork;
+import android.net.WifiKey;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.settingslib.Utils;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Matchers;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -27,6 +51,13 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
private static final int MIN_RSSI = -100;
private static final int MAX_RSSI = -55;
+ private static final int LATCH_TIMEOUT = 2000;
+ private static final String TEST_SSID = "\"Test SSID\"";
+ private static final String TEST_BSSID = "00:00:00:00:00:00";
+
+ private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
+ private CountDownLatch mRequestScoresLatch;
+
@Test
public void testWifiIcon() {
String testSsid = "Test SSID";
@@ -47,6 +78,82 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
}
@Test
+ public void testBadgedWifiIcon() throws Exception {
+ // TODO(sghuman): Refactor this setup code when creating a test for the badged QsIcon.
+ int testLevel = 1;
+ RssiCurve mockBadgeCurve = mock(RssiCurve.class);
+ Bundle attr = new Bundle();
+ attr.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve);
+ ScoredNetwork score =
+ new ScoredNetwork(
+ new NetworkKey(new WifiKey(TEST_SSID, TEST_BSSID)),
+ null,
+ false /* meteredHint */,
+ attr);
+
+ // Must set the Settings value before instantiating the NetworkControllerImpl due to bugs in
+ // FakeSettingsProvider.
+ SettingOverrider settingsOverrider =
+ mContext.getSettingsProvider().acquireOverridesBuilder(this)
+ .addSetting("global", Settings.Global.NETWORK_SCORING_UI_ENABLED, "1")
+ .build();
+ super.setUp(); // re-instantiate NetworkControllImpl now that setting has been updated
+ setupNetworkScoreManager();
+
+ // Test Requesting Scores
+ mRequestScoresLatch = new CountDownLatch(1);
+ setWifiEnabled(true);
+ setWifiState(true, TEST_SSID, TEST_BSSID);
+ mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) ScoredNetwork.BADGING_SD);
+
+ ArgumentCaptor<WifiNetworkScoreCache> scoreCacheCaptor =
+ ArgumentCaptor.forClass(WifiNetworkScoreCache.class);
+ verify(mMockNetworkScoreManager).registerNetworkScoreCache(
+ anyInt(),
+ scoreCacheCaptor.capture(),
+ Matchers.anyInt());
+ scoreCacheCaptor.getValue().updateScores(Arrays.asList(score));
+
+ // Test badge is set
+ setWifiLevel(testLevel);
+
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
+ anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
+ any());
+ IconState iconState = iconArg.getValue();
+
+ assertEquals("Badged Wifi Resource is set",
+ Utils.WIFI_PIE_FOR_BADGING[testLevel],
+ iconState.icon);
+ assertEquals("SD Badge is set",
+ Utils.getWifiBadgeResource(ScoredNetwork.BADGING_SD),
+ iconState.iconOverlay);
+
+ settingsOverrider.release();
+ }
+
+ private void setupNetworkScoreManager() {
+ // Capture requested keys and count down latch if present
+ doAnswer(
+ new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock input) {
+ if (mRequestScoresLatch != null) {
+ mRequestScoresLatch.countDown();
+ }
+ NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0];
+ for (NetworkKey key : keys) {
+ mRequestedKeys.add(key);
+ }
+ return true;
+ }
+ }).when(mMockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());
+ }
+
+ @Test
public void testQsWifiIcon() {
String testSsid = "Test SSID";
@@ -97,7 +204,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
@Test
public void testRoamingIconDuringWifi() {
// Setup normal connection
- String testSsid = "Test SSID";
+ String testSsid = "\"Test SSID\"";
int testLevel = 2;
setWifiEnabled(true);
setWifiState(true, testSsid);
@@ -109,9 +216,10 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
setGsmRoaming(true);
// Still be on wifi though.
setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
verifyLastMobileDataIndicators(true,
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
- TelephonyIcons.ROAMING_ICON);
+ 0, true);
}
protected void setWifiActivity(int activity) {
@@ -137,12 +245,19 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
}
protected void setWifiState(boolean connected, String ssid) {
+ setWifiState(connected, ssid, null);
+ }
+
+ protected void setWifiState(boolean connected, String ssid, String bssid) {
Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
Mockito.when(networkInfo.isConnected()).thenReturn(connected);
WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
Mockito.when(wifiInfo.getSSID()).thenReturn(ssid);
+ if (bssid != null) {
+ Mockito.when(wifiInfo.getBSSID()).thenReturn(bssid);
+ }
i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
i.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo);
@@ -166,8 +281,8 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
- enabledArg.capture(), any(), iconArg.capture(), anyBoolean(), anyBoolean(),
- descArg.capture());
+ enabledArg.capture(), any(), iconArg.capture(), anyBoolean(),
+ anyBoolean(), descArg.capture());
IconState iconState = iconArg.getValue();
assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
@@ -179,7 +294,8 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
- anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(), any());
+ anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
+ any());
IconState iconState = iconArg.getValue();
assertEquals("WiFi visible, in status bar", visible, iconState.visible);
assertEquals("WiFi signal, in status bar", icon, iconState.icon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
new file mode 100644
index 000000000000..f67296d9905a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.NotificationChannels;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ChannelsTest extends SysuiTestCase {
+ private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
+
+ @Before
+ public void setup() throws Exception {
+ mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, mMockNotificationManager);
+ }
+
+ @Test
+ public void testChannelSetup() {
+ Set<String> ALL_CHANNELS = new ArraySet<>(Arrays.asList(
+ NotificationChannels.ALERTS,
+ NotificationChannels.SCREENSHOTS,
+ NotificationChannels.STORAGE,
+ NotificationChannels.GENERAL
+ ));
+ NotificationChannels.createAll(mContext);
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(mMockNotificationManager).createNotificationChannels(captor.capture());
+ final List<NotificationChannel> list = captor.getValue();
+ assertEquals(ALL_CHANNELS.size(), list.size());
+ list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId())));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
new file mode 100644
index 000000000000..202c4cfda782
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+
+public class ViewUtils {
+
+ public static void attachView(View view) {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_APPLICATION_OVERLAY,
+ 0, PixelFormat.TRANSLUCENT);
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(() -> InstrumentationRegistry.getContext()
+ .getSystemService(WindowManager.class).addView(view, lp));
+ SysuiTestCase.waitForIdleSync(handler);
+ }
+
+ public static void detachView(View view) {
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(() -> InstrumentationRegistry.getContext()
+ .getSystemService(WindowManager.class).removeView(view));
+ SysuiTestCase.waitForIdleSync(handler);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
new file mode 100644
index 000000000000..d1abccaa6e76
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
@@ -0,0 +1,53 @@
+/*
+ * 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.utils.leaks;
+
+import android.content.Context;
+
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+
+public class FakePluginManager extends PluginManager {
+
+ private final BaseLeakChecker<PluginListener> mLeakChecker;
+
+ public FakePluginManager(Context context, LeakCheckedTest test) {
+ super(context);
+ mLeakChecker = new BaseLeakChecker<>(test, "Plugin");
+ }
+
+ @Override
+ public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
+ int version) {
+ mLeakChecker.addCallback(listener);
+ }
+
+ @Override
+ public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
+ int version, boolean allowMultiple) {
+ mLeakChecker.addCallback(listener);
+ }
+
+ @Override
+ public void removePluginListener(PluginListener<?> listener) {
+ mLeakChecker.removeCallback(listener);
+ }
+
+ @Override
+ public <T extends Plugin> T getOneShotPlugin(String action, int version) {
+ return null;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java
new file mode 100644
index 000000000000..b841ce908ca2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils.leaks;
+
+import android.content.Context;
+
+import com.android.systemui.tuner.TunerService;
+
+public class FakeTunerService extends TunerService {
+
+ private final BaseLeakChecker<Tunable> mBaseLeakChecker;
+
+ public FakeTunerService(Context context, LeakCheckedTest test) {
+ super(context);
+ mBaseLeakChecker = new BaseLeakChecker<>(test, "tunable");
+ destroy();
+ }
+
+ @Override
+ public void addTunable(Tunable tunable, String... keys) {
+ for (String key : keys) {
+ tunable.onTuningChanged(key, null);
+ }
+ mBaseLeakChecker.addCallback(tunable);
+ }
+
+ @Override
+ public void removeTunable(Tunable tunable) {
+ mBaseLeakChecker.removeCallback(tunable);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
index c182493cf570..c2048c7884de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
@@ -20,6 +20,7 @@ import static org.mockito.Mockito.doAnswer;
import android.util.ArrayMap;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
import org.junit.Assert;
import org.junit.Rule;
@@ -56,6 +58,25 @@ public abstract class LeakCheckedTest extends SysuiTestCase {
private final Map<String, Tracker> mTrackers = new HashMap<>();
private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
+ public static final Class<?>[] ALL_SUPPORTED_CLASSES = new Class[] {
+ BluetoothController.class,
+ LocationController.class,
+ RotationLockController.class,
+ ZenModeController.class,
+ CastController.class,
+ HotspotController.class,
+ FlashlightController.class,
+ UserInfoController.class,
+ KeyguardMonitor.class,
+ BatteryController.class,
+ SecurityController.class,
+ ManagedProfileController.class,
+ NextAlarmController.class,
+ NetworkController.class,
+ PluginManager.class,
+ TunerService.class,
+ };
+
@Rule
public TestWatcher successWatcher = new TestWatcher() {
@Override
@@ -96,6 +117,10 @@ public abstract class LeakCheckedTest extends SysuiTestCase {
obj = new FakeNextAlarmController(this);
} else if (cls == NetworkController.class) {
obj = new FakeNetworkController(this);
+ } else if (cls == PluginManager.class) {
+ obj = new FakePluginManager(mContext, this);
+ } else if (cls == TunerService.class) {
+ obj = new FakeTunerService(mContext, this);
} else {
Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
}
diff --git a/preloaded-classes b/preloaded-classes
index 2fad5dd04a82..7dc5a256bb87 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,3 +1,28 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+#
+# Preloaded-classes filter file for phones.
+#
+# Classes in this file will be allocated into the boot image, and forcibly initialized in
+# the zygote during initialization. This is a trade-off, using virtual address space to share
+# common heap between apps.
+#
+# This file has been derived for mainline phone (and tablet) usage.
+#
[B
[C
[D
@@ -9,7 +34,6 @@
[Landroid.animation.Keyframe$FloatKeyframe;
[Landroid.animation.Keyframe$IntKeyframe;
[Landroid.animation.Keyframe$ObjectKeyframe;
-[Landroid.animation.Keyframe;
[Landroid.animation.PropertyValuesHolder;
[Landroid.app.LoaderManagerImpl;
[Landroid.content.ContentProviderResult;
@@ -57,45 +81,45 @@
[Landroid.hardware.soundtrigger.SoundTrigger$Keyphrase;
[Landroid.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionExtra;
[Landroid.icu.impl.CacheValue$Strength;
+[Landroid.icu.impl.CacheValue;
+[Landroid.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingPattern;
+[Landroid.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingType;
[Landroid.icu.impl.ICUResourceBundle$OpenType;
[Landroid.icu.impl.StandardPlural;
[Landroid.icu.impl.Trie2$ValueWidth;
[Landroid.icu.impl.UCharacterProperty$BinaryProperty;
[Landroid.icu.impl.UCharacterProperty$IntProperty;
-[Landroid.icu.lang.UScript$ScriptUsage;
-[Landroid.icu.text.DateFormat$BooleanAttribute;
-[Landroid.icu.text.DateFormat$Field;
+[Landroid.icu.text.DateFormatSymbols$CalendarDataSink$AliasType;
[Landroid.icu.text.DateFormatSymbols$CapitalizationContextUsage;
-[Landroid.icu.text.DateTimePatternGenerator$DTPGflags;
[Landroid.icu.text.DisplayContext$Type;
[Landroid.icu.text.DisplayContext;
-[Landroid.icu.text.MessagePattern$ApostropheMode;
-[Landroid.icu.text.MessagePattern$ArgType;
-[Landroid.icu.text.MessagePattern$Part$Type;
[Landroid.icu.text.PluralRules$Operand;
[Landroid.icu.text.PluralRules$PluralType;
[Landroid.icu.text.PluralRules$SampleType;
+[Landroid.icu.text.TimeZoneNames$NameType;
[Landroid.icu.text.UnicodeSet;
[Landroid.icu.util.BytesTrie$Result;
-[Landroid.icu.util.Calendar$CalType;
[Landroid.icu.util.Currency$CurrencyUsage;
[Landroid.icu.util.ULocale$Category;
[Landroid.icu.util.ULocale;
+[Landroid.icu.util.UResourceBundle$RootType;
[Landroid.media.AudioGain;
+[Landroid.media.MediaCodecInfo$CodecProfileLevel;
[Landroid.net.Network;
[Landroid.net.NetworkInfo$DetailedState;
[Landroid.net.NetworkInfo$State;
+[Landroid.net.NetworkRequest$Type;
[Landroid.net.Uri;
[Landroid.net.wifi.SupplicantState;
[Landroid.os.AsyncTask$Status;
-[Landroid.os.Bundle;
+[Landroid.os.IBinder;
[Landroid.os.MessageQueue$IdleHandler;
[Landroid.os.Parcel;
-[Landroid.os.ParcelFileDescriptor;
[Landroid.os.Parcelable;
[Landroid.os.PatternMatcher;
[Landroid.os.storage.StorageVolume;
[Landroid.system.StructPollfd;
+[Landroid.telephony.TelephonyManager$MultiSimVariants;
[Landroid.text.DynamicLayout$ChangeWatcher;
[Landroid.text.InputFilter;
[Landroid.text.Layout$Alignment;
@@ -124,9 +148,7 @@
[Landroid.util.Range;
[Landroid.util.Rational;
[Landroid.view.Choreographer$CallbackQueue;
-[Landroid.view.Display$ColorTransform;
[Landroid.view.Display$Mode;
-[Landroid.view.Display;
[Landroid.view.HandlerActionQueue$HandlerAction;
[Landroid.view.MenuItem;
[Landroid.view.View;
@@ -146,18 +168,22 @@
[Lcom.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
[Lcom.android.org.conscrypt.OpenSSLX509CertPath$Encoding;
[Lcom.android.org.conscrypt.OpenSSLX509Certificate;
+[Lcom.android.org.conscrypt.ct.CTLogInfo;
[Ldalvik.system.DexPathList$Element;
-[Ljava.beans.PropertyChangeListener;
+[Ldalvik.system.DexPathList$NativeLibraryElement;
[Ljava.io.File$PathStatus;
[Ljava.io.File;
[Ljava.io.FileDescriptor;
[Ljava.io.IOException;
+[Ljava.io.ObjectInputStream$HandleTable$HandleList;
[Ljava.io.ObjectStreamField;
+[Ljava.lang.Boolean;
[Ljava.lang.Byte;
[Ljava.lang.CharSequence;
[Ljava.lang.Character$UnicodeBlock;
[Ljava.lang.Character;
[Ljava.lang.Class;
+[Ljava.lang.Comparable;
[Ljava.lang.Enum;
[Ljava.lang.Integer;
[Ljava.lang.Long;
@@ -174,21 +200,20 @@
[Ljava.lang.Throwable;
[Ljava.lang.Void;
[Ljava.lang.annotation.Annotation;
-[Ljava.lang.ref.SoftReference;
+[Ljava.lang.invoke.MethodType;
[Ljava.lang.ref.WeakReference;
[Ljava.lang.reflect.AccessibleObject;
[Ljava.lang.reflect.Constructor;
[Ljava.lang.reflect.Field;
[Ljava.lang.reflect.Method;
+[Ljava.lang.reflect.Parameter;
[Ljava.lang.reflect.Type;
[Ljava.lang.reflect.TypeVariable;
-[Ljava.math.BigDecimal;
[Ljava.math.BigInteger;
[Ljava.math.RoundingMode;
[Ljava.net.InetAddress;
-[Ljava.net.InterfaceAddress;
-[Ljava.net.NetworkInterface;
[Ljava.net.Proxy$Type;
+[Ljava.nio.file.attribute.FileAttribute;
[Ljava.security.CryptoPrimitive;
[Ljava.security.Provider;
[Ljava.security.cert.Certificate;
@@ -200,30 +225,31 @@
[Ljava.util.Enumeration;
[Ljava.util.Formatter$Flags;
[Ljava.util.Formatter$FormatString;
-[Ljava.util.HashMap$HashMapEntry;
+[Ljava.util.HashMap$Node;
[Ljava.util.Hashtable$HashtableEntry;
-[Ljava.util.List;
[Ljava.util.Locale$Category;
[Ljava.util.Locale;
[Ljava.util.Map$Entry;
[Ljava.util.WeakHashMap$Entry;
+[Ljava.util.concurrent.ConcurrentHashMap$CounterCell;
[Ljava.util.concurrent.ConcurrentHashMap$Node;
[Ljava.util.concurrent.ConcurrentHashMap$Segment;
+[Ljava.util.concurrent.ForkJoinTask$ExceptionNode;
[Ljava.util.concurrent.RunnableScheduledFuture;
[Ljava.util.concurrent.TimeUnit;
[Ljava.util.logging.Handler;
[Ljava.util.regex.Pattern;
-[Ljavax.crypto.Cipher$InitType;
-[Ljavax.crypto.Cipher$NeedToSet;
[Ljavax.net.ssl.KeyManager;
[Ljavax.net.ssl.TrustManager;
[Ljavax.security.cert.X509Certificate;
[Llibcore.io.ClassPathURLStreamHandler;
+[Llibcore.io.IoTracker$Mode;
[Llibcore.reflect.AnnotationMember$DefaultValues;
[Llibcore.reflect.AnnotationMember;
[Lorg.apache.http.Header;
[Lorg.json.JSONStringer$Scope;
[Lorg.kxml2.io.KXmlParser$ValueContext;
+[Lsun.misc.FDBigInteger;
[Lsun.misc.FormattedFloatingDecimal$Form;
[Lsun.security.jca.ProviderConfig;
[Lsun.security.jca.ServiceId;
@@ -244,31 +270,22 @@
[[Ljava.lang.Object;
[[Ljava.lang.String;
[[Ljava.lang.annotation.Annotation;
-[[S
[[[I
android.R$styleable
android.accounts.Account
android.accounts.Account$1
android.accounts.AccountManager
android.accounts.AccountManager$1
-android.accounts.AccountManager$11
-android.accounts.AccountManager$AmsTask
-android.accounts.AccountManager$AmsTask$1
-android.accounts.AccountManager$AmsTask$Response
-android.accounts.AccountManagerCallback
android.accounts.AccountManagerFuture
android.accounts.AccountsException
android.accounts.AuthenticatorException
android.accounts.IAccountManager
android.accounts.IAccountManager$Stub
android.accounts.IAccountManager$Stub$Proxy
-android.accounts.IAccountManagerResponse
-android.accounts.IAccountManagerResponse$Stub
android.accounts.OnAccountsUpdateListener
android.accounts.OperationCanceledException
android.animation.AnimationHandler
android.animation.AnimationHandler$1
-android.animation.AnimationHandler$2
android.animation.AnimationHandler$AnimationFrameCallback
android.animation.AnimationHandler$AnimationFrameCallbackProvider
android.animation.AnimationHandler$MyFrameCallbackProvider
@@ -277,12 +294,15 @@ android.animation.Animator$AnimatorConstantState
android.animation.Animator$AnimatorListener
android.animation.Animator$AnimatorPauseListener
android.animation.AnimatorInflater
-android.animation.AnimatorInflater$PathDataEvaluator
android.animation.AnimatorListenerAdapter
android.animation.AnimatorSet
-android.animation.AnimatorSet$AnimatorSetListener
+android.animation.AnimatorSet$1
+android.animation.AnimatorSet$2
+android.animation.AnimatorSet$3
+android.animation.AnimatorSet$AnimationEvent
android.animation.AnimatorSet$Builder
android.animation.AnimatorSet$Node
+android.animation.AnimatorSet$SeekState
android.animation.ArgbEvaluator
android.animation.FloatEvaluator
android.animation.FloatKeyframeSet
@@ -299,14 +319,13 @@ android.animation.Keyframes$IntKeyframes
android.animation.LayoutTransition
android.animation.LayoutTransition$TransitionListener
android.animation.ObjectAnimator
-android.animation.PathKeyframes
-android.animation.PathKeyframes$1
-android.animation.PathKeyframes$2
android.animation.PathKeyframes$FloatKeyframesBase
+android.animation.PathKeyframes$IntKeyframesBase
android.animation.PathKeyframes$SimpleKeyframes
android.animation.PropertyValuesHolder
android.animation.PropertyValuesHolder$FloatPropertyValuesHolder
android.animation.PropertyValuesHolder$IntPropertyValuesHolder
+android.animation.PropertyValuesHolder$PropertyValues
android.animation.RectEvaluator
android.animation.StateListAnimator
android.animation.StateListAnimator$1
@@ -316,12 +335,15 @@ android.animation.TimeInterpolator
android.animation.TypeEvaluator
android.animation.ValueAnimator
android.animation.ValueAnimator$AnimatorUpdateListener
+android.app.-$Lambda$36$c44uHH2WE4sJvw5tZZB6gRzEaHI
+android.app.-$Lambda$39$c44uHH2WE4sJvw5tZZB6gRzEaHI
+android.app.-$Lambda$7$u_rp3dnwvfyMTggc6hVftcuYJ3E
android.app.ActionBar
android.app.ActionBar$LayoutParams
android.app.Activity
android.app.Activity$HostCallbacks
android.app.ActivityManager
-android.app.ActivityManager$MemoryInfo
+android.app.ActivityManager$1
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
android.app.ActivityManager$StackId
@@ -357,20 +379,17 @@ android.app.AppGlobals
android.app.AppOpsManager
android.app.Application
android.app.Application$ActivityLifecycleCallbacks
-android.app.ApplicationErrorReport
android.app.ApplicationErrorReport$CrashInfo
android.app.ApplicationLoaders
android.app.ApplicationPackageManager
android.app.ApplicationPackageManager$ResourceName
android.app.BackStackRecord
android.app.BackStackRecord$Op
-android.app.BackStackRecord$TransitionState
android.app.ContentProviderHolder
android.app.ContentProviderHolder$1
android.app.ContextImpl
android.app.ContextImpl$ApplicationContentResolver
android.app.Dialog
-android.app.Dialog$-void__init__android_content_Context_context_int_themeResId_boolean_createContextThemeWrapper_LambdaImpl0
android.app.Dialog$ListenersHandler
android.app.DialogFragment
android.app.DownloadManager
@@ -383,7 +402,10 @@ android.app.FragmentManager
android.app.FragmentManager$BackStackEntry
android.app.FragmentManagerImpl
android.app.FragmentManagerImpl$1
+android.app.FragmentManagerImpl$OpGenerator
android.app.FragmentTransaction
+android.app.FragmentTransition
+android.app.FragmentTransition$FragmentContainerTransition
android.app.IActivityManager
android.app.IActivityManager$Stub
android.app.IActivityManager$Stub$Proxy
@@ -392,7 +414,6 @@ android.app.IAlarmManager$Stub
android.app.IAlarmManager$Stub$Proxy
android.app.IApplicationThread
android.app.IApplicationThread$Stub
-android.app.IApplicationThread$Stub$Proxy
android.app.IInstrumentationWatcher
android.app.IInstrumentationWatcher$Stub
android.app.INotificationManager
@@ -409,10 +430,10 @@ android.app.Instrumentation
android.app.IntentReceiverLeaked
android.app.IntentService
android.app.IntentService$ServiceHandler
-android.app.JobSchedulerImpl
android.app.KeyguardManager
android.app.ListActivity
android.app.LoadedApk
+android.app.LoadedApk$DexLoadReporter
android.app.LoadedApk$ReceiverDispatcher
android.app.LoadedApk$ReceiverDispatcher$Args
android.app.LoadedApk$ReceiverDispatcher$InnerReceiver
@@ -426,19 +447,17 @@ android.app.LoaderManager
android.app.LoaderManagerImpl
android.app.NativeActivity
android.app.Notification
-android.app.Notification$1
android.app.Notification$Action
android.app.Notification$BigTextStyle
android.app.Notification$Builder
-android.app.Notification$BuilderRemoteViews
android.app.Notification$Style
android.app.NotificationManager
-android.app.OnActivityPausedListener
android.app.PendingIntent
android.app.PendingIntent$1
android.app.PendingIntent$CanceledException
-android.app.ProgressDialog
+android.app.PendingIntent$OnMarshaledListener
android.app.QueuedWork
+android.app.QueuedWork$QueuedWorkHandler
android.app.ReceiverRestrictedContext
android.app.ResourcesManager
android.app.ResourcesManager$1
@@ -530,6 +549,11 @@ android.app.SystemServiceRegistry$71
android.app.SystemServiceRegistry$72
android.app.SystemServiceRegistry$73
android.app.SystemServiceRegistry$74
+android.app.SystemServiceRegistry$75
+android.app.SystemServiceRegistry$76
+android.app.SystemServiceRegistry$77
+android.app.SystemServiceRegistry$78
+android.app.SystemServiceRegistry$79
android.app.SystemServiceRegistry$8
android.app.SystemServiceRegistry$9
android.app.SystemServiceRegistry$CachedServiceFetcher
@@ -550,13 +574,11 @@ android.app.backup.BackupDataInput$EntityHeader
android.app.backup.BackupDataOutput
android.app.backup.BackupHelperDispatcher
android.app.backup.BackupHelperDispatcher$Header
+android.app.backup.BackupManager
android.app.backup.FileBackupHelperBase
android.app.backup.FullBackup
android.app.backup.FullBackupDataOutput
-android.app.job.IJobScheduler
-android.app.job.IJobScheduler$Stub
android.app.job.JobInfo
-android.app.job.JobInfo$Builder
android.app.job.JobScheduler
android.app.job.JobService
android.app.trust.ITrustManager
@@ -564,14 +586,15 @@ android.app.trust.ITrustManager$Stub
android.app.trust.ITrustManager$Stub$Proxy
android.app.trust.TrustManager
android.app.usage.NetworkStatsManager
+android.app.usage.StorageStatsManager
android.app.usage.UsageStatsManager
android.appwidget.AppWidgetManager
-android.appwidget.AppWidgetProvider
android.bluetooth.BluetoothAdapter
android.bluetooth.BluetoothAdapter$1
android.bluetooth.BluetoothManager
android.bluetooth.IBluetooth
android.bluetooth.IBluetooth$Stub
+android.bluetooth.IBluetooth$Stub$Proxy
android.bluetooth.IBluetoothManager
android.bluetooth.IBluetoothManager$Stub
android.bluetooth.IBluetoothManager$Stub$Proxy
@@ -582,8 +605,6 @@ android.content.BroadcastReceiver
android.content.BroadcastReceiver$PendingResult
android.content.BroadcastReceiver$PendingResult$1
android.content.ClipData
-android.content.ClipData$Item
-android.content.ClipDescription
android.content.ClipboardManager
android.content.ComponentCallbacks
android.content.ComponentCallbacks2
@@ -594,7 +615,6 @@ android.content.ContentProvider$Transport
android.content.ContentProviderClient
android.content.ContentProviderNative
android.content.ContentProviderOperation
-android.content.ContentProviderOperation$Builder
android.content.ContentProviderProxy
android.content.ContentProviderResult
android.content.ContentResolver
@@ -618,10 +638,6 @@ android.content.IIntentReceiver$Stub
android.content.IIntentSender
android.content.IIntentSender$Stub
android.content.IIntentSender$Stub$Proxy
-android.content.ISyncAdapter
-android.content.ISyncAdapter$Stub
-android.content.ISyncContext
-android.content.ISyncContext$Stub
android.content.Intent
android.content.Intent$1
android.content.IntentFilter
@@ -635,13 +651,7 @@ android.content.ServiceConnection
android.content.SharedPreferences
android.content.SharedPreferences$Editor
android.content.SharedPreferences$OnSharedPreferenceChangeListener
-android.content.SyncResult
-android.content.SyncResult$1
-android.content.SyncStats
-android.content.SyncStats$1
android.content.UndoManager
-android.content.UndoManager$UndoState
-android.content.UndoOperation
android.content.UndoOwner
android.content.UriMatcher
android.content.pm.ActivityInfo
@@ -714,7 +724,6 @@ android.content.res.ResourcesImpl
android.content.res.ResourcesImpl$ThemeImpl
android.content.res.ResourcesKey
android.content.res.StringBlock
-android.content.res.StringBlock$StyleIDs
android.content.res.ThemedResourceCache
android.content.res.TypedArray
android.content.res.XmlBlock
@@ -752,7 +761,6 @@ android.database.IContentObserver
android.database.IContentObserver$Stub
android.database.IContentObserver$Stub$Proxy
android.database.MatrixCursor
-android.database.MatrixCursor$RowBuilder
android.database.Observable
android.database.SQLException
android.database.sqlite.DatabaseObjectNotClosedException
@@ -796,6 +804,7 @@ android.ddm.DdmHandleProfiling
android.ddm.DdmHandleThread
android.ddm.DdmHandleViewDebug
android.ddm.DdmRegister
+android.graphics.BaseCanvas
android.graphics.Bitmap
android.graphics.Bitmap$1
android.graphics.Bitmap$CompressFormat
@@ -812,7 +821,6 @@ android.graphics.Canvas$NoImagePreloadHolder
android.graphics.CanvasProperty
android.graphics.Color
android.graphics.ColorFilter
-android.graphics.ColorMatrix
android.graphics.ColorMatrixColorFilter
android.graphics.ComposePathEffect
android.graphics.ComposeShader
@@ -823,15 +831,17 @@ android.graphics.DrawFilter
android.graphics.EmbossMaskFilter
android.graphics.FontFamily
android.graphics.FontListParser
+android.graphics.GraphicBuffer
+android.graphics.GraphicBuffer$1
android.graphics.Insets
android.graphics.Interpolator
android.graphics.Interpolator$Result
-android.graphics.LayerRasterizer
android.graphics.LightingColorFilter
android.graphics.LinearGradient
android.graphics.MaskFilter
android.graphics.Matrix
android.graphics.Matrix$1
+android.graphics.Matrix$NoImagePreloadHolder
android.graphics.Matrix$ScaleToFit
android.graphics.Movie
android.graphics.NinePatch
@@ -863,7 +873,6 @@ android.graphics.PorterDuff$Mode
android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
android.graphics.RadialGradient
-android.graphics.Rasterizer
android.graphics.Rect
android.graphics.Rect$1
android.graphics.RectF
@@ -876,7 +885,6 @@ android.graphics.Shader
android.graphics.Shader$TileMode
android.graphics.SumPathEffect
android.graphics.SurfaceTexture
-android.graphics.SurfaceTexture$OnFrameAvailableListener
android.graphics.SweepGradient
android.graphics.TableMaskFilter
android.graphics.TemporaryBuffer
@@ -893,7 +901,6 @@ android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT
-android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI
android.graphics.drawable.AnimationDrawable
android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
@@ -904,6 +911,7 @@ android.graphics.drawable.Drawable
android.graphics.drawable.Drawable$Callback
android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
+android.graphics.drawable.DrawableContainer$BlockInvalidateCallback
android.graphics.drawable.DrawableContainer$DrawableContainerState
android.graphics.drawable.DrawableInflater
android.graphics.drawable.DrawableWrapper
@@ -943,11 +951,30 @@ android.graphics.drawable.TransitionDrawable
android.graphics.drawable.VectorDrawable
android.graphics.drawable.VectorDrawable$VFullPath
android.graphics.drawable.VectorDrawable$VFullPath$1
+android.graphics.drawable.VectorDrawable$VFullPath$10
+android.graphics.drawable.VectorDrawable$VFullPath$2
+android.graphics.drawable.VectorDrawable$VFullPath$3
+android.graphics.drawable.VectorDrawable$VFullPath$4
+android.graphics.drawable.VectorDrawable$VFullPath$5
+android.graphics.drawable.VectorDrawable$VFullPath$6
+android.graphics.drawable.VectorDrawable$VFullPath$7
+android.graphics.drawable.VectorDrawable$VFullPath$8
+android.graphics.drawable.VectorDrawable$VFullPath$9
android.graphics.drawable.VectorDrawable$VGroup
android.graphics.drawable.VectorDrawable$VGroup$1
+android.graphics.drawable.VectorDrawable$VGroup$2
+android.graphics.drawable.VectorDrawable$VGroup$3
+android.graphics.drawable.VectorDrawable$VGroup$4
+android.graphics.drawable.VectorDrawable$VGroup$5
+android.graphics.drawable.VectorDrawable$VGroup$6
+android.graphics.drawable.VectorDrawable$VGroup$7
+android.graphics.drawable.VectorDrawable$VGroup$8
+android.graphics.drawable.VectorDrawable$VGroup$9
android.graphics.drawable.VectorDrawable$VObject
android.graphics.drawable.VectorDrawable$VPath
+android.graphics.drawable.VectorDrawable$VPath$1
android.graphics.drawable.VectorDrawable$VectorDrawableState
+android.graphics.drawable.VectorDrawable$VectorDrawableState$1
android.graphics.drawable.shapes.OvalShape
android.graphics.drawable.shapes.RectShape
android.graphics.drawable.shapes.Shape
@@ -958,6 +985,8 @@ android.hardware.Camera
android.hardware.Camera$CameraInfo
android.hardware.Camera$Face
android.hardware.ConsumerIrManager
+android.hardware.HardwareBuffer
+android.hardware.HardwareBuffer$1
android.hardware.Sensor
android.hardware.SensorEvent
android.hardware.SensorEventListener
@@ -966,7 +995,6 @@ android.hardware.SerialManager
android.hardware.SerialPort
android.hardware.SystemSensorManager
android.hardware.SystemSensorManager$BaseEventQueue
-android.hardware.SystemSensorManager$SensorEventQueue
android.hardware.camera2.CameraCharacteristics$Key
android.hardware.camera2.CameraManager
android.hardware.camera2.CaptureRequest$Key
@@ -996,9 +1024,10 @@ android.hardware.input.InputDeviceIdentifier
android.hardware.input.InputDeviceIdentifier$1
android.hardware.input.InputManager
android.hardware.input.InputManager$InputDevicesChangedListener
+android.hardware.location.ActivityRecognitionHardware
android.hardware.location.ContextHubManager
-android.hardware.location.IContextHubService
-android.hardware.location.IContextHubService$Stub
+android.hardware.location.IActivityRecognitionHardware
+android.hardware.location.IActivityRecognitionHardware$Stub
android.hardware.radio.RadioManager
android.hardware.radio.RadioManager$AmBandConfig
android.hardware.radio.RadioManager$AmBandConfig$1
@@ -1044,8 +1073,6 @@ android.hardware.soundtrigger.SoundTrigger$SoundModel
android.hardware.soundtrigger.SoundTrigger$SoundModelEvent
android.hardware.soundtrigger.SoundTrigger$SoundModelEvent$1
android.hardware.soundtrigger.SoundTriggerModule
-android.hardware.usb.IUsbManager
-android.hardware.usb.IUsbManager$Stub
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
android.hardware.usb.UsbManager
@@ -1056,16 +1083,16 @@ android.icu.impl.CacheValue
android.icu.impl.CacheValue$NullValue
android.icu.impl.CacheValue$SoftValue
android.icu.impl.CacheValue$Strength
-android.icu.impl.CalendarData
android.icu.impl.CalendarUtil
+android.icu.impl.CalendarUtil$CalendarPreferences
android.icu.impl.CharTrie
android.icu.impl.ClassLoaderUtil
android.icu.impl.CurrencyData
android.icu.impl.CurrencyData$CurrencyDisplayInfo
android.icu.impl.CurrencyData$CurrencyDisplayInfoProvider
android.icu.impl.CurrencyData$CurrencySpacingInfo
-android.icu.impl.DateNumberFormat
-android.icu.impl.Grego
+android.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingPattern
+android.icu.impl.CurrencyData$CurrencySpacingInfo$SpacingType
android.icu.impl.ICUBinary
android.icu.impl.ICUBinary$Authenticate
android.icu.impl.ICUBinary$DatPackageReader
@@ -1076,6 +1103,7 @@ android.icu.impl.ICUCache
android.icu.impl.ICUConfig
android.icu.impl.ICUCurrencyDisplayInfoProvider
android.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo
+android.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo$SpacingInfoSink
android.icu.impl.ICUCurrencyMetaInfo
android.icu.impl.ICUCurrencyMetaInfo$Collector
android.icu.impl.ICUCurrencyMetaInfo$CurrencyCollector
@@ -1091,13 +1119,15 @@ android.icu.impl.ICURWLock
android.icu.impl.ICUResourceBundle
android.icu.impl.ICUResourceBundle$1
android.icu.impl.ICUResourceBundle$2
-android.icu.impl.ICUResourceBundle$2$1
+android.icu.impl.ICUResourceBundle$3
+android.icu.impl.ICUResourceBundle$3$1
+android.icu.impl.ICUResourceBundle$4
android.icu.impl.ICUResourceBundle$AvailEntry
+android.icu.impl.ICUResourceBundle$Loader
android.icu.impl.ICUResourceBundle$OpenType
android.icu.impl.ICUResourceBundle$WholeBundle
android.icu.impl.ICUResourceBundleImpl
android.icu.impl.ICUResourceBundleImpl$ResourceArray
-android.icu.impl.ICUResourceBundleImpl$ResourceBinary
android.icu.impl.ICUResourceBundleImpl$ResourceContainer
android.icu.impl.ICUResourceBundleImpl$ResourceInt
android.icu.impl.ICUResourceBundleImpl$ResourceIntVector
@@ -1111,6 +1141,7 @@ android.icu.impl.ICUResourceBundleReader$Container
android.icu.impl.ICUResourceBundleReader$IsAcceptable
android.icu.impl.ICUResourceBundleReader$ReaderCache
android.icu.impl.ICUResourceBundleReader$ReaderCacheKey
+android.icu.impl.ICUResourceBundleReader$ReaderValue
android.icu.impl.ICUResourceBundleReader$ResourceCache
android.icu.impl.ICUResourceBundleReader$ResourceCache$Level
android.icu.impl.ICUResourceBundleReader$Table
@@ -1121,7 +1152,6 @@ android.icu.impl.ICUService$CacheEntry
android.icu.impl.ICUService$Factory
android.icu.impl.ICUService$Key
android.icu.impl.IDNA2003
-android.icu.impl.JavaTimeZone
android.icu.impl.LocaleIDParser
android.icu.impl.LocaleIDs
android.icu.impl.Norm2AllModes
@@ -1129,7 +1159,6 @@ android.icu.impl.Norm2AllModes$1
android.icu.impl.Norm2AllModes$ComposeNormalizer2
android.icu.impl.Norm2AllModes$DecomposeNormalizer2
android.icu.impl.Norm2AllModes$FCDNormalizer2
-android.icu.impl.Norm2AllModes$NFCSingleton
android.icu.impl.Norm2AllModes$NFKCSingleton
android.icu.impl.Norm2AllModes$NoopNormalizer2
android.icu.impl.Norm2AllModes$Norm2AllModesSingleton
@@ -1137,14 +1166,13 @@ android.icu.impl.Norm2AllModes$Normalizer2WithImpl
android.icu.impl.Normalizer2Impl
android.icu.impl.Normalizer2Impl$1
android.icu.impl.Normalizer2Impl$IsAcceptable
-android.icu.impl.OlsonTimeZone
android.icu.impl.Pair
android.icu.impl.PatternProps
-android.icu.impl.PatternTokenizer
android.icu.impl.PluralRulesLoader
android.icu.impl.ReplaceableUCharacterIterator
android.icu.impl.RuleCharacterIterator
android.icu.impl.SimpleCache
+android.icu.impl.SimpleFormatterImpl
android.icu.impl.SoftCache
android.icu.impl.StandardPlural
android.icu.impl.StringPrepDataReader
@@ -1159,7 +1187,6 @@ android.icu.impl.Trie2$UTrie2Header
android.icu.impl.Trie2$ValueMapper
android.icu.impl.Trie2$ValueWidth
android.icu.impl.Trie2_16
-android.icu.impl.Trie2_32
android.icu.impl.UBiDiProps
android.icu.impl.UBiDiProps$IsAcceptable
android.icu.impl.UCharacterProperty
@@ -1194,24 +1221,13 @@ android.icu.impl.UCharacterProperty$IntProperty
android.icu.impl.UCharacterProperty$IsAcceptable
android.icu.impl.UCharacterProperty$NormInertBinaryProperty
android.icu.impl.UCharacterProperty$NormQuickCheckIntProperty
-android.icu.impl.UPropertyAliases
-android.icu.impl.UPropertyAliases$IsAcceptable
android.icu.impl.URLHandler$URLVisitor
-android.icu.impl.USerializedSet
+android.icu.impl.UResource$Array
+android.icu.impl.UResource$Key
+android.icu.impl.UResource$Sink
+android.icu.impl.UResource$Table
+android.icu.impl.UResource$Value
android.icu.impl.Utility
-android.icu.impl.ZoneMeta
-android.icu.impl.ZoneMeta$CustomTimeZoneCache
-android.icu.impl.ZoneMeta$SystemTimeZoneCache
-android.icu.impl.coll.CollationData
-android.icu.impl.coll.CollationDataReader
-android.icu.impl.coll.CollationDataReader$IsAcceptable
-android.icu.impl.coll.CollationFastLatin
-android.icu.impl.coll.CollationLoader
-android.icu.impl.coll.CollationRoot
-android.icu.impl.coll.CollationSettings
-android.icu.impl.coll.CollationTailoring
-android.icu.impl.coll.SharedObject
-android.icu.impl.coll.SharedObject$Reference
android.icu.impl.locale.AsciiUtil
android.icu.impl.locale.BaseLocale
android.icu.impl.locale.BaseLocale$Cache
@@ -1222,8 +1238,6 @@ android.icu.impl.locale.LocaleSyntaxException
android.icu.lang.UCharacter
android.icu.lang.UCharacterEnums$ECharacterCategory
android.icu.lang.UCharacterEnums$ECharacterDirection
-android.icu.lang.UScript
-android.icu.lang.UScript$ScriptUsage
android.icu.math.BigDecimal
android.icu.math.MathContext
android.icu.text.BreakIterator
@@ -1232,51 +1246,26 @@ android.icu.text.BreakIterator$BreakIteratorServiceShim
android.icu.text.BreakIteratorFactory
android.icu.text.BreakIteratorFactory$BFService
android.icu.text.BreakIteratorFactory$BFService$1RBBreakIteratorFactory
-android.icu.text.Collator
-android.icu.text.Collator$ServiceShim
-android.icu.text.CollatorServiceShim
-android.icu.text.CollatorServiceShim$CService
-android.icu.text.CollatorServiceShim$CService$1CollatorFactory
android.icu.text.CurrencyDisplayNames
android.icu.text.CurrencyMetaInfo
android.icu.text.CurrencyMetaInfo$CurrencyDigits
android.icu.text.CurrencyMetaInfo$CurrencyFilter
-android.icu.text.DateFormat
-android.icu.text.DateFormat$BooleanAttribute
-android.icu.text.DateFormat$Field
android.icu.text.DateFormatSymbols
+android.icu.text.DateFormatSymbols$1
+android.icu.text.DateFormatSymbols$CalendarDataSink
+android.icu.text.DateFormatSymbols$CalendarDataSink$AliasType
android.icu.text.DateFormatSymbols$CapitalizationContextUsage
-android.icu.text.DateIntervalFormat
-android.icu.text.DateIntervalFormat$BestMatchInfo
-android.icu.text.DateIntervalInfo
-android.icu.text.DateIntervalInfo$PatternInfo
-android.icu.text.DateTimePatternGenerator
-android.icu.text.DateTimePatternGenerator$DTPGflags
-android.icu.text.DateTimePatternGenerator$DateTimeMatcher
-android.icu.text.DateTimePatternGenerator$DistanceInfo
-android.icu.text.DateTimePatternGenerator$FormatParser
-android.icu.text.DateTimePatternGenerator$PatternInfo
-android.icu.text.DateTimePatternGenerator$PatternWithMatcher
-android.icu.text.DateTimePatternGenerator$PatternWithSkeletonFlag
-android.icu.text.DateTimePatternGenerator$VariableField
android.icu.text.DecimalFormat
android.icu.text.DecimalFormat$Unit
android.icu.text.DecimalFormatSymbols
android.icu.text.DecimalFormatSymbols$1
android.icu.text.DecimalFormatSymbols$CacheData
+android.icu.text.DecimalFormatSymbols$DecFmtDataSink
android.icu.text.DigitList
android.icu.text.DisplayContext
android.icu.text.DisplayContext$Type
android.icu.text.IDNA
android.icu.text.LanguageBreakEngine
-android.icu.text.MessageFormat
-android.icu.text.MessageFormat$AppendableWrapper
-android.icu.text.MessageFormat$Field
-android.icu.text.MessagePattern
-android.icu.text.MessagePattern$ApostropheMode
-android.icu.text.MessagePattern$ArgType
-android.icu.text.MessagePattern$Part
-android.icu.text.MessagePattern$Part$Type
android.icu.text.Normalizer
android.icu.text.Normalizer$FCDMode
android.icu.text.Normalizer$Mode
@@ -1292,6 +1281,9 @@ android.icu.text.Normalizer2
android.icu.text.NumberFormat
android.icu.text.NumberFormat$Field
android.icu.text.NumberingSystem
+android.icu.text.NumberingSystem$1
+android.icu.text.NumberingSystem$2
+android.icu.text.NumberingSystem$LocaleLookupData
android.icu.text.PluralRanges
android.icu.text.PluralRanges$Matrix
android.icu.text.PluralRules
@@ -1317,11 +1309,10 @@ android.icu.text.RBBIDataWrapper$TrieFoldingFunc
android.icu.text.Replaceable
android.icu.text.ReplaceableString
android.icu.text.RuleBasedBreakIterator
-android.icu.text.RuleBasedCollator
-android.icu.text.SimpleDateFormat
-android.icu.text.SimpleDateFormat$PatternItem
+android.icu.text.RuleBasedBreakIterator$LookAheadResults
android.icu.text.StringPrep
android.icu.text.StringPrepParseException
+android.icu.text.TimeZoneNames$NameType
android.icu.text.UCharacterIterator
android.icu.text.UFieldPosition
android.icu.text.UFormat
@@ -1331,48 +1322,36 @@ android.icu.text.UnhandledBreakEngine
android.icu.text.UnicodeFilter
android.icu.text.UnicodeMatcher
android.icu.text.UnicodeSet
-android.icu.text.UnicodeSet$Filter
-android.icu.text.UnicodeSet$GeneralCategoryMaskFilter
-android.icu.text.UnicodeSet$IntPropertyFilter
-android.icu.util.BasicTimeZone
-android.icu.util.BytesTrie
android.icu.util.BytesTrie$Result
-android.icu.util.Calendar
-android.icu.util.Calendar$CalType
-android.icu.util.Calendar$FormatConfiguration
-android.icu.util.Calendar$PatternData
-android.icu.util.Calendar$WeekData
-android.icu.util.Calendar$WeekDataCache
android.icu.util.Currency
+android.icu.util.Currency$1
android.icu.util.Currency$CurrencyUsage
android.icu.util.Currency$EquivalenceRelation
android.icu.util.Freezable
-android.icu.util.GregorianCalendar
android.icu.util.MeasureUnit
android.icu.util.MeasureUnit$1
android.icu.util.MeasureUnit$2
android.icu.util.MeasureUnit$3
android.icu.util.MeasureUnit$Factory
-android.icu.util.Output
-android.icu.util.SimpleTimeZone
android.icu.util.TimeUnit
android.icu.util.TimeZone
android.icu.util.TimeZone$ConstantZone
android.icu.util.ULocale
+android.icu.util.ULocale$1
+android.icu.util.ULocale$2
android.icu.util.ULocale$Category
android.icu.util.ULocale$JDKLocaleHelper
android.icu.util.ULocale$Type
android.icu.util.UResourceBundle
-android.icu.util.UResourceBundle$ResourceCacheKey
+android.icu.util.UResourceBundle$RootType
android.icu.util.UResourceBundleIterator
android.icu.util.UResourceTypeMismatchException
android.icu.util.VersionInfo
android.location.CountryDetector
-android.location.ILocationManager
-android.location.ILocationManager$Stub
android.location.Location
+android.location.Location$1
+android.location.Location$2
android.location.LocationManager
-android.media.AmrInputStream
android.media.AudioAttributes
android.media.AudioAttributes$1
android.media.AudioAttributes$Builder
@@ -1386,7 +1365,7 @@ android.media.AudioHandle
android.media.AudioManager
android.media.AudioManager$1
android.media.AudioManager$2
-android.media.AudioManager$OnAudioFocusChangeListener
+android.media.AudioManager$3
android.media.AudioManager$ServiceEventHandlerDelegate
android.media.AudioManager$ServiceEventHandlerDelegate$1
android.media.AudioMixPort
@@ -1404,7 +1383,6 @@ android.media.CamcorderProfile
android.media.CameraProfile
android.media.DecoderCapabilities
android.media.EncoderCapabilities
-android.media.ExifInterface
android.media.IAudioFocusDispatcher
android.media.IAudioFocusDispatcher$Stub
android.media.IAudioService
@@ -1412,6 +1390,10 @@ android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
android.media.IMediaHTTPConnection
android.media.IMediaHTTPConnection$Stub
+android.media.IPlaybackConfigDispatcher
+android.media.IPlaybackConfigDispatcher$Stub
+android.media.IPlayer
+android.media.IPlayer$Stub
android.media.IRecordingConfigDispatcher
android.media.IRecordingConfigDispatcher$Stub
android.media.Image
@@ -1422,6 +1404,8 @@ android.media.ImageWriter$WriterSurfaceImage
android.media.JetPlayer
android.media.MediaCodec
android.media.MediaCodecInfo
+android.media.MediaCodecInfo$CodecCapabilities
+android.media.MediaCodecInfo$CodecProfileLevel
android.media.MediaCodecList
android.media.MediaCrypto
android.media.MediaDrm
@@ -1432,21 +1416,17 @@ android.media.MediaMetadataRetriever
android.media.MediaMuxer
android.media.MediaPlayer
android.media.MediaPlayer$OnCompletionListener
-android.media.MediaPlayer$OnErrorListener
-android.media.MediaPlayer$OnPreparedListener
-android.media.MediaPlayer$OnSeekCompleteListener
-android.media.MediaPlayer$OnVideoSizeChangedListener
android.media.MediaRecorder
android.media.MediaRouter
-android.media.MediaRouter$Callback
-android.media.MediaRouter$RouteCategory
-android.media.MediaRouter$RouteInfo
android.media.MediaScanner
android.media.MediaSync
android.media.PlaybackParams
android.media.PlaybackParams$1
android.media.PlayerBase
android.media.PlayerBase$1
+android.media.PlayerBase$2
+android.media.PlayerBase$PlayerIdCard
+android.media.PlayerBase$PlayerIdCard$1
android.media.RemoteDisplay
android.media.ResampleInputStream
android.media.SubtitleController$Listener
@@ -1456,12 +1436,10 @@ android.media.audiopolicy.AudioMixingRule
android.media.audiopolicy.AudioMixingRule$AudioMixMatchCriterion
android.media.midi.MidiManager
android.media.projection.MediaProjectionManager
-android.media.session.MediaController
-android.media.session.MediaController$TransportControls
-android.media.session.MediaSession$Token
android.media.session.MediaSessionManager
android.media.soundtrigger.SoundTriggerManager
android.media.tv.TvInputManager
+android.metrics.LogMaker
android.mtp.MtpDatabase
android.mtp.MtpDevice
android.mtp.MtpDeviceInfo
@@ -1476,6 +1454,8 @@ android.net.ConnectivityManager
android.net.ConnectivityManager$CallbackHandler
android.net.ConnectivityManager$NetworkCallback
android.net.ConnectivityThread
+# Must not be initialized, creates a thread.
+# android.net.ConnectivityThread$Singleton
android.net.Credentials
android.net.EthernetManager
android.net.IConnectivityManager
@@ -1504,6 +1484,7 @@ android.net.NetworkPolicyManager
android.net.NetworkRequest
android.net.NetworkRequest$1
android.net.NetworkRequest$Builder
+android.net.NetworkRequest$Type
android.net.NetworkScoreManager
android.net.NetworkStats
android.net.NetworkStats$1
@@ -1512,9 +1493,6 @@ android.net.Proxy
android.net.ProxyInfo
android.net.RouteInfo
android.net.RouteInfo$1
-android.net.SSLCertificateSocketFactory
-android.net.SSLCertificateSocketFactory$1
-android.net.SSLSessionCache
android.net.TrafficStats
android.net.Uri
android.net.Uri$1
@@ -1539,29 +1517,13 @@ android.net.wifi.SupplicantState$1
android.net.wifi.WifiInfo
android.net.wifi.WifiInfo$1
android.net.wifi.WifiManager
-android.net.wifi.WifiManager$WifiLock
android.net.wifi.WifiScanner
android.net.wifi.WifiSsid
android.net.wifi.WifiSsid$1
-android.net.wifi.nan.WifiNanManager
+android.net.wifi.aware.WifiAwareManager
android.net.wifi.p2p.WifiP2pManager
-android.nfc.IAppCallback
-android.nfc.IAppCallback$Stub
android.nfc.INfcAdapter
android.nfc.INfcAdapter$Stub
-android.nfc.INfcAdapter$Stub$Proxy
-android.nfc.INfcCardEmulation
-android.nfc.INfcCardEmulation$Stub
-android.nfc.INfcCardEmulation$Stub$Proxy
-android.nfc.INfcFCardEmulation
-android.nfc.INfcFCardEmulation$Stub
-android.nfc.INfcFCardEmulation$Stub$Proxy
-android.nfc.INfcTag
-android.nfc.INfcTag$Stub
-android.nfc.INfcTag$Stub$Proxy
-android.nfc.NfcActivityManager
-android.nfc.NfcAdapter
-android.nfc.NfcAdapter$1
android.nfc.NfcManager
android.opengl.EGL14
android.opengl.EGLConfig
@@ -1583,6 +1545,7 @@ android.opengl.GLES32
android.opengl.GLUtils
android.opengl.Matrix
android.opengl.Visibility
+android.os.-$Lambda$5$6x30vPJhBKUfNY8tswxuZo3DCe0
android.os.AsyncTask$1
android.os.AsyncTask$2
android.os.AsyncTask$3
@@ -1614,17 +1577,24 @@ android.os.Debug$MemoryInfo$1
android.os.DropBoxManager
android.os.Environment
android.os.Environment$UserEnvironment
+android.os.FactoryTest
android.os.FileObserver$ObserverThread
android.os.FileUtils
+android.os.GraphicsEnvironment
android.os.Handler
android.os.Handler$Callback
android.os.Handler$MessengerImpl
android.os.HandlerThread
android.os.HardwarePropertiesManager
+android.os.HwBinder
+android.os.HwBlob
+android.os.HwParcel
+android.os.HwRemoteBinder
android.os.IBinder
android.os.IBinder$DeathRecipient
android.os.ICancellationSignal
android.os.ICancellationSignal$Stub
+android.os.IHwBinder
android.os.IInterface
android.os.IMessenger
android.os.IMessenger$Stub
@@ -1641,7 +1611,7 @@ android.os.IUserManager$Stub
android.os.IUserManager$Stub$Proxy
android.os.IVibratorService
android.os.IVibratorService$Stub
-android.os.IVibratorService$Stub$Proxy
+android.os.IncidentManager
android.os.LocaleList
android.os.LocaleList$1
android.os.Looper
@@ -1658,7 +1628,6 @@ android.os.Parcel$1
android.os.ParcelFileDescriptor
android.os.ParcelFileDescriptor$1
android.os.ParcelFileDescriptor$AutoCloseInputStream
-android.os.ParcelFileDescriptor$AutoCloseOutputStream
android.os.Parcelable
android.os.Parcelable$ClassLoaderCreator
android.os.Parcelable$Creator
@@ -1677,8 +1646,11 @@ android.os.RemoteException
android.os.ResultReceiver
android.os.SELinux
android.os.ServiceManager
+android.os.ServiceManager$ServiceNotFoundException
android.os.ServiceManagerNative
android.os.ServiceManagerProxy
+android.os.ServiceSpecificException
+android.os.ShellCallback
android.os.StatFs
android.os.StrictMode
android.os.StrictMode$1
@@ -1704,6 +1676,7 @@ android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
android.os.StrictMode$ViolationInfo
+android.os.StrictMode$ViolationInfo$1
android.os.StrictMode$VmPolicy
android.os.StrictMode$VmPolicy$Builder
android.os.SystemClock
@@ -1716,6 +1689,7 @@ android.os.UserHandle
android.os.UserHandle$1
android.os.UserManager
android.os.Vibrator
+android.os.ZygoteProcess
android.os.ZygoteStartFailedEx
android.os.health.SystemHealthManager
android.os.storage.IStorageManager
@@ -1724,17 +1698,16 @@ android.os.storage.IStorageManager$Stub$Proxy
android.os.storage.StorageManager
android.os.storage.StorageVolume
android.os.storage.StorageVolume$1
-android.preference.Preference$OnPreferenceChangeListener
android.preference.PreferenceActivity
android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
android.preference.PreferenceManager
android.preference.PreferenceManager$OnPreferenceTreeClickListener
android.print.PrintManager
+android.provider.-$Lambda$46$87WmhkvObehVg0OMBzwa_MTVV8g
android.provider.BaseColumns
android.provider.ContactsContract
android.provider.ContactsContract$CommonDataKinds$BaseTypes
android.provider.ContactsContract$CommonDataKinds$CommonColumns
-android.provider.ContactsContract$CommonDataKinds$Email
android.provider.ContactsContract$CommonDataKinds$Phone
android.provider.ContactsContract$ContactCounts
android.provider.ContactsContract$ContactNameColumns
@@ -1748,13 +1721,12 @@ android.provider.ContactsContract$DataColumnsWithJoins
android.provider.ContactsContract$DataUsageStatColumns
android.provider.ContactsContract$RawContactsColumns
android.provider.ContactsContract$StatusColumns
-android.provider.MediaStore$Images$ImageColumns
-android.provider.MediaStore$Images$Media
android.provider.MediaStore$MediaColumns
+android.provider.Settings
+android.provider.Settings$ContentProviderHolder
android.provider.Settings$GenerationTracker
android.provider.Settings$Global
android.provider.Settings$NameValueCache
-android.provider.Settings$NameValueCache$-java_lang_String_getStringForUser_android_content_ContentResolver_cr_java_lang_String_name_int_userHandle_LambdaImpl0
android.provider.Settings$NameValueTable
android.provider.Settings$Secure
android.provider.Settings$SettingNotFoundException
@@ -1773,8 +1745,6 @@ android.provider.Settings$System$InclusiveFloatRangeValidator
android.provider.Settings$System$InclusiveIntegerRangeValidator
android.provider.Settings$System$Validator
android.renderscript.RenderScriptCacheDir
-android.security.FrameworkNetworkSecurityPolicy
-android.security.NetworkSecurityPolicy
android.security.keystore.AndroidKeyStoreBCWorkaroundProvider
android.security.keystore.AndroidKeyStoreProvider
android.security.net.config.ApplicationConfig
@@ -1797,9 +1767,7 @@ android.security.net.config.PinSet
android.security.net.config.RootTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.security.net.config.SystemCertificateSource
-android.security.net.config.TrustAnchor
android.security.net.config.TrustedCertificateStoreAdapter
-android.security.net.config.UserCertificateSource
android.service.persistentdata.PersistentDataBlockManager
android.system.ErrnoException
android.system.GaiException
@@ -1811,6 +1779,7 @@ android.system.StructAddrinfo
android.system.StructFlock
android.system.StructGroupReq
android.system.StructGroupSourceReq
+android.system.StructIfaddrs
android.system.StructLinger
android.system.StructPasswd
android.system.StructPollfd
@@ -1824,11 +1793,11 @@ android.telecom.TelecomManager
android.telephony.CarrierConfigManager
android.telephony.PhoneNumberUtils
android.telephony.PhoneStateListener
-android.telephony.PhoneStateListener$1
-android.telephony.PhoneStateListener$IPhoneStateListenerStub
android.telephony.Rlog
+android.telephony.ServiceState
android.telephony.SubscriptionManager
android.telephony.TelephonyManager
+android.telephony.TelephonyManager$MultiSimVariants
android.text.AndroidBidi
android.text.AndroidCharacter
android.text.BoringLayout
@@ -1839,15 +1808,19 @@ android.text.DynamicLayout$ChangeWatcher
android.text.Editable
android.text.Editable$Factory
android.text.FontConfig
+android.text.FontConfig$1
android.text.FontConfig$Alias
+android.text.FontConfig$Alias$1
android.text.FontConfig$Axis
+android.text.FontConfig$Axis$1
android.text.FontConfig$Family
+android.text.FontConfig$Family$1
android.text.FontConfig$Font
+android.text.FontConfig$Font$1
+android.text.FontManager
android.text.GetChars
android.text.GraphicsOperations
android.text.Html
-android.text.Html$HtmlParser
-android.text.HtmlToSpannedConverter
android.text.Hyphenator
android.text.InputFilter
android.text.InputType
@@ -1889,15 +1862,11 @@ android.text.TextPaint
android.text.TextUtils
android.text.TextUtils$1
android.text.TextUtils$EllipsizeCallback
-android.text.TextUtils$SimpleStringSplitter
-android.text.TextUtils$StringSplitter
android.text.TextUtils$TruncateAt
android.text.TextWatcher
android.text.format.DateFormat
android.text.format.DateUtils
-android.text.format.Formatter
android.text.format.Time
-android.text.format.Time$TimeCalculator
android.text.method.AllCapsTransformationMethod
android.text.method.ArrowKeyMovementMethod
android.text.method.BaseKeyListener
@@ -1919,10 +1888,8 @@ android.text.method.TransformationMethod2
android.text.style.AlignmentSpan
android.text.style.CharacterStyle
android.text.style.ClickableSpan
-android.text.style.DynamicDrawableSpan
android.text.style.EasyEditSpan
android.text.style.ForegroundColorSpan
-android.text.style.ImageSpan
android.text.style.LeadingMarginSpan
android.text.style.LineBackgroundSpan
android.text.style.LineHeightSpan
@@ -1933,9 +1900,7 @@ android.text.style.SpellCheckSpan
android.text.style.StyleSpan
android.text.style.SuggestionSpan
android.text.style.TabStopSpan
-android.text.style.TextAppearanceSpan
android.text.style.URLSpan
-android.text.style.UnderlineSpan
android.text.style.UpdateAppearance
android.text.style.UpdateLayout
android.text.style.WrapTogetherSpan
@@ -1956,7 +1921,6 @@ android.transition.ChangeTransform$1
android.transition.ChangeTransform$2
android.transition.Fade
android.transition.PathMotion
-android.transition.Scene
android.transition.Transition
android.transition.Transition$1
android.transition.Transition$EpicenterCallback
@@ -1976,18 +1940,20 @@ android.util.Base64
android.util.Base64$Coder
android.util.Base64$Decoder
android.util.Base64$Encoder
+android.util.BootTimingsTraceLog
android.util.ContainerHelpers
android.util.DisplayMetrics
android.util.EventLog
android.util.EventLog$Event
android.util.FloatProperty
+android.util.IntArray
android.util.IntProperty
-android.util.JsonReader
android.util.Log
android.util.Log$1
android.util.Log$ImmediateLogWriter
android.util.Log$TerribleFailureHandler
android.util.LogPrinter
+android.util.LongArray
android.util.LongSparseArray
android.util.LongSparseLongArray
android.util.LruCache
@@ -2002,6 +1968,7 @@ android.util.MutableLong
android.util.Pair
android.util.PathParser
android.util.PathParser$PathData
+android.util.Patterns
android.util.Pools$Pool
android.util.Pools$SimplePool
android.util.Pools$SynchronizedPool
@@ -2011,24 +1978,24 @@ android.util.Range
android.util.Rational
android.util.Singleton
android.util.Size
+android.util.SizeF
android.util.Slog
android.util.SparseArray
android.util.SparseBooleanArray
android.util.SparseIntArray
-android.util.SparseLongArray
android.util.StateSet
android.util.SuperNotCalledException
-android.util.TimeFormatException
android.util.TypedValue
android.util.Xml
android.util.jar.StrictJarFile
+android.view.-$Lambda$48$iU_USrtPm1XIm5H9QYQvXfBGDE4
+android.view.-$Lambda$49$iU_USrtPm1XIm5H9QYQvXfBGDE4
android.view.AbsSavedState
android.view.AbsSavedState$1
android.view.AbsSavedState$2
android.view.ActionMode
android.view.ActionMode$Callback
android.view.ActionProvider
-android.view.ActionProvider$SubUiVisibilityListener
android.view.Choreographer
android.view.Choreographer$1
android.view.Choreographer$2
@@ -2041,8 +2008,6 @@ android.view.ContextMenu
android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
-android.view.Display$ColorTransform
-android.view.Display$ColorTransform$1
android.view.Display$HdrCapabilities
android.view.Display$HdrCapabilities$1
android.view.Display$Mode
@@ -2052,6 +2017,7 @@ android.view.DisplayEventReceiver
android.view.DisplayInfo
android.view.DisplayInfo$1
android.view.DisplayListCanvas
+android.view.DragEvent
android.view.FallbackEventHandler
android.view.FocusFinder
android.view.FocusFinder$1
@@ -2066,8 +2032,6 @@ android.view.GestureDetector$OnContextClickListener
android.view.GestureDetector$OnDoubleTapListener
android.view.GestureDetector$OnGestureListener
android.view.GestureDetector$SimpleOnGestureListener
-android.view.GraphicBuffer
-android.view.GraphicBuffer$1
android.view.Gravity
android.view.HandlerActionQueue
android.view.HandlerActionQueue$HandlerAction
@@ -2092,7 +2056,6 @@ android.view.InputChannel
android.view.InputChannel$1
android.view.InputDevice
android.view.InputDevice$1
-android.view.InputDevice$MotionRange
android.view.InputEvent
android.view.InputEvent$1
android.view.InputEventConsistencyVerifier
@@ -2125,9 +2088,12 @@ android.view.MotionEvent$PointerCoords
android.view.MotionEvent$PointerProperties
android.view.PointerIcon
android.view.PointerIcon$1
+android.view.RecordingCanvas
android.view.RenderNode
+android.view.RenderNode$NoImagePreloadHolder
android.view.RenderNodeAnimator
android.view.RenderNodeAnimator$1
+android.view.RenderNodeAnimatorSetHelper
android.view.SearchEvent
android.view.SoundEffectConstants
android.view.SubMenu
@@ -2143,9 +2109,8 @@ android.view.SurfaceHolder$Callback2
android.view.SurfaceSession
android.view.SurfaceView
android.view.TextureView
-android.view.TextureView$SurfaceTextureListener
android.view.ThreadedRenderer
-android.view.ThreadedRenderer$HardwareDrawCallbacks
+android.view.ThreadedRenderer$DrawCallbacks
android.view.ThreadedRenderer$ProcessInitializer
android.view.VelocityTracker
android.view.VelocityTracker$Estimator
@@ -2182,6 +2147,7 @@ android.view.View$OnLongClickListener
android.view.View$OnTouchListener
android.view.View$PerformClick
android.view.View$ScrollabilityCache
+android.view.View$TooltipInfo
android.view.View$TransformationInfo
android.view.View$UnsetPressedState
android.view.ViewConfiguration
@@ -2193,11 +2159,13 @@ android.view.ViewGroup$LayoutParams
android.view.ViewGroup$MarginLayoutParams
android.view.ViewGroup$OnHierarchyChangeListener
android.view.ViewGroup$TouchTarget
+android.view.ViewGroupOverlay
android.view.ViewManager
android.view.ViewOutlineProvider
android.view.ViewOutlineProvider$1
android.view.ViewOutlineProvider$2
android.view.ViewOutlineProvider$3
+android.view.ViewOverlay
android.view.ViewParent
android.view.ViewPropertyAnimator
android.view.ViewPropertyAnimator$1
@@ -2245,6 +2213,7 @@ android.view.ViewTreeObserver$OnTouchModeChangeListener
android.view.Window
android.view.Window$Callback
android.view.Window$OnWindowDismissedCallback
+android.view.Window$OnWindowSwipeDismissedCallback
android.view.Window$WindowControllerCallback
android.view.WindowAnimationFrameStats
android.view.WindowAnimationFrameStats$1
@@ -2254,7 +2223,6 @@ android.view.WindowContentFrameStats$1
android.view.WindowInsets
android.view.WindowLeaked
android.view.WindowManager
-android.view.WindowManager$BadTokenException
android.view.WindowManager$LayoutParams
android.view.WindowManager$LayoutParams$1
android.view.WindowManagerGlobal
@@ -2272,9 +2240,6 @@ android.view.accessibility.AccessibilityNodeInfo
android.view.accessibility.AccessibilityNodeProvider
android.view.accessibility.AccessibilityRecord
android.view.accessibility.CaptioningManager
-android.view.accessibility.CaptioningManager$1
-android.view.accessibility.CaptioningManager$CaptioningChangeListener
-android.view.accessibility.CaptioningManager$MyContentObserver
android.view.accessibility.IAccessibilityManager
android.view.accessibility.IAccessibilityManager$Stub
android.view.accessibility.IAccessibilityManager$Stub$Proxy
@@ -2291,24 +2256,23 @@ android.view.animation.Animation$AnimationListener
android.view.animation.Animation$NoImagePreloadHolder
android.view.animation.AnimationSet
android.view.animation.AnimationUtils
+android.view.animation.AnimationUtils$1
+android.view.animation.AnimationUtils$AnimationState
android.view.animation.BaseInterpolator
android.view.animation.DecelerateInterpolator
android.view.animation.Interpolator
android.view.animation.LinearInterpolator
-android.view.animation.OvershootInterpolator
android.view.animation.PathInterpolator
android.view.animation.ScaleAnimation
android.view.animation.Transformation
android.view.animation.TranslateAnimation
+android.view.autofill.AutoFillManager
android.view.inputmethod.BaseInputConnection
android.view.inputmethod.ComposingText
android.view.inputmethod.CursorAnchorInfo$Builder
android.view.inputmethod.EditorInfo
android.view.inputmethod.EditorInfo$1
-android.view.inputmethod.ExtractedText
-android.view.inputmethod.ExtractedText$1
android.view.inputmethod.InputConnection
-android.view.inputmethod.InputConnectionInspector
android.view.inputmethod.InputMethodManager
android.view.inputmethod.InputMethodManager$1
android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
@@ -2316,6 +2280,7 @@ android.view.inputmethod.InputMethodManager$FinishedInputEventCallback
android.view.inputmethod.InputMethodManager$H
android.view.inputmethod.InputMethodManager$ImeInputEventSender
android.view.inputmethod.InputMethodManager$PendingEvent
+android.view.textclassifier.TextClassificationManager
android.view.textservice.SpellCheckerSubtype
android.view.textservice.SpellCheckerSubtype$1
android.view.textservice.TextServicesManager
@@ -2323,7 +2288,6 @@ android.webkit.IWebViewUpdateService
android.webkit.IWebViewUpdateService$Stub
android.webkit.IWebViewUpdateService$Stub$Proxy
android.webkit.MimeTypeMap
-android.webkit.WebSettings
android.webkit.WebView
android.webkit.WebViewFactory
android.webkit.WebViewFactory$MissingWebViewPackageException
@@ -2339,14 +2303,6 @@ android.widget.AbsListView$SavedState$1
android.widget.AbsSeekBar
android.widget.AbsSpinner
android.widget.AbsoluteLayout
-android.widget.ActionMenuPresenter
-android.widget.ActionMenuPresenter$1
-android.widget.ActionMenuPresenter$2
-android.widget.ActionMenuPresenter$OverflowMenuButton
-android.widget.ActionMenuPresenter$OverflowMenuButton$1
-android.widget.ActionMenuPresenter$PopupPresenterCallback
-android.widget.ActionMenuView
-android.widget.ActionMenuView$ActionMenuChildView
android.widget.ActionMenuView$OnMenuItemClickListener
android.widget.Adapter
android.widget.AdapterView
@@ -2367,24 +2323,16 @@ android.widget.EditText
android.widget.Editor
android.widget.Editor$1
android.widget.Editor$2
-android.widget.Editor$Blink
android.widget.Editor$CursorAnchorInfoNotifier
-android.widget.Editor$CursorController
-android.widget.Editor$EditOperation
-android.widget.Editor$EditOperation$1
android.widget.Editor$InputContentType
-android.widget.Editor$InputMethodState
-android.widget.Editor$InsertionPointCursorController
android.widget.Editor$PositionListener
android.widget.Editor$ProcessTextIntentActionsHandler
-android.widget.Editor$SelectionModifierCursorController
android.widget.Editor$SpanController
android.widget.Editor$SuggestionHelper
android.widget.Editor$SuggestionHelper$SuggestionSpanComparator
android.widget.Editor$TextRenderNode
android.widget.Editor$TextViewPositionListener
android.widget.Editor$UndoInputFilter
-android.widget.Filter
android.widget.Filter$FilterListener
android.widget.Filterable
android.widget.ForwardingListener
@@ -2392,8 +2340,6 @@ android.widget.FrameLayout
android.widget.FrameLayout$LayoutParams
android.widget.HeaderViewListAdapter
android.widget.HorizontalScrollView
-android.widget.HorizontalScrollView$SavedState
-android.widget.HorizontalScrollView$SavedState$1
android.widget.ImageButton
android.widget.ImageView
android.widget.ImageView$ScaleType
@@ -2402,12 +2348,12 @@ android.widget.LinearLayout$LayoutParams
android.widget.ListAdapter
android.widget.ListPopupWindow
android.widget.ListPopupWindow$ListSelectorHider
+android.widget.ListPopupWindow$PopupDataSetObserver
android.widget.ListPopupWindow$PopupScrollListener
android.widget.ListPopupWindow$PopupTouchInterceptor
android.widget.ListPopupWindow$ResizePopupRunnable
android.widget.ListView
android.widget.ListView$ArrowScrollFocusResult
-android.widget.ListView$FixedViewInfo
android.widget.MultiAutoCompleteTextView
android.widget.OverScroller
android.widget.OverScroller$SplineOverScroller
@@ -2415,8 +2361,6 @@ android.widget.PopupWindow
android.widget.PopupWindow$1
android.widget.PopupWindow$2
android.widget.PopupWindow$OnDismissListener
-android.widget.PopupWindow$PopupDecorView
-android.widget.PopupWindow$PopupDecorView$1
android.widget.ProgressBar
android.widget.ProgressBar$1
android.widget.ProgressBar$SavedState
@@ -2428,30 +2372,17 @@ android.widget.RelativeLayout$DependencyGraph
android.widget.RelativeLayout$DependencyGraph$Node
android.widget.RelativeLayout$LayoutParams
android.widget.RemoteViews
-android.widget.RemoteViews$1
-android.widget.RemoteViews$2
-android.widget.RemoteViews$3
-android.widget.RemoteViews$Action
-android.widget.RemoteViews$ActionException
-android.widget.RemoteViews$BitmapCache
-android.widget.RemoteViews$MemoryUsageCounter
-android.widget.RemoteViews$MutablePair
-android.widget.RemoteViews$OnClickHandler
-android.widget.RemoteViews$ReflectionAction
-android.widget.RemoteViews$RuntimeAction
-android.widget.RemoteViews$SetOnClickPendingIntent
+android.widget.RemoteViews$RemoteView
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RtlSpacingHelper
android.widget.ScrollBarDrawable
android.widget.ScrollView
android.widget.Scroller
android.widget.Scroller$ViscousFluidInterpolator
-android.widget.SectionIndexer
android.widget.SeekBar
android.widget.Space
android.widget.Spinner
android.widget.SpinnerAdapter
-android.widget.Switch
android.widget.TextView
android.widget.TextView$BufferType
android.widget.TextView$ChangeWatcher
@@ -2465,7 +2396,6 @@ android.widget.Toast
android.widget.Toolbar
android.widget.Toolbar$1
android.widget.Toolbar$2
-android.widget.Toolbar$ExpandedActionViewMenuPresenter
android.widget.Toolbar$LayoutParams
android.widget.WrapperListAdapter
com.android.dex.ClassData
@@ -2497,9 +2427,6 @@ com.android.dex.util.FileUtils
com.android.i18n.phonenumbers.NumberParseException
com.android.i18n.phonenumbers.PhoneNumberUtil
com.android.internal.R$styleable
-com.android.internal.app.AlertController
-com.android.internal.app.AlertController$1
-com.android.internal.app.AlertController$ButtonHandler
com.android.internal.app.IAppOpsCallback
com.android.internal.app.IAppOpsCallback$Stub
com.android.internal.app.IAppOpsService
@@ -2507,42 +2434,47 @@ com.android.internal.app.IAppOpsService$Stub
com.android.internal.app.IAppOpsService$Stub$Proxy
com.android.internal.app.IBatteryStats
com.android.internal.app.IBatteryStats$Stub
+com.android.internal.app.IBatteryStats$Stub$Proxy
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
-com.android.internal.appwidget.IAppWidgetService
-com.android.internal.appwidget.IAppWidgetService$Stub
-com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
com.android.internal.content.NativeLibraryHelper
com.android.internal.content.ReferrerIntent
com.android.internal.content.ReferrerIntent$1
+com.android.internal.graphics.drawable.AnimationScaleListDrawable
+com.android.internal.graphics.drawable.AnimationScaleListDrawable$AnimationScaleListState
com.android.internal.inputmethod.InputMethodUtils
com.android.internal.inputmethod.InputMethodUtils$1
com.android.internal.inputmethod.LocaleUtils$LocaleExtractor
com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.logging.AndroidHandler$1
+com.android.internal.logging.EventLogTags
+com.android.internal.logging.MetricsLogger
com.android.internal.net.NetworkStatsFactory
com.android.internal.os.AndroidPrintStream
com.android.internal.os.BinderInternal
com.android.internal.os.BinderInternal$GcWatcher
-com.android.internal.os.InstallerConnection$InstallerException
+com.android.internal.os.FuseAppLoop
+com.android.internal.os.FuseAppLoop$1
+com.android.internal.os.FuseAppLoop$UnmountedException
com.android.internal.os.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.PathClassLoaderFactory
+com.android.internal.os.RoSystemProperties
com.android.internal.os.RuntimeInit
com.android.internal.os.RuntimeInit$1
com.android.internal.os.RuntimeInit$Arguments
com.android.internal.os.RuntimeInit$KillApplicationHandler
com.android.internal.os.RuntimeInit$LoggingHandler
-com.android.internal.os.RoSystemProperties
com.android.internal.os.SamplingProfilerIntegration
com.android.internal.os.SomeArgs
com.android.internal.os.Zygote
+com.android.internal.os.Zygote$MethodAndArgsCaller
com.android.internal.os.ZygoteConnection
com.android.internal.os.ZygoteConnection$Arguments
com.android.internal.os.ZygoteInit
-com.android.internal.os.ZygoteInit$MethodAndArgsCaller
com.android.internal.os.ZygoteSecurityException
+com.android.internal.os.ZygoteServer
com.android.internal.policy.DecorContext
com.android.internal.policy.DecorView
com.android.internal.policy.DecorView$ColorViewState
@@ -2554,8 +2486,6 @@ com.android.internal.policy.PhoneWindow$PanelFeatureState
com.android.internal.policy.PhoneWindow$PhoneWindowMenuCallback
com.android.internal.policy.PhoneWindow$RotationWatcher
com.android.internal.policy.PhoneWindow$RotationWatcher$1
-com.android.internal.telephony.IPhoneStateListener
-com.android.internal.telephony.IPhoneStateListener$Stub
com.android.internal.telephony.ISub
com.android.internal.telephony.ISub$Stub
com.android.internal.telephony.ISub$Stub$Proxy
@@ -2569,6 +2499,8 @@ com.android.internal.telephony.PhoneConstants$State
com.android.internal.textservice.ITextServicesManager
com.android.internal.textservice.ITextServicesManager$Stub
com.android.internal.textservice.ITextServicesManager$Stub$Proxy
+com.android.internal.transition.EpicenterTranslateClipReveal
+com.android.internal.transition.TransitionConstants
com.android.internal.util.ArrayUtils
com.android.internal.util.FastPrintWriter
com.android.internal.util.FastPrintWriter$DummyWriter
@@ -2579,15 +2511,10 @@ com.android.internal.util.Preconditions
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.XmlUtils
com.android.internal.util.XmlUtils$WriteMapCallback
-com.android.internal.view.ActionBarPolicy
com.android.internal.view.IInputConnectionWrapper
com.android.internal.view.IInputConnectionWrapper$MyHandler
-com.android.internal.view.IInputConnectionWrapper$SomeArgs
com.android.internal.view.IInputContext
com.android.internal.view.IInputContext$Stub
-com.android.internal.view.IInputContextCallback
-com.android.internal.view.IInputContextCallback$Stub
-com.android.internal.view.IInputContextCallback$Stub$Proxy
com.android.internal.view.IInputMethodClient
com.android.internal.view.IInputMethodClient$Stub
com.android.internal.view.IInputMethodManager
@@ -2603,23 +2530,13 @@ com.android.internal.view.animation.FallbackLUTInterpolator
com.android.internal.view.animation.HasNativeInterpolator
com.android.internal.view.animation.NativeInterpolatorFactory
com.android.internal.view.animation.NativeInterpolatorFactoryHelper
-com.android.internal.view.menu.ActionMenuItem
-com.android.internal.view.menu.BaseMenuPresenter
com.android.internal.view.menu.MenuBuilder
com.android.internal.view.menu.MenuBuilder$Callback
-com.android.internal.view.menu.MenuBuilder$ItemInvoker
com.android.internal.view.menu.MenuItemImpl
-com.android.internal.view.menu.MenuPresenter
com.android.internal.view.menu.MenuPresenter$Callback
-com.android.internal.view.menu.MenuView
com.android.internal.view.menu.ShowableListMenu
com.android.internal.widget.BackgroundFallback
com.android.internal.widget.DecorContentParent
-com.android.internal.widget.DecorToolbar
-com.android.internal.widget.EditableInputConnection
-com.android.internal.widget.ScrollBarUtils
-com.android.internal.widget.ToolbarWidgetWrapper
-com.android.internal.widget.ToolbarWidgetWrapper$1
com.android.okhttp.Address
com.android.okhttp.Authenticator
com.android.okhttp.CacheControl
@@ -2635,6 +2552,8 @@ com.android.okhttp.ConnectionPool$1
com.android.okhttp.ConnectionSpec
com.android.okhttp.ConnectionSpec$Builder
com.android.okhttp.Dispatcher
+com.android.okhttp.Dns
+com.android.okhttp.Dns$1
com.android.okhttp.Handshake
com.android.okhttp.Headers
com.android.okhttp.Headers$Builder
@@ -2659,8 +2578,6 @@ com.android.okhttp.Route
com.android.okhttp.TlsVersion
com.android.okhttp.internal.ConnectionSpecSelector
com.android.okhttp.internal.Internal
-com.android.okhttp.internal.Network
-com.android.okhttp.internal.Network$1
com.android.okhttp.internal.OptionalMethod
com.android.okhttp.internal.Platform
com.android.okhttp.internal.RouteDatabase
@@ -2670,14 +2587,14 @@ com.android.okhttp.internal.Util$1
com.android.okhttp.internal.http.AuthenticatorAdapter
com.android.okhttp.internal.http.CacheStrategy
com.android.okhttp.internal.http.CacheStrategy$Factory
-com.android.okhttp.internal.http.HttpConnection
-com.android.okhttp.internal.http.HttpConnection$AbstractSource
-com.android.okhttp.internal.http.HttpConnection$ChunkedSource
-com.android.okhttp.internal.http.HttpConnection$FixedLengthSource
+com.android.okhttp.internal.http.Http1xStream
+com.android.okhttp.internal.http.Http1xStream$AbstractSource
+com.android.okhttp.internal.http.Http1xStream$ChunkedSource
+com.android.okhttp.internal.http.Http1xStream$FixedLengthSource
com.android.okhttp.internal.http.HttpEngine
com.android.okhttp.internal.http.HttpEngine$1
com.android.okhttp.internal.http.HttpMethod
-com.android.okhttp.internal.http.HttpTransport
+com.android.okhttp.internal.http.HttpStream
com.android.okhttp.internal.http.OkHeaders
com.android.okhttp.internal.http.OkHeaders$1
com.android.okhttp.internal.http.RealResponseBody
@@ -2687,10 +2604,11 @@ com.android.okhttp.internal.http.RetryableSink
com.android.okhttp.internal.http.RouteException
com.android.okhttp.internal.http.RouteSelector
com.android.okhttp.internal.http.StatusLine
-com.android.okhttp.internal.http.Transport
+com.android.okhttp.internal.http.StreamAllocation
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection
com.android.okhttp.internal.huc.HttpURLConnectionImpl
com.android.okhttp.internal.huc.HttpsURLConnectionImpl
+com.android.okhttp.internal.io.RealConnection
com.android.okhttp.internal.tls.OkHostnameVerifier
com.android.okhttp.okio.AsyncTimeout
com.android.okhttp.okio.AsyncTimeout$1
@@ -2771,8 +2689,12 @@ com.android.org.bouncycastle.jcajce.provider.symmetric.DES
com.android.org.bouncycastle.jcajce.provider.symmetric.DES$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.DESede
com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12
com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBES2AlgorithmParameters$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.RC2
com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings
com.android.org.bouncycastle.jcajce.provider.symmetric.SymmetricAlgorithmProvider
@@ -2792,18 +2714,20 @@ com.android.org.bouncycastle.util.Arrays
com.android.org.bouncycastle.util.Encodable
com.android.org.bouncycastle.util.Strings
com.android.org.bouncycastle.util.Strings$1
+com.android.org.conscrypt.AbstractOpenSSLSession
com.android.org.conscrypt.AbstractSessionContext
com.android.org.conscrypt.AbstractSessionContext$1
com.android.org.conscrypt.AddressUtils
com.android.org.conscrypt.ByteArray
-com.android.org.conscrypt.CertPinManager
+com.android.org.conscrypt.CertBlacklist
com.android.org.conscrypt.CertificatePriorityComparator
com.android.org.conscrypt.ChainStrengthAnalyzer
com.android.org.conscrypt.ClientSessionContext
com.android.org.conscrypt.ClientSessionContext$HostAndPort
com.android.org.conscrypt.CryptoUpcalls
-com.android.org.conscrypt.FileClientSessionCache
-com.android.org.conscrypt.FileClientSessionCache$Impl
+com.android.org.conscrypt.EvpMdRef$MD5
+com.android.org.conscrypt.EvpMdRef$SHA1
+com.android.org.conscrypt.EvpMdRef$SHA256
com.android.org.conscrypt.Hex
com.android.org.conscrypt.JSSEProvider
com.android.org.conscrypt.KeyManagerFactoryImpl
@@ -2817,10 +2741,7 @@ com.android.org.conscrypt.NativeRef$EC_POINT
com.android.org.conscrypt.NativeRef$EVP_MD_CTX
com.android.org.conscrypt.NativeRef$EVP_PKEY
com.android.org.conscrypt.OpenSSLBIOInputStream
-com.android.org.conscrypt.OpenSSLContextImpl
-com.android.org.conscrypt.OpenSSLContextImpl$TLSv12
com.android.org.conscrypt.OpenSSLECGroupContext
-com.android.org.conscrypt.OpenSSLECKeyFactory
com.android.org.conscrypt.OpenSSLECPointContext
com.android.org.conscrypt.OpenSSLECPublicKey
com.android.org.conscrypt.OpenSSLExtendedSessionImpl
@@ -2829,6 +2750,7 @@ com.android.org.conscrypt.OpenSSLKeyHolder
com.android.org.conscrypt.OpenSSLMessageDigestJDK
com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5
com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1
+com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA256
com.android.org.conscrypt.OpenSSLProvider
com.android.org.conscrypt.OpenSSLRSAKeyFactory
com.android.org.conscrypt.OpenSSLRSAPublicKey
@@ -2847,11 +2769,7 @@ com.android.org.conscrypt.OpenSSLX509CertificateFactory$1
com.android.org.conscrypt.OpenSSLX509CertificateFactory$2
com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser
com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException
-com.android.org.conscrypt.PinEntryException
-com.android.org.conscrypt.PinListEntry
-com.android.org.conscrypt.PinManagerException
com.android.org.conscrypt.Platform
-com.android.org.conscrypt.SSLClientSessionCache
com.android.org.conscrypt.SSLParametersImpl
com.android.org.conscrypt.SSLParametersImpl$AliasChooser
com.android.org.conscrypt.SSLParametersImpl$PSKCallbacks
@@ -2863,6 +2781,17 @@ com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustedCertificateIndex
com.android.org.conscrypt.TrustedCertificateKeyStoreSpi
com.android.org.conscrypt.TrustedCertificateStore
+com.android.org.conscrypt.TrustedCertificateStore$1
+com.android.org.conscrypt.TrustedCertificateStore$CertSelector
+com.android.org.conscrypt.ct.CTLogInfo
+com.android.org.conscrypt.ct.CTLogStore
+com.android.org.conscrypt.ct.CTLogStoreImpl
+com.android.org.conscrypt.ct.CTLogStoreImpl$InvalidLogFileException
+com.android.org.conscrypt.ct.CTPolicy
+com.android.org.conscrypt.ct.CTPolicyImpl
+com.android.org.conscrypt.ct.CTVerifier
+com.android.org.conscrypt.ct.KnownLogs
+com.android.org.conscrypt.ct.SerializationException
com.android.org.conscrypt.util.ArrayUtils
com.android.server.NetworkManagementSocketTagger
com.android.server.NetworkManagementSocketTagger$1
@@ -2871,20 +2800,31 @@ com.google.android.collect.Lists
com.google.android.collect.Maps
com.google.android.gles_jni.EGLImpl
com.google.android.gles_jni.GLImpl
+dalvik.annotation.optimization.CriticalNative
+dalvik.annotation.optimization.FastNative
dalvik.system.BaseDexClassLoader
+dalvik.system.BaseDexClassLoader$Reporter
dalvik.system.BlockGuard
dalvik.system.BlockGuard$1
dalvik.system.BlockGuard$2
dalvik.system.BlockGuard$BlockGuardPolicyException
dalvik.system.BlockGuard$Policy
+dalvik.system.ClassExt
dalvik.system.CloseGuard
dalvik.system.CloseGuard$DefaultReporter
+dalvik.system.CloseGuard$DefaultTracker
dalvik.system.CloseGuard$Reporter
+dalvik.system.CloseGuard$Tracker
dalvik.system.DalvikLogHandler
+dalvik.system.DexClassLoader
dalvik.system.DexFile
dalvik.system.DexFile$DFEnum
dalvik.system.DexPathList
dalvik.system.DexPathList$Element
+dalvik.system.DexPathList$NativeLibraryElement
+dalvik.system.EmulatedStackFrame
+dalvik.system.EmulatedStackFrame$Range
+dalvik.system.InMemoryDexClassLoader$DexData
dalvik.system.PathClassLoader
dalvik.system.SocketTagger
dalvik.system.SocketTagger$1
@@ -2892,11 +2832,6 @@ dalvik.system.VMDebug
dalvik.system.VMRuntime
dalvik.system.VMStack
dalvik.system.ZygoteHooks
-java.beans.ChangeListenerMap
-java.beans.PropertyChangeEvent
-java.beans.PropertyChangeListener
-java.beans.PropertyChangeSupport
-java.beans.PropertyChangeSupport$PropertyChangeListenerMap
java.io.Bits
java.io.BufferedInputStream
java.io.BufferedOutputStream
@@ -2911,6 +2846,7 @@ java.io.DataInput
java.io.DataInputStream
java.io.DataOutput
java.io.DataOutputStream
+java.io.DefaultFileSystem
java.io.EOFException
java.io.ExpiringCache
java.io.ExpiringCache$1
@@ -2919,6 +2855,7 @@ java.io.Externalizable
java.io.File
java.io.File$PathStatus
java.io.FileDescriptor
+java.io.FileDescriptor$1
java.io.FileFilter
java.io.FileInputStream
java.io.FileInputStream$UseManualSkipException
@@ -2930,18 +2867,33 @@ java.io.FileWriter
java.io.FilenameFilter
java.io.FilterInputStream
java.io.FilterOutputStream
-java.io.FilterReader
java.io.Flushable
java.io.IOException
java.io.InputStream
java.io.InputStreamReader
java.io.InterruptedIOException
+java.io.InvalidClassException
java.io.InvalidObjectException
java.io.ObjectInput
java.io.ObjectInputStream
+java.io.ObjectInputStream$BlockDataInputStream
+java.io.ObjectInputStream$HandleTable
+java.io.ObjectInputStream$HandleTable$HandleList
+java.io.ObjectInputStream$PeekInputStream
+java.io.ObjectInputStream$ValidationList
java.io.ObjectOutput
java.io.ObjectOutputStream
+java.io.ObjectOutputStream$BlockDataOutputStream
+java.io.ObjectOutputStream$HandleTable
+java.io.ObjectOutputStream$PutField
+java.io.ObjectOutputStream$ReplaceTable
java.io.ObjectStreamClass
+java.io.ObjectStreamClass$2
+java.io.ObjectStreamClass$Caches
+java.io.ObjectStreamClass$EntryFuture
+java.io.ObjectStreamClass$FieldReflector
+java.io.ObjectStreamClass$FieldReflectorKey
+java.io.ObjectStreamClass$WeakClassKey
java.io.ObjectStreamConstants
java.io.ObjectStreamException
java.io.ObjectStreamField
@@ -2950,7 +2902,6 @@ java.io.OutputStreamWriter
java.io.PrintStream
java.io.PrintWriter
java.io.PushbackInputStream
-java.io.PushbackReader
java.io.RandomAccessFile
java.io.Reader
java.io.SequenceInputStream
@@ -2962,10 +2913,13 @@ java.io.UTFDataFormatException
java.io.UnixFileSystem
java.io.UnsupportedEncodingException
java.io.Writer
+java.lang.-$Lambda$250$S9HjrJh0nDg7IyU6wZdPArnZWRQ
+java.lang.-$Lambda$251$S9HjrJh0nDg7IyU6wZdPArnZWRQ
java.lang.AbstractMethodError
java.lang.AbstractStringBuilder
java.lang.AndroidHardcodedSystemProperties
java.lang.Appendable
+java.lang.ArithmeticException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayStoreException
java.lang.AssertionError
@@ -2977,8 +2931,6 @@ java.lang.Byte$ByteCache
java.lang.CaseMapper
java.lang.CaseMapper$1
java.lang.CharSequence
-java.lang.CharSequence$-java_util_stream_IntStream_chars__LambdaImpl0
-java.lang.CharSequence$-java_util_stream_IntStream_codePoints__LambdaImpl0
java.lang.CharSequence$1CharIterator
java.lang.CharSequence$1CodePointIterator
java.lang.Character
@@ -3008,9 +2960,7 @@ java.lang.EnumConstantNotPresentException
java.lang.Error
java.lang.Exception
java.lang.Float
-java.lang.FloatingDecimal
-java.lang.FloatingDecimal$1
-java.lang.FloatingDecimal$2
+java.lang.IllegalAccessError
java.lang.IllegalAccessException
java.lang.IllegalArgumentException
java.lang.IllegalStateException
@@ -3029,7 +2979,7 @@ java.lang.LinkageError
java.lang.Long
java.lang.Long$LongCache
java.lang.Math
-java.lang.Math$NoImagePreloadHolder
+java.lang.Math$RandomNumberGeneratorHolder
java.lang.NoClassDefFoundError
java.lang.NoSuchFieldError
java.lang.NoSuchFieldException
@@ -3042,6 +2992,7 @@ java.lang.Object
java.lang.OutOfMemoryError
java.lang.Package
java.lang.Process
+java.lang.ProcessBuilder
java.lang.ProcessEnvironment
java.lang.Readable
java.lang.ReflectiveOperationException
@@ -3053,7 +3004,6 @@ java.lang.SecurityException
java.lang.SecurityManager
java.lang.Short
java.lang.Short$ShortCache
-java.lang.Shutdown
java.lang.StackOverflowError
java.lang.StackTraceElement
java.lang.StrictMath
@@ -3061,7 +3011,6 @@ java.lang.String
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
-java.lang.StringCoding
java.lang.StringFactory
java.lang.StringIndexOutOfBoundsException
java.lang.System
@@ -3095,6 +3044,22 @@ java.lang.annotation.IncompleteAnnotationException
java.lang.annotation.Inherited
java.lang.annotation.Retention
java.lang.annotation.Target
+java.lang.invoke.MethodHandle
+java.lang.invoke.MethodHandleImpl
+java.lang.invoke.MethodHandleImpl$HandleInfo
+java.lang.invoke.MethodHandleInfo
+java.lang.invoke.MethodHandleStatics
+java.lang.invoke.MethodHandles
+java.lang.invoke.MethodType
+java.lang.invoke.MethodType$ConcurrentWeakInternSet
+java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry
+java.lang.invoke.MethodTypeForm
+java.lang.invoke.Transformers$BindTo
+java.lang.invoke.Transformers$Collector
+java.lang.invoke.Transformers$Spreader
+java.lang.invoke.Transformers$Transformer
+java.lang.invoke.Transformers$VarargsCollector
+java.lang.invoke.WrongMethodTypeException
java.lang.ref.FinalizerReference
java.lang.ref.FinalizerReference$Sentinel
java.lang.ref.PhantomReference
@@ -3102,47 +3067,54 @@ java.lang.ref.Reference
java.lang.ref.ReferenceQueue
java.lang.ref.SoftReference
java.lang.ref.WeakReference
-java.lang.reflect.AbstractMethod
-java.lang.reflect.AbstractMethod$GenericInfo
java.lang.reflect.AccessibleObject
java.lang.reflect.AnnotatedElement
java.lang.reflect.Array
java.lang.reflect.Constructor
+java.lang.reflect.Executable
+java.lang.reflect.Executable$GenericInfo
java.lang.reflect.Field
-java.lang.reflect.GenericArrayType
java.lang.reflect.GenericDeclaration
java.lang.reflect.InvocationHandler
java.lang.reflect.InvocationTargetException
+java.lang.reflect.MalformedParametersException
java.lang.reflect.Member
java.lang.reflect.Method
java.lang.reflect.Method$1
java.lang.reflect.Modifier
+java.lang.reflect.Parameter
java.lang.reflect.ParameterizedType
java.lang.reflect.Proxy
java.lang.reflect.Proxy$1
+java.lang.reflect.Proxy$Key1
+java.lang.reflect.Proxy$Key2
+java.lang.reflect.Proxy$KeyFactory
+java.lang.reflect.Proxy$KeyX
+java.lang.reflect.Proxy$ProxyClassFactory
java.lang.reflect.Type
java.lang.reflect.TypeVariable
-java.lang.reflect.WildcardType
+java.lang.reflect.WeakCache
+java.lang.reflect.WeakCache$CacheKey
+java.lang.reflect.WeakCache$CacheValue
+java.lang.reflect.WeakCache$Factory
+java.lang.reflect.WeakCache$LookupValue
+java.lang.reflect.WeakCache$Value
java.math.BigDecimal
java.math.BigInt
java.math.BigInteger
-java.math.BitLevel
java.math.NativeBN
java.math.RoundingMode
-java.net.AbstractPlainDatagramSocketImpl
java.net.AbstractPlainSocketImpl
java.net.AddressCache
java.net.AddressCache$AddressCacheEntry
java.net.AddressCache$AddressCacheKey
java.net.ConnectException
java.net.CookieHandler
-java.net.DatagramPacket
-java.net.DatagramSocketImpl
-java.net.DefaultInterface
java.net.HttpURLConnection
java.net.IDN
java.net.Inet4Address
java.net.Inet6Address
+java.net.Inet6Address$Inet6AddressHolder
java.net.Inet6AddressImpl
java.net.InetAddress
java.net.InetAddress$1
@@ -3150,12 +3122,10 @@ java.net.InetAddress$InetAddressHolder
java.net.InetAddressImpl
java.net.InetSocketAddress
java.net.InetSocketAddress$InetSocketAddressHolder
-java.net.InterfaceAddress
java.net.JarURLConnection
java.net.MalformedURLException
java.net.NetworkInterface
java.net.Parts
-java.net.PlainDatagramSocketImpl
java.net.PlainSocketImpl
java.net.ProtocolException
java.net.Proxy
@@ -3164,6 +3134,8 @@ java.net.ProxySelector
java.net.ResponseCache
java.net.ServerSocket
java.net.Socket
+java.net.Socket$2
+java.net.Socket$3
java.net.SocketAddress
java.net.SocketException
java.net.SocketImpl
@@ -3173,7 +3145,6 @@ java.net.SocketOutputStream
java.net.SocketTimeoutException
java.net.SocksConsts
java.net.SocksSocketImpl
-java.net.SocksSocketImpl$3
java.net.URI
java.net.URI$Parser
java.net.URISyntaxException
@@ -3222,6 +3193,7 @@ java.nio.channels.FileChannel$MapMode
java.nio.channels.FileLock
java.nio.channels.GatheringByteChannel
java.nio.channels.InterruptibleChannel
+java.nio.channels.MulticastChannel
java.nio.channels.NetworkChannel
java.nio.channels.ReadableByteChannel
java.nio.channels.ScatteringByteChannel
@@ -3248,6 +3220,7 @@ java.nio.charset.CodingErrorAction
java.nio.charset.IllegalCharsetNameException
java.nio.charset.StandardCharsets
java.nio.charset.UnsupportedCharsetException
+java.nio.file.attribute.FileAttribute
java.security.AccessControlContext
java.security.AccessControlException
java.security.AccessController
@@ -3338,7 +3311,6 @@ java.security.interfaces.RSAPrivateKey
java.security.interfaces.RSAPublicKey
java.security.spec.AlgorithmParameterSpec
java.security.spec.ECField
-java.security.spec.ECFieldF2m
java.security.spec.ECFieldFp
java.security.spec.ECParameterSpec
java.security.spec.ECPoint
@@ -3346,15 +3318,12 @@ java.security.spec.ECPublicKeySpec
java.security.spec.EllipticCurve
java.security.spec.EncodedKeySpec
java.security.spec.InvalidKeySpecException
-java.security.spec.InvalidParameterSpecException
java.security.spec.KeySpec
java.security.spec.RSAPublicKeySpec
java.security.spec.X509EncodedKeySpec
-java.sql.Timestamp
java.text.AttributedCharacterIterator$Attribute
java.text.CalendarBuilder
java.text.CharacterIterator
-java.text.Collator
java.text.DateFormat
java.text.DateFormat$Field
java.text.DateFormatSymbols
@@ -3371,13 +3340,19 @@ java.text.Normalizer$Form
java.text.NumberFormat
java.text.ParseException
java.text.ParsePosition
-java.text.RuleBasedCollator
java.text.SimpleDateFormat
java.text.StringCharacterIterator
-java.text.spi.DateFormatProvider
-java.text.spi.DateFormatSymbolsProvider
-java.text.spi.DecimalFormatSymbolsProvider
-java.text.spi.NumberFormatProvider
+java.time.DateTimeException
+java.util.-$Lambda$181$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$182$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$183$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$184$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$267$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$268$4EqhxufgNKat19m0CB0-toH_lzo
+java.util.-$Lambda$291$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$292$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$293$aUGKT4ItCOku5-JSG-x8Aqj2pJw
+java.util.-$Lambda$294$aUGKT4ItCOku5-JSG-x8Aqj2pJw
java.util.AbstractCollection
java.util.AbstractList
java.util.AbstractList$Itr
@@ -3397,8 +3372,21 @@ java.util.ArrayList$Itr
java.util.ArrayList$ListItr
java.util.ArrayList$SubList
java.util.ArrayList$SubList$1
+java.util.ArrayPrefixHelpers$CumulateTask
+java.util.ArrayPrefixHelpers$DoubleCumulateTask
+java.util.ArrayPrefixHelpers$IntCumulateTask
+java.util.ArrayPrefixHelpers$LongCumulateTask
java.util.Arrays
java.util.Arrays$ArrayList
+java.util.Arrays$NaturalOrder
+java.util.ArraysParallelSortHelpers$FJByte$Sorter
+java.util.ArraysParallelSortHelpers$FJChar$Sorter
+java.util.ArraysParallelSortHelpers$FJDouble$Sorter
+java.util.ArraysParallelSortHelpers$FJFloat$Sorter
+java.util.ArraysParallelSortHelpers$FJInt$Sorter
+java.util.ArraysParallelSortHelpers$FJLong$Sorter
+java.util.ArraysParallelSortHelpers$FJObject$Sorter
+java.util.ArraysParallelSortHelpers$FJShort$Sorter
java.util.BitSet
java.util.Calendar
java.util.Collection
@@ -3410,6 +3398,9 @@ java.util.Collections$AsLIFOQueue
java.util.Collections$CheckedCollection
java.util.Collections$CheckedList
java.util.Collections$CheckedMap
+java.util.Collections$CheckedNavigableMap
+java.util.Collections$CheckedNavigableSet
+java.util.Collections$CheckedQueue
java.util.Collections$CheckedRandomAccessList
java.util.Collections$CheckedSet
java.util.Collections$CheckedSortedMap
@@ -3430,6 +3421,8 @@ java.util.Collections$SingletonSet
java.util.Collections$SynchronizedCollection
java.util.Collections$SynchronizedList
java.util.Collections$SynchronizedMap
+java.util.Collections$SynchronizedNavigableMap
+java.util.Collections$SynchronizedNavigableSet
java.util.Collections$SynchronizedRandomAccessList
java.util.Collections$SynchronizedSet
java.util.Collections$SynchronizedSortedMap
@@ -3442,18 +3435,16 @@ java.util.Collections$UnmodifiableMap
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry
+java.util.Collections$UnmodifiableNavigableMap
+java.util.Collections$UnmodifiableNavigableMap$EmptyNavigableMap
+java.util.Collections$UnmodifiableNavigableSet
+java.util.Collections$UnmodifiableNavigableSet$EmptyNavigableSet
java.util.Collections$UnmodifiableRandomAccessList
java.util.Collections$UnmodifiableSet
java.util.Collections$UnmodifiableSortedMap
java.util.Collections$UnmodifiableSortedSet
java.util.ComparableTimSort
java.util.Comparator
-java.util.Comparator$-java_util_Comparator_comparingDouble_java_util_function_ToDoubleFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparingInt_java_util_function_ToIntFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparingLong_java_util_function_ToLongFunction_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_java_util_Comparator_keyComparator_LambdaImpl0
-java.util.Comparator$-java_util_Comparator_thenComparing_java_util_Comparator_other_LambdaImpl0
java.util.Comparators$NaturalOrderComparator
java.util.Comparators$NullComparator
java.util.ConcurrentModificationException
@@ -3467,7 +3458,6 @@ java.util.EnumMap$1
java.util.EnumSet
java.util.Enumeration
java.util.EventListener
-java.util.EventObject
java.util.Formattable
java.util.Formatter
java.util.Formatter$Conversion
@@ -3481,14 +3471,14 @@ java.util.HashMap
java.util.HashMap$EntryIterator
java.util.HashMap$EntrySet
java.util.HashMap$HashIterator
-java.util.HashMap$HashMapEntry
java.util.HashMap$KeyIterator
java.util.HashMap$KeySet
+java.util.HashMap$Node
+java.util.HashMap$TreeNode
java.util.HashMap$ValueIterator
java.util.HashMap$Values
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$EntrySet
java.util.Hashtable$Enumerator
java.util.Hashtable$HashtableEntry
java.util.IdentityHashMap
@@ -3498,11 +3488,14 @@ java.util.IllegalFormatException
java.util.IllformedLocaleException
java.util.Iterator
java.util.LinkedHashMap
-java.util.LinkedHashMap$EntryIterator
-java.util.LinkedHashMap$KeyIterator
+java.util.LinkedHashMap$LinkedEntryIterator
+java.util.LinkedHashMap$LinkedEntrySet
java.util.LinkedHashMap$LinkedHashIterator
java.util.LinkedHashMap$LinkedHashMapEntry
-java.util.LinkedHashMap$ValueIterator
+java.util.LinkedHashMap$LinkedKeyIterator
+java.util.LinkedHashMap$LinkedKeySet
+java.util.LinkedHashMap$LinkedValueIterator
+java.util.LinkedHashMap$LinkedValues
java.util.LinkedHashSet
java.util.LinkedList
java.util.LinkedList$ListItr
@@ -3513,6 +3506,8 @@ java.util.Locale
java.util.Locale$Builder
java.util.Locale$Cache
java.util.Locale$Category
+java.util.Locale$FilteringMode
+java.util.Locale$LanguageRange
java.util.Locale$LocaleKey
java.util.Map
java.util.Map$Entry
@@ -3524,30 +3519,16 @@ java.util.Objects
java.util.PrimitiveIterator
java.util.PrimitiveIterator$OfInt
java.util.PriorityQueue
-java.util.PriorityQueue$Itr
java.util.Properties
java.util.Properties$LineReader
-java.util.PropertyResourceBundle
java.util.Queue
java.util.Random
java.util.RandomAccess
java.util.RandomAccessSubList
java.util.RegularEnumSet
-java.util.RegularEnumSet$EnumSetIterator
java.util.ResourceBundle
java.util.ResourceBundle$1
-java.util.ResourceBundle$BundleReference
-java.util.ResourceBundle$CacheKey
-java.util.ResourceBundle$CacheKeyReference
-java.util.ResourceBundle$Control
-java.util.ResourceBundle$Control$1
-java.util.ResourceBundle$Control$CandidateListCache
-java.util.ResourceBundle$LoaderReference
-java.util.ResourceBundle$RBClassLoader
-java.util.ResourceBundle$RBClassLoader$1
-java.util.ServiceLoader
-java.util.ServiceLoader$1
-java.util.ServiceLoader$LazyIterator
+java.util.Scanner
java.util.Set
java.util.SimpleTimeZone
java.util.SortedMap
@@ -3564,12 +3545,11 @@ java.util.Spliterators$EmptySpliterator$OfInt
java.util.Spliterators$EmptySpliterator$OfLong
java.util.Spliterators$EmptySpliterator$OfRef
java.util.Stack
+java.util.StringJoiner
java.util.StringTokenizer
java.util.SubList
java.util.TimSort
java.util.TimeZone
-java.util.Timer
-java.util.TimerTask
java.util.TreeMap
java.util.TreeMap$EntryIterator
java.util.TreeMap$EntrySet
@@ -3591,31 +3571,69 @@ java.util.WeakHashMap$HashIterator
java.util.WeakHashMap$KeyIterator
java.util.WeakHashMap$KeySet
java.util.WeakHashMap$Values
+java.util.concurrent.-$Lambda$269$xR9BLpu6SifNikvFgr4lEiECBsk
java.util.concurrent.AbstractExecutorService
java.util.concurrent.BlockingQueue
java.util.concurrent.Callable
java.util.concurrent.CancellationException
java.util.concurrent.ConcurrentHashMap
java.util.concurrent.ConcurrentHashMap$BaseIterator
+java.util.concurrent.ConcurrentHashMap$BulkTask
java.util.concurrent.ConcurrentHashMap$CollectionView
+java.util.concurrent.ConcurrentHashMap$CounterCell
java.util.concurrent.ConcurrentHashMap$EntryIterator
java.util.concurrent.ConcurrentHashMap$EntrySetView
+java.util.concurrent.ConcurrentHashMap$ForEachEntryTask
+java.util.concurrent.ConcurrentHashMap$ForEachKeyTask
+java.util.concurrent.ConcurrentHashMap$ForEachMappingTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedEntryTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedKeyTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedMappingTask
+java.util.concurrent.ConcurrentHashMap$ForEachTransformedValueTask
+java.util.concurrent.ConcurrentHashMap$ForEachValueTask
java.util.concurrent.ConcurrentHashMap$ForwardingNode
java.util.concurrent.ConcurrentHashMap$KeyIterator
java.util.concurrent.ConcurrentHashMap$KeySetView
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceEntriesToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceKeysToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceMappingsToLongTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToDoubleTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToIntTask
+java.util.concurrent.ConcurrentHashMap$MapReduceValuesToLongTask
java.util.concurrent.ConcurrentHashMap$Node
+java.util.concurrent.ConcurrentHashMap$ReduceEntriesTask
+java.util.concurrent.ConcurrentHashMap$ReduceKeysTask
+java.util.concurrent.ConcurrentHashMap$ReduceValuesTask
+java.util.concurrent.ConcurrentHashMap$ReservationNode
+java.util.concurrent.ConcurrentHashMap$SearchEntriesTask
+java.util.concurrent.ConcurrentHashMap$SearchKeysTask
+java.util.concurrent.ConcurrentHashMap$SearchMappingsTask
+java.util.concurrent.ConcurrentHashMap$SearchValuesTask
java.util.concurrent.ConcurrentHashMap$Segment
java.util.concurrent.ConcurrentHashMap$Traverser
java.util.concurrent.ConcurrentHashMap$TreeBin
java.util.concurrent.ConcurrentHashMap$TreeNode
+java.util.concurrent.ConcurrentHashMap$ValueIterator
+java.util.concurrent.ConcurrentHashMap$ValuesView
java.util.concurrent.ConcurrentLinkedQueue
java.util.concurrent.ConcurrentLinkedQueue$Node
java.util.concurrent.ConcurrentMap
java.util.concurrent.CopyOnWriteArrayList
-java.util.concurrent.CopyOnWriteArrayList$CowIterator
+java.util.concurrent.CopyOnWriteArrayList$COWIterator
java.util.concurrent.CopyOnWriteArraySet
java.util.concurrent.CountDownLatch
java.util.concurrent.CountDownLatch$Sync
+java.util.concurrent.CountedCompleter
java.util.concurrent.Delayed
java.util.concurrent.ExecutionException
java.util.concurrent.Executor
@@ -3626,6 +3644,9 @@ java.util.concurrent.Executors$DelegatedExecutorService
java.util.concurrent.Executors$DelegatedScheduledExecutorService
java.util.concurrent.Executors$FinalizableDelegatedExecutorService
java.util.concurrent.Executors$RunnableAdapter
+java.util.concurrent.ForkJoinPool
+java.util.concurrent.ForkJoinTask
+java.util.concurrent.ForkJoinTask$ExceptionNode
java.util.concurrent.Future
java.util.concurrent.FutureTask
java.util.concurrent.FutureTask$WaitNode
@@ -3649,6 +3670,7 @@ java.util.concurrent.SynchronousQueue$TransferStack
java.util.concurrent.SynchronousQueue$TransferStack$SNode
java.util.concurrent.SynchronousQueue$Transferer
java.util.concurrent.ThreadFactory
+java.util.concurrent.ThreadLocalRandom
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.ThreadPoolExecutor$AbortPolicy
java.util.concurrent.ThreadPoolExecutor$Worker
@@ -3684,19 +3706,33 @@ java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock
java.util.concurrent.locks.ReentrantReadWriteLock$Sync
java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
+java.util.function.-$Lambda$276$1MZdIZ-DL_fjy9l0o8IMJk57T2g
java.util.function.BiConsumer
java.util.function.BiFunction
+java.util.function.BinaryOperator
java.util.function.Consumer
+java.util.function.DoubleBinaryOperator
java.util.function.Function
+java.util.function.IntBinaryOperator
+java.util.function.IntConsumer
+java.util.function.IntFunction
+java.util.function.IntToDoubleFunction
+java.util.function.IntToLongFunction
+java.util.function.IntUnaryOperator
+java.util.function.LongBinaryOperator
+java.util.function.LongUnaryOperator
java.util.function.Predicate
java.util.function.Supplier
+java.util.function.ToDoubleBiFunction
java.util.function.ToDoubleFunction
+java.util.function.ToIntBiFunction
java.util.function.ToIntFunction
+java.util.function.ToLongBiFunction
java.util.function.ToLongFunction
java.util.function.UnaryOperator
java.util.jar.JarEntry
java.util.jar.JarFile
-java.util.jar.JarFile$1
+java.util.jar.JarFile$JarEntryIterator
java.util.jar.JarFile$JarFileEntry
java.util.logging.ErrorManager
java.util.logging.Formatter
@@ -3706,7 +3742,8 @@ java.util.logging.Level$KnownLevel
java.util.logging.LogManager
java.util.logging.LogManager$1
java.util.logging.LogManager$2
-java.util.logging.LogManager$4
+java.util.logging.LogManager$3
+java.util.logging.LogManager$5
java.util.logging.LogManager$Cleaner
java.util.logging.LogManager$LogNode
java.util.logging.LogManager$LoggerContext
@@ -3714,8 +3751,8 @@ java.util.logging.LogManager$LoggerContext$1
java.util.logging.LogManager$LoggerWeakRef
java.util.logging.LogManager$RootLogger
java.util.logging.LogManager$SystemLoggerContext
-java.util.logging.LogRecord
java.util.logging.Logger
+java.util.logging.Logger$LoggerBundle
java.util.logging.LoggingPermission
java.util.logging.LoggingProxyImpl
java.util.prefs.AbstractPreferences
@@ -3725,9 +3762,10 @@ java.util.regex.MatchResult
java.util.regex.Matcher
java.util.regex.Pattern
java.util.regex.PatternSyntaxException
-java.util.spi.LocaleServiceProvider
java.util.stream.BaseStream
+java.util.stream.DoubleStream
java.util.stream.IntStream
+java.util.stream.LongStream
java.util.stream.Stream
java.util.stream.StreamSupport
java.util.zip.Adler32
@@ -3746,24 +3784,15 @@ java.util.zip.ZipCoder
java.util.zip.ZipConstants
java.util.zip.ZipEntry
java.util.zip.ZipFile
-java.util.zip.ZipFile$1
+java.util.zip.ZipFile$ZipEntryIterator
java.util.zip.ZipFile$ZipFileInflaterInputStream
java.util.zip.ZipFile$ZipFileInputStream
+java.util.zip.ZipUtils
javax.crypto.BadPaddingException
javax.crypto.Cipher
-javax.crypto.Cipher$CipherSpiAndProvider
-javax.crypto.Cipher$InitParams
-javax.crypto.Cipher$InitType
-javax.crypto.Cipher$NeedToSet
-javax.crypto.Cipher$SpiAndProviderUpdater
-javax.crypto.Cipher$Transform
-javax.crypto.CipherSpi
javax.crypto.IllegalBlockSizeException
-javax.crypto.JceSecurity
javax.crypto.NoSuchPaddingException
-javax.crypto.NullCipher
javax.crypto.SecretKey
-javax.crypto.ShortBufferException
javax.crypto.spec.IvParameterSpec
javax.crypto.spec.SecretKeySpec
javax.microedition.khronos.egl.EGL
@@ -3799,7 +3828,6 @@ javax.net.ssl.SSLSession
javax.net.ssl.SSLSessionContext
javax.net.ssl.SSLSocket
javax.net.ssl.SSLSocketFactory
-javax.net.ssl.SSLSocketFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.TrustManagerFactory$1
@@ -3808,13 +3836,12 @@ javax.net.ssl.X509ExtendedKeyManager
javax.net.ssl.X509ExtendedTrustManager
javax.net.ssl.X509KeyManager
javax.net.ssl.X509TrustManager
+javax.security.auth.Destroyable
javax.security.auth.callback.UnsupportedCallbackException
javax.security.auth.x500.X500Principal
javax.security.cert.Certificate
javax.security.cert.CertificateException
javax.security.cert.X509Certificate
-libcore.icu.DateIntervalFormat
-libcore.icu.DateUtilsBridge
libcore.icu.ICU
libcore.icu.LocaleData
libcore.icu.NativeConverter
@@ -3834,8 +3861,9 @@ libcore.io.EventLogger$DefaultReporter
libcore.io.EventLogger$Reporter
libcore.io.ForwardingOs
libcore.io.IoBridge
+libcore.io.IoTracker
+libcore.io.IoTracker$Mode
libcore.io.IoUtils
-libcore.io.IoUtils$FileReader
libcore.io.Libcore
libcore.io.Memory
libcore.io.MemoryMappedFile
@@ -3854,8 +3882,6 @@ libcore.reflect.AnnotationMember$DefaultValues
libcore.reflect.GenericSignatureParser
libcore.reflect.InternalNames
libcore.reflect.ListOfTypes
-libcore.reflect.ListOfVariables
-libcore.reflect.ParameterizedTypeImpl
libcore.reflect.Types
libcore.util.BasicLruCache
libcore.util.CharsetUtils
@@ -3865,8 +3891,6 @@ libcore.util.NativeAllocationRegistry
libcore.util.NativeAllocationRegistry$CleanerRunner
libcore.util.NativeAllocationRegistry$CleanerThunk
libcore.util.ZoneInfo
-libcore.util.ZoneInfo$CheckedArithmeticException
-libcore.util.ZoneInfo$WallTime
libcore.util.ZoneInfoDB
libcore.util.ZoneInfoDB$TzData
libcore.util.ZoneInfoDB$TzData$1
@@ -3879,54 +3903,22 @@ org.apache.harmony.luni.internal.util.TimezoneGetter
org.apache.harmony.xml.ExpatAttributes
org.apache.harmony.xml.ExpatParser
org.apache.http.Header
-org.apache.http.HeaderIterator
org.apache.http.HttpEntity
org.apache.http.HttpEntityEnclosingRequest
-org.apache.http.HttpHost
org.apache.http.HttpMessage
org.apache.http.HttpRequest
org.apache.http.HttpResponse
-org.apache.http.HttpVersion
-org.apache.http.NameValuePair
org.apache.http.ProtocolVersion
org.apache.http.StatusLine
org.apache.http.client.HttpClient
-org.apache.http.client.ResponseHandler
-org.apache.http.client.methods.AbortableHttpRequest
-org.apache.http.client.methods.HttpEntityEnclosingRequestBase
-org.apache.http.client.methods.HttpPost
-org.apache.http.client.methods.HttpRequestBase
org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.utils.URLEncodedUtils
-org.apache.http.conn.ClientConnectionManager
org.apache.http.conn.ConnectTimeoutException
org.apache.http.entity.AbstractHttpEntity
-org.apache.http.entity.BasicHttpEntity
-org.apache.http.impl.cookie.DateParseException
-org.apache.http.impl.cookie.DateUtils
org.apache.http.message.AbstractHttpMessage
org.apache.http.message.BasicHeader
org.apache.http.message.BasicHttpResponse
org.apache.http.message.BasicStatusLine
org.apache.http.message.HeaderGroup
-org.apache.http.params.AbstractHttpParams
-org.apache.http.params.BasicHttpParams
-org.apache.http.params.CoreConnectionPNames
-org.apache.http.params.HttpConnectionParams
-org.apache.http.params.HttpParams
-org.apache.http.protocol.HttpContext
-org.ccil.cowan.tagsoup.AttributesImpl
-org.ccil.cowan.tagsoup.AutoDetector
-org.ccil.cowan.tagsoup.Element
-org.ccil.cowan.tagsoup.ElementType
-org.ccil.cowan.tagsoup.HTMLModels
-org.ccil.cowan.tagsoup.HTMLScanner
-org.ccil.cowan.tagsoup.HTMLSchema
-org.ccil.cowan.tagsoup.Parser
-org.ccil.cowan.tagsoup.Parser$1
-org.ccil.cowan.tagsoup.ScanHandler
-org.ccil.cowan.tagsoup.Scanner
-org.ccil.cowan.tagsoup.Schema
org.json.JSON
org.json.JSONArray
org.json.JSONException
@@ -3938,31 +3930,30 @@ org.json.JSONTokener
org.kxml2.io.KXmlParser
org.kxml2.io.KXmlParser$ValueContext
org.xml.sax.Attributes
-org.xml.sax.ContentHandler
-org.xml.sax.DTDHandler
-org.xml.sax.EntityResolver
-org.xml.sax.ErrorHandler
-org.xml.sax.InputSource
-org.xml.sax.Locator
org.xml.sax.SAXException
-org.xml.sax.SAXNotRecognizedException
-org.xml.sax.SAXNotSupportedException
-org.xml.sax.XMLReader
-org.xml.sax.ext.LexicalHandler
-org.xml.sax.helpers.DefaultHandler
org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserException
org.xmlpull.v1.XmlSerializer
+sun.invoke.util.BytecodeDescriptor
+sun.invoke.util.Wrapper
sun.misc.Cleaner
sun.misc.CompoundEnumeration
+sun.misc.FDBigInteger
+sun.misc.FloatingDecimal
+sun.misc.FloatingDecimal$1
+sun.misc.FloatingDecimal$ASCIIToBinaryBuffer
+sun.misc.FloatingDecimal$ASCIIToBinaryConverter
+sun.misc.FloatingDecimal$BinaryToASCIIBuffer
+sun.misc.FloatingDecimal$BinaryToASCIIConverter
+sun.misc.FloatingDecimal$ExceptionalBinaryToASCIIBuffer
+sun.misc.FloatingDecimal$PreparedASCIIToBinaryBuffer
sun.misc.FormattedFloatingDecimal
sun.misc.FormattedFloatingDecimal$1
sun.misc.FormattedFloatingDecimal$Form
-sun.misc.FpUtils
-sun.misc.Hashing
sun.misc.IOUtils
-sun.misc.IoTrace
+sun.misc.JavaIOFileDescriptorAccess
sun.misc.REException
+sun.misc.SharedSecrets
sun.misc.Unsafe
sun.misc.VM
sun.misc.Version
@@ -3978,10 +3969,10 @@ sun.net.util.IPAddressUtil
sun.net.www.ParseUtil
sun.net.www.protocol.file.Handler
sun.net.www.protocol.jar.Handler
-sun.nio.ch.AbstractPollArrayWrapper
sun.nio.ch.DatagramChannelImpl
sun.nio.ch.DatagramDispatcher
sun.nio.ch.DirectBuffer
+sun.nio.ch.EPollArrayWrapper
sun.nio.ch.FileChannelImpl
sun.nio.ch.FileChannelImpl$Unmapper
sun.nio.ch.FileDispatcher
@@ -3991,13 +3982,11 @@ sun.nio.ch.FileLockImpl
sun.nio.ch.FileLockTable
sun.nio.ch.IOStatus
sun.nio.ch.IOUtil
-sun.nio.ch.InheritedChannel
sun.nio.ch.Interruptible
sun.nio.ch.NativeDispatcher
sun.nio.ch.NativeThread
sun.nio.ch.NativeThreadSet
sun.nio.ch.Net
-sun.nio.ch.PollArrayWrapper
sun.nio.ch.SelChImpl
sun.nio.ch.ServerSocketChannelImpl
sun.nio.ch.SharedFileLockTable
@@ -4006,14 +3995,8 @@ sun.nio.ch.SocketChannelImpl
sun.nio.cs.ArrayEncoder
sun.nio.cs.StreamDecoder
sun.nio.cs.StreamEncoder
-sun.reflect.annotation.AnnotationType
sun.security.action.GetBooleanAction
sun.security.action.GetPropertyAction
-sun.security.ec.ECKeyFactory
-sun.security.ec.ECKeyFactory$1
-sun.security.ec.ECKeyFactory$2
-sun.security.ec.ECParameters
-sun.security.ec.NamedCurve
sun.security.jca.GetInstance
sun.security.jca.GetInstance$Instance
sun.security.jca.ProviderConfig
@@ -4027,7 +4010,6 @@ sun.security.jca.ProviderList$ServiceList$1
sun.security.jca.Providers
sun.security.jca.ServiceId
sun.security.pkcs.PKCS9Attribute
-sun.security.pkcs.ParsingException
sun.security.pkcs.SignerInfo
sun.security.provider.CertPathProvider
sun.security.provider.X509Factory
@@ -4043,7 +4025,9 @@ sun.security.provider.certpath.PKIXCertPathValidator
sun.security.provider.certpath.PKIXMasterCertPathValidator
sun.security.provider.certpath.PolicyChecker
sun.security.provider.certpath.PolicyNodeImpl
-sun.security.provider.certpath.UntrustedChecker
+sun.security.util.-$Lambda$179$Kli5xKA4dAwmFO1sy_hpNWmbfH4
+sun.security.util.AbstractAlgorithmConstraints
+sun.security.util.AlgorithmDecomposer
sun.security.util.BitArray
sun.security.util.ByteArrayLexOrder
sun.security.util.ByteArrayTagOrder
@@ -4057,7 +4041,6 @@ sun.security.util.DerInputStream
sun.security.util.DerOutputStream
sun.security.util.DerValue
sun.security.util.DisabledAlgorithmConstraints
-sun.security.util.DisabledAlgorithmConstraints$1
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint$Operator
sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraints
@@ -4067,7 +4050,6 @@ sun.security.util.MemoryCache
sun.security.util.MemoryCache$CacheEntry
sun.security.util.MemoryCache$SoftCacheEntry
sun.security.util.ObjectIdentifier
-sun.security.util.UntrustedCertificates
sun.security.x509.AVA
sun.security.x509.AVAKeyword
sun.security.x509.AccessDescription
@@ -4124,8 +4106,6 @@ sun.security.x509.X509AttributeName
sun.security.x509.X509CertImpl
sun.security.x509.X509CertInfo
sun.security.x509.X509Key
-sun.util.LocaleServiceProviderPool
-sun.util.LocaleServiceProviderPool$1
sun.util.calendar.AbstractCalendar
sun.util.calendar.BaseCalendar
sun.util.calendar.BaseCalendar$Date
@@ -4139,18 +4119,15 @@ sun.util.calendar.LocalGregorianCalendar
sun.util.locale.BaseLocale
sun.util.locale.BaseLocale$Cache
sun.util.locale.BaseLocale$Key
-sun.util.locale.Extension
sun.util.locale.InternalLocaleBuilder
sun.util.locale.InternalLocaleBuilder$CaseInsensitiveChar
sun.util.locale.LanguageTag
-sun.util.locale.LocaleExtensions
sun.util.locale.LocaleObjectCache
sun.util.locale.LocaleObjectCache$CacheEntry
sun.util.locale.LocaleSyntaxException
sun.util.locale.LocaleUtils
sun.util.locale.ParseStatus
sun.util.locale.StringTokenIterator
-sun.util.locale.UnicodeLocaleExtension
sun.util.logging.LoggingProxy
sun.util.logging.LoggingSupport
sun.util.logging.LoggingSupport$1
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 341438d2c0f9..a590805cf745 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3275,9 +3275,8 @@ message MetricsEvent {
// OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
-
- // OPEN: Settings > Apps > Default Apps > Default auto-fill app
- DEFAULT_AUTO_FILL_PICKER = 792;
+ // OPEN: Settings > Apps > Default Apps > Default autofill app
+ DEFAULT_AUTOFILL_PICKER = 792;
// These values should never appear in log outputs - they are reserved for
// internal Tron use.
@@ -3331,6 +3330,64 @@ message MetricsEvent {
// ACTION: Deny "Enable picture-in-picture on hide" for an app
APP_PICTURE_IN_PICTURE_ON_HIDE_DENY = 814;
+ // OPEN: Settings > Language & input > Text-to-speech output -> Speech rate & pitch
+ // CATEGORY: SETTINGS
+ // OS: 8.0
+ TTS_SLIDERS = 815;
+
+ // ACTION: Settings -> Display -> Theme
+ ACTION_THEME = 816;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings -> Select to Speak
+ // ACTION: Select to Speak configuration is chosen
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK = 817;
+
+ // OPEN: Settings > System > Backup
+ // CATEGORY: SETTINGS
+ // OS: O
+ BACKUP_SETTINGS = 818;
+
+ // ACTION: Picture-in-picture was explicitly entered for an activity
+ // VALUE: true if it was entered while hiding as a result of moving to
+ // another task, false otherwise
+ ACTION_PICTURE_IN_PICTURE_ENTERED = 819;
+
+ // ACTION: The activity currently in picture-in-picture was expanded back to fullscreen
+ // PACKAGE: The package name of the activity that was expanded back to fullscreen
+ ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820;
+
+ // ACTION: The activity currently in picture-in-picture was minimized
+ // VALUE: True if the PiP was minimized, false otherwise
+ ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821;
+
+ // ACTION: Picture-in-picture was dismissed via the dismiss button
+ // VALUE: 0 if dismissed by tap, 1 if dismissed by drag
+ ACTION_PICTURE_IN_PICTURE_DISMISSED = 822;
+
+ // ACTION: The visibility of the picture-in-picture meny
+ // VALUE: Whether or not the menu is visible
+ ACTION_PICTURE_IN_PICTURE_MENU = 823;
+
+ // Enclosing category for group of PICTURE_IN_PICTURE_ASPECT_RATIO_FOO events,
+ // logged when the aspect ratio changes
+ ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824;
+
+ // The current aspect ratio of the PiP, logged when it changes.
+ PICTURE_IN_PICTURE_ASPECT_RATIO = 825;
+
+ // FIELD - length in dp of ACTION_LS_* gestures, or zero if not applicable
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O
+ FIELD_GESTURE_LENGTH = 826;
+
+ // FIELD - velocity in dp (per second?) of ACTION_LS_* gestures, or zero if not applicable
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O
+ FIELD_GESTURE_VELOCITY = 827;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
index c04191bb095d..49a71b430ac6 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -2441,10 +2441,10 @@ public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
* @param TransA The type of transpose applied to matrix A.
* @param TransB The type of transpose applied to matrix B.
* @param alpha The scalar alpha.
- * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2
- * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2
+ * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+ * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
* @param beta The scalar beta.
- * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2
+ * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
*/
public void ZGEMM(@Transpose int TransA, @Transpose int TransB, Double2 alpha, Allocation A,
Allocation B, Double2 beta, Allocation C) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index 582b19b62c22..b95d2e689873 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -16,19 +16,18 @@
package com.android.server.accessibility;
+import android.accessibilityservice.AccessibilityService;
import android.content.Context;
import android.gesture.Gesture;
-import android.gesture.GestureLibraries;
-import android.gesture.GestureLibrary;
import android.gesture.GesturePoint;
import android.gesture.GestureStore;
import android.gesture.GestureStroke;
import android.gesture.Prediction;
+import android.graphics.PointF;
import android.util.Slog;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.R;
@@ -47,6 +46,49 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
// Tag for logging received events.
private static final String LOG_TAG = "AccessibilityGestureDetector";
+ // Constants for sampling motion event points.
+ // We sample based on a minimum distance between points, primarily to improve accuracy by
+ // reducing noisy minor changes in direction.
+ private static final float MIN_INCHES_BETWEEN_SAMPLES = 0.1f;
+ private final float mMinPixelsBetweenSamplesX;
+ private final float mMinPixelsBetweenSamplesY;
+
+ // Constants for separating gesture segments
+ private static final float ANGLE_THRESHOLD = 0.0f;
+
+ // Constants for line segment directions
+ private static final int LEFT = 0;
+ private static final int RIGHT = 1;
+ private static final int UP = 2;
+ private static final int DOWN = 3;
+ private static final int[][] DIRECTIONS_TO_GESTURE_ID = {
+ {
+ AccessibilityService.GESTURE_SWIPE_LEFT,
+ AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT,
+ AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP,
+ AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN
+ },
+ {
+ AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT,
+ AccessibilityService.GESTURE_SWIPE_RIGHT,
+ AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP,
+ AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN
+ },
+ {
+ AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT,
+ AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT,
+ AccessibilityService.GESTURE_SWIPE_UP,
+ AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN
+ },
+ {
+ AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT,
+ AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT,
+ AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP,
+ AccessibilityService.GESTURE_SWIPE_DOWN
+ }
+ };
+
+
/**
* Listener functions are called as a result of onMoveEvent(). The current
* MotionEvent in the context of these functions is the event passed into
@@ -102,10 +144,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
}
private final Listener mListener;
- private final GestureDetector mGestureDetector;
-
- // The library for gesture detection.
- private final GestureLibrary mGestureLibrary;
+ private final Context mContext; // Retained for on-demand construction of GestureDetector.
+ protected GestureDetector mGestureDetector; // Double-tap detector. Visible for test.
// Indicates that a single tap has occurred.
private boolean mFirstTapDetected;
@@ -168,28 +208,26 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
// movement when gesturing, and touch exploring. Based on user testing,
// all gestures started with the initial movement taking less than 100ms.
// When touch exploring, the first movement almost always takes longer than
- // 200ms. From this data, 200ms seems the best value to decide what
- // kind of interaction it is.
- private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 200;
+ // 200ms.
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
// Time threshold used to determine if a gesture should be cancelled. If
- // the finger pauses for longer than this delay, the ongoing gesture is
+ // the finger takes more than this time to move 1cm, the ongoing gesture is
// cancelled.
- private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 500;
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
AccessibilityGestureDetector(Context context, Listener listener) {
mListener = listener;
-
- mGestureDetector = new GestureDetector(context, this);
- mGestureDetector.setOnDoubleTapListener(this);
-
- mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
- mGestureLibrary.setOrientationStyle(8 /* GestureStore.ORIENTATION_SENSITIVE_8 */);
- mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE);
- mGestureLibrary.load();
+ mContext = context;
mGestureDetectionThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
context.getResources().getDisplayMetrics()) * GESTURE_CONFIRM_MM;
+
+ // Calculate minimum gesture velocity
+ final float pixelsPerInchX = context.getResources().getDisplayMetrics().xdpi;
+ final float pixelsPerInchY = context.getResources().getDisplayMetrics().ydpi;
+ mMinPixelsBetweenSamplesX = MIN_INCHES_BETWEEN_SAMPLES * pixelsPerInchX;
+ mMinPixelsBetweenSamplesY = MIN_INCHES_BETWEEN_SAMPLES * pixelsPerInchY;
}
/**
@@ -205,6 +243,18 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
* @return true if the event is consumed, else false
*/
public boolean onMotionEvent(MotionEvent event, int policyFlags) {
+
+ // Construct GestureDetector double-tap detector on demand, so that testable sub-class
+ // can use mock GestureDetector.
+ // TODO: Break the circular dependency between GestureDetector's constructor and
+ // AccessibilityGestureDetector's constructor. Construct GestureDetector in TouchExplorer,
+ // using a GestureDetector listener owned by TouchExplorer, which passes double-tap state
+ // information to AccessibilityGestureDetector.
+ if (mGestureDetector == null) {
+ mGestureDetector = new GestureDetector(mContext, this);
+ mGestureDetector.setOnDoubleTapListener(this);
+ }
+
final float x = event.getX();
final float y = event.getY();
final long time = event.getEventTime();
@@ -267,7 +317,7 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
final float dX = Math.abs(x - mPreviousGestureX);
final float dY = Math.abs(y - mPreviousGestureY);
- if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) {
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
mPreviousGestureX = x;
mPreviousGestureY = y;
mStrokeBuffer.add(new GesturePoint(x, y, time));
@@ -280,8 +330,11 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
return finishDoubleTap(event, policyFlags);
}
if (mGestureStarted) {
- mStrokeBuffer.add(new GesturePoint(x, y, time));
-
+ final float dX = Math.abs(x - mPreviousGestureX);
+ final float dY = Math.abs(y - mPreviousGestureY);
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ mStrokeBuffer.add(new GesturePoint(x, y, time));
+ }
return recognizeGesture(event, policyFlags);
}
break;
@@ -397,30 +450,154 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
mStrokeBuffer.clear();
}
+ /**
+ * Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then calls
+ * Listener callbacks for success or failure.
+ *
+ * @param event The raw motion event to pass to the listener callbacks.
+ * @param policyFlags Policy flags for the event.
+ *
+ * @return true if the event is consumed, else false
+ */
private boolean recognizeGesture(MotionEvent event, int policyFlags) {
- Gesture gesture = new Gesture();
- gesture.addStroke(new GestureStroke(mStrokeBuffer));
-
- ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture);
- if (!predictions.isEmpty()) {
- Prediction bestPrediction = predictions.get(0);
- if (bestPrediction.score >= MIN_PREDICTION_SCORE) {
- if (DEBUG) {
- Slog.i(LOG_TAG, "gesture: " + bestPrediction.name + " score: "
- + bestPrediction.score);
- }
- try {
- final int gestureId = Integer.parseInt(bestPrediction.name);
- return mListener.onGestureCompleted(gestureId);
- } catch (NumberFormatException nfe) {
- Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
+ if (mStrokeBuffer.size() < 2) {
+ return mListener.onGestureCancelled(event, policyFlags);
+ }
+
+ // Look at mStrokeBuffer and extract 2 line segments, delimited by near-perpendicular
+ // direction change.
+ // Method: for each sampled motion event, check the angle of the most recent motion vector
+ // versus the preceding motion vector, and segment the line if the angle is about
+ // 90 degrees.
+
+ ArrayList<PointF> path = new ArrayList<>();
+ PointF lastDelimiter = new PointF(mStrokeBuffer.get(0).x, mStrokeBuffer.get(0).y);
+ path.add(lastDelimiter);
+
+ float dX = 0; // Sum of unit vectors from last delimiter to each following point
+ float dY = 0;
+ int count = 0; // Number of points since last delimiter
+ float length = 0; // Vector length from delimiter to most recent point
+
+ PointF next = new PointF();
+ for (int i = 1; i < mStrokeBuffer.size(); ++i) {
+ next = new PointF(mStrokeBuffer.get(i).x, mStrokeBuffer.get(i).y);
+ if (count > 0) {
+ // Average of unit vectors from delimiter to following points
+ float currentDX = dX / count;
+ float currentDY = dY / count;
+
+ // newDelimiter is a possible new delimiter, based on a vector with length from
+ // the last delimiter to the previous point, but in the direction of the average
+ // unit vector from delimiter to previous points.
+ // Using the averaged vector has the effect of "squaring off the curve",
+ // creating a sharper angle between the last motion and the preceding motion from
+ // the delimiter. In turn, this sharper angle achieves the splitting threshold
+ // even in a gentle curve.
+ PointF newDelimiter = new PointF(length * currentDX + lastDelimiter.x,
+ length * currentDY + lastDelimiter.y);
+
+ // Unit vector from newDelimiter to the most recent point
+ float nextDX = next.x - newDelimiter.x;
+ float nextDY = next.y - newDelimiter.y;
+ float nextLength = (float) Math.sqrt(nextDX * nextDX + nextDY * nextDY);
+ nextDX = nextDX / nextLength;
+ nextDY = nextDY / nextLength;
+
+ // Compare the initial motion direction to the most recent motion direction,
+ // and segment the line if direction has changed by about 90 degrees.
+ float dot = currentDX * nextDX + currentDY * nextDY;
+ if (dot < ANGLE_THRESHOLD) {
+ path.add(newDelimiter);
+ lastDelimiter = newDelimiter;
+ dX = 0;
+ dY = 0;
+ count = 0;
}
}
+
+ // Vector from last delimiter to most recent point
+ float currentDX = next.x - lastDelimiter.x;
+ float currentDY = next.y - lastDelimiter.y;
+ length = (float) Math.sqrt(currentDX * currentDX + currentDY * currentDY);
+
+ // Increment sum of unit vectors from delimiter to each following point
+ count = count + 1;
+ dX = dX + currentDX / length;
+ dY = dY + currentDY / length;
}
+ path.add(next);
+ Slog.i(LOG_TAG, "path=" + path.toString());
+
+ // Classify line segments, and call Listener callbacks.
+ return recognizeGesturePath(event, policyFlags, path);
+ }
+
+ /**
+ * Classifies a pair of line segments, by direction.
+ * Calls Listener callbacks for success or failure.
+ *
+ * @param event The raw motion event to pass to the listener's onGestureCanceled method.
+ * @param policyFlags Policy flags for the event.
+ * @param path A sequence of motion line segments derived from motion points in mStrokeBuffer.
+ *
+ * @return true if the event is consumed, else false
+ */
+ private boolean recognizeGesturePath(MotionEvent event, int policyFlags,
+ ArrayList<PointF> path) {
+
+ if (path.size() == 2) {
+ PointF start = path.get(0);
+ PointF end = path.get(1);
+
+ float dX = end.x - start.x;
+ float dY = end.y - start.y;
+ int direction = toDirection(dX, dY);
+ switch (direction) {
+ case LEFT:
+ return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_LEFT);
+ case RIGHT:
+ return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_RIGHT);
+ case UP:
+ return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_UP);
+ case DOWN:
+ return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_DOWN);
+ default:
+ // Do nothing.
+ }
+
+ } else if (path.size() == 3) {
+ PointF start = path.get(0);
+ PointF mid = path.get(1);
+ PointF end = path.get(2);
+
+ float dX0 = mid.x - start.x;
+ float dY0 = mid.y - start.y;
+
+ float dX1 = end.x - mid.x;
+ float dY1 = end.y - mid.y;
+
+ int segmentDirection0 = toDirection(dX0, dY0);
+ int segmentDirection1 = toDirection(dX1, dY1);
+ int gestureId = DIRECTIONS_TO_GESTURE_ID[segmentDirection0][segmentDirection1];
+ return mListener.onGestureCompleted(gestureId);
+ }
+ // else if (path.size() < 2 || 3 < path.size()) then no gesture recognized.
return mListener.onGestureCancelled(event, policyFlags);
}
+ /** Maps a vector to a dominant direction in set {LEFT, RIGHT, UP, DOWN}. */
+ private static int toDirection(float dX, float dY) {
+ if (Math.abs(dX) > Math.abs(dY)) {
+ // Horizontal
+ return (dX < 0) ? LEFT : RIGHT;
+ } else {
+ // Vertical
+ return (dY < 0) ? UP : DOWN;
+ }
+ }
+
private MotionEvent mapSecondPointerToFirstPointer(MotionEvent event) {
// Only map basic events when two fingers are down.
if (event.getPointerCount() != 2 ||
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ece51494ef32..aae5dd83723a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -63,11 +63,15 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
+import android.hardware.fingerprint.IFingerprintService;
+import android.provider.SettingsStringUtil.ComponentNameSet;
+import android.provider.SettingsStringUtil.SettingStringHelper;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.Slog;
@@ -96,9 +100,9 @@ import com.android.internal.R;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.SomeArgs;
import com.android.server.LocalServices;
-
import com.android.server.policy.AccessibilityShortcutController;
import com.android.server.statusbar.StatusBarManagerInternal;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -203,6 +207,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private MotionEventInjector mMotionEventInjector;
+ private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
+
private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
@@ -441,7 +447,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
return userState.getClientState();
} else {
- userState.mClients.register(client);
+ userState.mUserClients.register(client);
// If this client is not for the current user we do not
// return a state since it is not for the foreground user.
// We will send the state to the client on a user switch.
@@ -809,6 +815,42 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ /**
+ * Invoked remotely over AIDL by SysUi when the accessibility button within the system's
+ * navigation area has been clicked.
+ */
+ @Override
+ public void notifyAccessibilityButtonClicked() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
+ synchronized (mLock) {
+ notifyAccessibilityButtonClickedLocked();
+ }
+ }
+
+ /**
+ * Invoked remotely over AIDL by SysUi when the availability of the accessibility
+ * button within the system's navigation area has changed.
+ *
+ * @param available {@code true} if the accessibility button is available to the
+ * user, {@code false} otherwise
+ */
+ @Override
+ public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
+ synchronized (mLock) {
+ notifyAccessibilityButtonAvailabilityChangedLocked(available);
+ }
+ }
+
+
boolean onGesture(int gestureId) {
synchronized (mLock) {
boolean handled = notifyGestureLocked(gestureId, false);
@@ -923,7 +965,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
oldUserState.onSwitchToAnotherUser();
// Disable the local managers for the old user.
- if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
+ if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
oldUserState.mUserId, 0).sendToTarget();
}
@@ -1040,6 +1082,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private void notifyAccessibilityButtonClickedLocked() {
+ final UserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ final Service service = state.mBoundServices.get(i);
+ // TODO(b/34720082): Only notify a single user-defined service
+ if (service.mRequestAccessibilityButton) {
+ service.notifyAccessibilityButtonClickedLocked();
+ }
+ }
+ }
+
+ private void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+ final UserState state = getCurrentUserStateLocked();
+ state.mIsAccessibilityButtonAvailable = available;
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ final Service service = state.mBoundServices.get(i);
+ if (service.mRequestAccessibilityButton) {
+ service.notifyAccessibilityButtonAvailabilityChangedLocked(available);
+ }
+ }
+ }
+
/**
* Removes an AccessibilityInteractionConnection.
*
@@ -1174,7 +1238,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
service.onAdded();
userState.mBoundServices.add(service);
userState.mComponentNameToServiceMap.put(service.mComponentName, service);
- scheduleNotifyClientsOfServicesStateChange();
+ scheduleNotifyClientsOfServicesStateChange(userState);
}
} catch (RemoteException re) {
/* do nothing */
@@ -1196,7 +1260,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
Service boundService = userState.mBoundServices.get(i);
userState.mComponentNameToServiceMap.put(boundService.mComponentName, boundService);
}
- scheduleNotifyClientsOfServicesStateChange();
+ scheduleNotifyClientsOfServicesStateChange(userState);
}
/**
@@ -1358,22 +1422,26 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final int clientState = userState.getClientState();
if (userState.mLastSentClientState != clientState
&& (mGlobalClients.getRegisteredCallbackCount() > 0
- || userState.mClients.getRegisteredCallbackCount() > 0)) {
+ || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
userState.mLastSentClientState = clientState;
mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
clientState, userState.mUserId).sendToTarget();
}
}
- private void scheduleNotifyClientsOfServicesStateChange() {
- mMainHandler.obtainMessage(MainHandler.MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS)
- .sendToTarget();
+ private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
+ mMainHandler.obtainMessage(MainHandler.MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS,
+ userState.mUserId).sendToTarget();
}
private void scheduleUpdateInputFilter(UserState userState) {
mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget();
}
+ private void scheduleUpdateFingerprintGestureHandling(UserState userState) {
+ mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_FINGERPRINT, userState).sendToTarget();
+ }
+
private void updateInputFilter(UserState userState) {
boolean setInputFilter = false;
AccessibilityInputFilter inputFilter = null;
@@ -1501,6 +1569,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
updateDisplayInversionLocked(userState);
updateMagnificationLocked(userState);
updateSoftKeyboardShowModeLocked(userState);
+ scheduleUpdateFingerprintGestureHandling(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
@@ -1919,6 +1988,35 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private void updateFingerprintGestureHandling(UserState userState) {
+ final List<Service> services;
+ synchronized (mLock) {
+ // Only create the controller when a service wants to use the feature
+ services = userState.mBoundServices;
+ int numServices = services.size();
+ for (int i = 0; i < numServices; i++) {
+ if (services.get(i).isCapturingFingerprintGestures()) {
+ final long identity = Binder.clearCallingIdentity();
+ IFingerprintService service = null;
+ try {
+ service = IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ if (service != null) {
+ mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(
+ service, mLock);
+ break;
+ }
+ }
+ }
+ }
+ if (mFingerprintGestureDispatcher != null) {
+ mFingerprintGestureDispatcher.updateClientList(services);
+ }
+ }
+
private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
@@ -1975,10 +2073,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
* Enables accessibility service specified by {@param componentName} for the {@param userId}.
*/
private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
- SettingsStringHelper settingsHelper = new SettingsStringHelper(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
- settingsHelper.addService(componentName);
- settingsHelper.writeToSettings();
+ final SettingStringHelper setting =
+ new SettingStringHelper(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId);
+ setting.write(ComponentNameSet.add(setting.read(), componentName));
UserState userState = getUserStateLocked(userId);
if (userState.mEnabledServices.add(componentName)) {
@@ -1990,10 +2090,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
* Disables accessibility service specified by {@param componentName} for the {@param userId}.
*/
private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
- SettingsStringHelper settingsHelper = new SettingsStringHelper(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
- settingsHelper.deleteService(componentName);
- settingsHelper.writeToSettings();
+ final SettingStringHelper setting =
+ new SettingStringHelper(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId);
+ setting.write(ComponentNameSet.remove(setting.read(), componentName));
UserState userState = getUserStateLocked(userId);
if (userState.mEnabledServices.remove(componentName)) {
@@ -2001,43 +2103,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
- private class SettingsStringHelper {
- private static final String SETTINGS_DELIMITER = ":";
- private ContentResolver mContentResolver;
- private final String mSettingsName;
- private Set<String> mServices;
- private final int mUserId;
-
- public SettingsStringHelper(String name, int userId) {
- mUserId = userId;
- mSettingsName = name;
- mContentResolver = mContext.getContentResolver();
- String servicesString = Settings.Secure.getStringForUser(
- mContentResolver, mSettingsName, userId);
- mServices = new HashSet();
- if (!TextUtils.isEmpty(servicesString)) {
- final TextUtils.SimpleStringSplitter colonSplitter =
- new TextUtils.SimpleStringSplitter(SETTINGS_DELIMITER.charAt(0));
- colonSplitter.setString(servicesString);
- while (colonSplitter.hasNext()) {
- final String serviceName = colonSplitter.next();
- mServices.add(serviceName);
- }
+ /**
+ * AIDL-exposed method. System only.
+ * Inform accessibility that a fingerprint gesture was performed
+ *
+ * @param gestureKeyCode The key code corresponding to the fingerprint gesture.
+ * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it
+ * doesn't.
+ */
+ @Override
+ public boolean sendFingerprintGesture(int gestureKeyCode) {
+ synchronized(mLock) {
+ if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+ throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
}
}
-
- public void addService(ComponentName component) {
- mServices.add(component.flattenToString());
- }
-
- public void deleteService(ComponentName component) {
- mServices.remove(component.flattenToString());
- }
-
- public void writeToSettings() {
- Settings.Secure.putStringForUser(mContentResolver, mSettingsName,
- TextUtils.join(SETTINGS_DELIMITER, mServices), mUserId);
+ if (mFingerprintGestureDispatcher == null) {
+ return false;
}
+ return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
}
@Override
@@ -2131,6 +2215,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
+ public static final int MSG_UPDATE_FINGERPRINT = 11;
public MainHandler(Looper looper) {
super(looper);
@@ -2165,12 +2250,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final int clientState = msg.arg1;
final int userId = msg.arg2;
sendStateToClients(clientState, mGlobalClients);
- sendStateToClientsForUser(clientState, userId);
+ sendStateToClients(clientState, getUserClientsForId(userId));
} break;
case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
final int userId = msg.arg1;
- sendStateToClientsForUser(0, userId);
+ sendStateToClients(0, getUserClientsForId(userId));
} break;
case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
@@ -2197,7 +2282,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
} break;
case MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS: {
- notifyClientsOfServicesStateChange();
+ final int userId = msg.arg1;
+ notifyClientsOfServicesStateChange(mGlobalClients);
+ notifyClientsOfServicesStateChange(getUserClientsForId(userId));
+ } break;
+
+ case MSG_UPDATE_FINGERPRINT: {
+ updateFingerprintGestureHandling((UserState) msg.obj);
} break;
}
}
@@ -2218,12 +2309,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
- private void sendStateToClientsForUser(int clientState, int userId) {
+ private RemoteCallbackList<IAccessibilityManagerClient> getUserClientsForId(int userId) {
final UserState userState;
synchronized (mLock) {
userState = getUserStateLocked(userId);
}
- sendStateToClients(clientState, userState.mClients);
+ return userState.mUserClients;
}
private void sendStateToClients(int clientState,
@@ -2243,11 +2334,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
- private void notifyClientsOfServicesStateChange() {
- RemoteCallbackList<IAccessibilityManagerClient> clients;
- synchronized (mLock) {
- clients = getCurrentUserStateLocked().mClients;
- }
+ private void notifyClientsOfServicesStateChange(
+ RemoteCallbackList<IAccessibilityManagerClient> clients) {
try {
final int userClientCount = clients.beginBroadcast();
for (int i = 0; i < userClientCount; i++) {
@@ -2329,7 +2417,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
* connection for the service.
*/
class Service extends IAccessibilityServiceConnection.Stub
- implements ServiceConnection, DeathRecipient, KeyEventDispatcher.KeyEventFilter {;
+ implements ServiceConnection, DeathRecipient, KeyEventDispatcher.KeyEventFilter,
+ FingerprintGestureDispatcher.FingerprintGestureClient {
final int mUserId;
@@ -2359,6 +2448,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
boolean mRetrieveInteractiveWindows;
+ boolean mCaptureFingerprintGestures;
+
+ boolean mRequestAccessibilityButton;
+
int mFetchFlags;
long mNotificationTimeout;
@@ -2438,6 +2531,47 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return true;
}
+ @Override
+ public boolean isCapturingFingerprintGestures() {
+ return (mServiceInterface != null)
+ && mSecurityPolicy.canCaptureFingerprintGestures(this)
+ && mCaptureFingerprintGestures;
+ }
+
+ @Override
+ public void onFingerprintGestureDetectionActiveChanged(boolean active) {
+ if (!isCapturingFingerprintGestures()) {
+ return;
+ }
+ IAccessibilityServiceClient serviceInterface;
+ synchronized (mLock) {
+ serviceInterface = mServiceInterface;
+ }
+ if (serviceInterface != null) {
+ try {
+ mServiceInterface.onFingerprintCapturingGesturesChanged(active);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void onFingerprintGesture(int gesture) {
+ if (!isCapturingFingerprintGestures()) {
+ return;
+ }
+ IAccessibilityServiceClient serviceInterface;
+ synchronized (mLock) {
+ serviceInterface = mServiceInterface;
+ }
+ if (serviceInterface != null) {
+ try {
+ mServiceInterface.onFingerprintGesture(gesture);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
mEventTypes = info.eventTypes;
mFeedbackType = info.feedbackType;
@@ -2471,6 +2605,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
& AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
mRetrieveInteractiveWindows = (info.flags
& AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
+ mCaptureFingerprintGestures = (info.flags
+ & AccessibilityServiceInfo.FLAG_CAPTURE_FINGERPRINT_GESTURES) != 0;
+ mRequestAccessibilityButton = (info.flags
+ & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
}
/**
@@ -2584,7 +2722,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
UserState userState = getUserStateLocked(mUserId);
onUserStateChangedLocked(userState);
- scheduleNotifyClientsOfServicesStateChange();
+ scheduleNotifyClientsOfServicesStateChange(userState);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2632,7 +2770,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.getCallingUserId());
+ .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
return resolvedUserId == mCurrentUserId;
}
@@ -2794,7 +2932,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public boolean findAccessibilityNodeInfoByAccessibilityId(
int accessibilityWindowId, long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
- long interrogatingTid) throws RemoteException {
+ long interrogatingTid, Bundle arguments) throws RemoteException {
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
@@ -2826,7 +2964,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
try {
connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
- interrogatingPid, interrogatingTid, spec);
+ interrogatingPid, interrogatingTid, spec, arguments);
return true;
} catch (RemoteException re) {
if (DEBUG) {
@@ -3060,6 +3198,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
@Override
+ public boolean isFingerprintGestureDetectionAvailable() {
+ return isCapturingFingerprintGestures()
+ && (mFingerprintGestureDispatcher != null)
+ && mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable();
+ }
+
+ @Override
public float getMagnificationScale() {
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
@@ -3215,6 +3360,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
@Override
+ public boolean isAccessibilityButtonAvailable() {
+ final UserState userState;
+ synchronized (mLock) {
+ if (!isCalledForCurrentUserLocked()) {
+ return false;
+ }
+ userState = getCurrentUserStateLocked();
+ }
+
+ return mRequestAccessibilityButton && userState.mIsAccessibilityButtonAvailable;
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
synchronized (mLock) {
@@ -3427,6 +3585,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
}
+ public void notifyAccessibilityButtonClickedLocked() {
+ mInvocationHandler.notifyAccessibilityButtonClickedLocked();
+ }
+
+ public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+ mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
+ }
+
/**
* Called by the invocation handler to notify the service that the
* state of magnification has changed.
@@ -3465,6 +3631,36 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private void notifyAccessibilityButtonClickedInternal() {
+ final IAccessibilityServiceClient listener;
+ synchronized (mLock) {
+ listener = mServiceInterface;
+ }
+ if (listener != null) {
+ try {
+ listener.onAccessibilityButtonClicked();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
+ }
+ }
+ }
+
+ private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
+ final IAccessibilityServiceClient listener;
+ synchronized (mLock) {
+ listener = mServiceInterface;
+ }
+ if (listener != null) {
+ try {
+ listener.onAccessibilityButtonAvailabilityChanged(available);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error sending accessibility button availability change to " + mService,
+ re);
+ }
+ }
+ }
+
private void notifyGestureInternal(int gestureId) {
final IAccessibilityServiceClient listener;
synchronized (mLock) {
@@ -3606,6 +3802,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
+ private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
+ private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
private boolean mIsMagnificationCallbackEnabled = false;
private boolean mIsSoftKeyboardCallbackEnabled = false;
@@ -3641,6 +3839,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
notifySoftKeyboardShowModeChangedInternal(showState);
} break;
+ case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: {
+ notifyAccessibilityButtonClickedInternal();
+ } break;
+
+ case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
+ final boolean available = (message.arg1 != 0);
+ notifyAccessibilityButtonAvailabilityChangedInternal(available);
+ } break;
+
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
@@ -3680,6 +3887,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public void setSoftKeyboardCallbackEnabled(boolean enabled) {
mIsSoftKeyboardCallbackEnabled = enabled;
}
+
+ public void notifyAccessibilityButtonClickedLocked() {
+ final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED);
+ msg.sendToTarget();
+ }
+
+ public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+ final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED,
+ (available ? 1 : 0), 0);
+ msg.sendToTarget();
+ }
}
}
@@ -3782,6 +4000,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
@@ -4234,6 +4453,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
& AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;
}
+ public boolean canCaptureFingerprintGestures(Service service) {
+ return (service.mAccessibilityServiceInfo.getCapabilities()
+ & AccessibilityServiceInfo.CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES) != 0;
+ }
+
private int resolveProfileParentLocked(int userId) {
if (userId != mCurrentUserId) {
final long identity = Binder.clearCallingIdentity();
@@ -4344,7 +4568,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// Non-transient state.
- public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
+ public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
new RemoteCallbackList<>();
public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
@@ -4378,6 +4602,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public int mSoftKeyboardShowMode = 0;
+ public boolean mIsAccessibilityButtonAvailable;
+
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
public boolean mIsEnhancedWebAccessibilityEnabled;
@@ -4452,6 +4678,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
mSoftKeyboardShowMode = 0;
+
+ // Clear state tracked from system UI
+ mIsAccessibilityButtonAvailable = false;
}
public void destroyUiAutomationService() {
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
new file mode 100644
index 000000000000..fe787b36472d
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Encapsulate fingerprint gesture logic
+ */
+public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
+ implements Handler.Callback{
+ private static final int MSG_REGISTER = 1;
+ private static final int MSG_UNREGISTER = 2;
+ private static final String LOG_TAG = "FingerprintGestureDispatcher";
+
+ private final List<FingerprintGestureClient> mCapturingClients = new ArrayList<>(0);
+ private final Object mLock;
+ private final IFingerprintService mFingerprintService;
+ private final Handler mHandler;
+
+ // This field is ground truth for whether or not we are registered. Only write to it in handler.
+ private boolean mRegisteredReadOnlyExceptInHandler;
+
+ /**
+ * @param fingerprintService The system's fingerprint service
+ * @param lock A lock to use when managing internal state
+ */
+ public FingerprintGestureDispatcher(IFingerprintService fingerprintService, Object lock) {
+ mFingerprintService = fingerprintService;
+ mLock = lock;
+ mHandler = new Handler(this);
+ }
+
+ /**
+ * @param fingerprintService The system's fingerprint service
+ * @param lock A lock to use when managing internal state
+ * @param handler A handler to use internally. Used for testing.
+ */
+ public FingerprintGestureDispatcher(IFingerprintService fingerprintService, Object lock,
+ Handler handler) {
+ mFingerprintService = fingerprintService;
+ mLock = lock;
+ mHandler = handler;
+ }
+
+ /**
+ * Update the list of clients that are interested in fingerprint gestures.
+ *
+ * @param clientList The list of potential clients.
+ */
+ public void updateClientList(List<? extends FingerprintGestureClient> clientList) {
+ synchronized (mLock) {
+ mCapturingClients.clear();
+ for (int i = 0; i < clientList.size(); i++) {
+ FingerprintGestureClient client = clientList.get(i);
+ if (client.isCapturingFingerprintGestures()) {
+ mCapturingClients.add(client);
+ }
+ }
+ if (mCapturingClients.isEmpty()) {
+ if (mRegisteredReadOnlyExceptInHandler) {
+ mHandler.obtainMessage(MSG_UNREGISTER).sendToTarget();
+ }
+ } else {
+ if(!mRegisteredReadOnlyExceptInHandler) {
+ mHandler.obtainMessage(MSG_REGISTER).sendToTarget();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onClientActiveChanged(boolean nonGestureFingerprintClientActive) {
+ synchronized (mLock) {
+ for (int i = 0; i < mCapturingClients.size(); i++) {
+ mCapturingClients.get(i).onFingerprintGestureDetectionActiveChanged(
+ !nonGestureFingerprintClientActive);
+ }
+ }
+ }
+
+ public boolean isFingerprintGestureDetectionAvailable() {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return !mFingerprintService.isClientActive();
+ } catch (RemoteException re) {
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Called when the fingerprint sensor detects a gesture
+ *
+ * @param fingerprintKeyCode
+ * @return {@code true} if the gesture is consumed. {@code false} otherwise.
+ */
+ public boolean onFingerprintGesture(int fingerprintKeyCode) {
+ int idForFingerprintGestureManager;
+
+ final List<FingerprintGestureClient> clientList;
+ synchronized (mLock) {
+ if (mCapturingClients.isEmpty()) {
+ return false;
+ }
+ switch (fingerprintKeyCode) {
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
+ idForFingerprintGestureManager =
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP;
+ break;
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
+ idForFingerprintGestureManager =
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+ break;
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:
+ idForFingerprintGestureManager =
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT;
+ break;
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
+ idForFingerprintGestureManager =
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT;
+ break;
+ default:
+ return false;
+ }
+ clientList = new ArrayList<>(mCapturingClients);
+ }
+ for (int i = 0; i < clientList.size(); i++) {
+ clientList.get(i).onFingerprintGesture(idForFingerprintGestureManager);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ if (message.what == MSG_REGISTER) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mFingerprintService.addClientActiveCallback(this);
+ mRegisteredReadOnlyExceptInHandler = true;
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Failed to register for fingerprint activity callbacks");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return false;
+ } else if (message.what == MSG_UNREGISTER) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mFingerprintService.removeClientActiveCallback(this);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Failed to unregister for fingerprint activity callbacks");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ mRegisteredReadOnlyExceptInHandler = false;
+ } else {
+ Slog.e(LOG_TAG, "Unknown message: " + message.what);
+ return false;
+ }
+ return true;
+ }
+
+ // Interface for potential clients.
+ public interface FingerprintGestureClient {
+ /**
+ * @return {@code true} if the client is capturing fingerprint gestures
+ */
+ boolean isCapturingFingerprintGestures();
+
+ /**
+ * Callback when gesture detection becomes active or inactive.
+ *
+ * @param active {@code true} when detection is active
+ */
+ void onFingerprintGestureDetectionActiveChanged(boolean active);
+
+ /**
+ * Callback when gesture is detected
+ *
+ * @param gesture The identifier for the gesture. For example,
+ * {@link FingerprintGestureController#FINGERPRINT_GESTURE_SWIPE_LEFT}
+ */
+ void onFingerprintGesture(int gesture);
+ }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 3523706859c0..4d2b10610fa8 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -42,6 +42,7 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -70,6 +71,8 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.service.appwidget.AppWidgetServiceDumpProto;
+import android.service.appwidget.WidgetProto;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -82,6 +85,7 @@ import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TypedValue;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
@@ -716,34 +720,78 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
+ ", uid=" + Binder.getCallingUid());
synchronized (mLock) {
- int N = mProviders.size();
- pw.println("Providers:");
- for (int i = 0; i < N; i++) {
- dumpProvider(mProviders.get(i), i, pw);
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpInternal(pw);
}
+ }
+ }
- N = mWidgets.size();
- pw.println(" ");
- pw.println("Widgets:");
- for (int i = 0; i < N; i++) {
- dumpWidget(mWidgets.get(i), i, pw);
- }
+ private void dumpProto(FileDescriptor fd) {
+ Slog.i(TAG, "dump proto for " + mWidgets.size() + " widgets");
- N = mHosts.size();
- pw.println(" ");
- pw.println("Hosts:");
- for (int i = 0; i < N; i++) {
- dumpHost(mHosts.get(i), i, pw);
- }
+ ProtoOutputStream proto = new ProtoOutputStream(fd);
+ int N = mWidgets.size();
+ for (int i=0; i < N; i++) {
+ dumpProtoWidget(proto, mWidgets.get(i));
+ }
+ proto.flush();
+ }
+ private void dumpProtoWidget(ProtoOutputStream proto, Widget widget) {
+ if (widget.host == null || widget.provider == null) {
+ Slog.d(TAG, "skip dumping widget because host or provider is null: widget.host="
+ + widget.host + " widget.provider=" + widget.provider);
+ return;
+ }
+ long token = proto.start(AppWidgetServiceDumpProto.WIDGETS);
+ proto.write(WidgetProto.IS_CROSS_PROFILE,
+ widget.host.getUserId() != widget.provider.getUserId());
+ proto.write(WidgetProto.IS_HOST_STOPPED, widget.host.callbacks == null);
+ proto.write(WidgetProto.HOST_PACKAGE, widget.host.id.packageName);
+ proto.write(WidgetProto.PROVIDER_PACKAGE, widget.provider.id.componentName.getPackageName());
+ proto.write(WidgetProto.PROVIDER_CLASS, widget.provider.id.componentName.getClassName());
+ if (widget.options != null) {
+ proto.write(WidgetProto.MIN_WIDTH,
+ widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 0));
+ proto.write(WidgetProto.MIN_HEIGHT,
+ widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 0));
+ proto.write(WidgetProto.MAX_WIDTH,
+ widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 0));
+ proto.write(WidgetProto.MAX_HEIGHT,
+ widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0));
+ }
+ proto.end(token);
+ }
- N = mPackagesWithBindWidgetPermission.size();
- pw.println(" ");
- pw.println("Grants:");
- for (int i = 0; i < N; i++) {
- Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i);
- dumpGrant(grant, i, pw);
- }
+ private void dumpInternal(PrintWriter pw) {
+ int N = mProviders.size();
+ pw.println("Providers:");
+ for (int i = 0; i < N; i++) {
+ dumpProvider(mProviders.get(i), i, pw);
+ }
+
+ N = mWidgets.size();
+ pw.println(" ");
+ pw.println("Widgets:");
+ for (int i = 0; i < N; i++) {
+ dumpWidget(mWidgets.get(i), i, pw);
+ }
+
+ N = mHosts.size();
+ pw.println(" ");
+ pw.println("Hosts:");
+ for (int i = 0; i < N; i++) {
+ dumpHost(mHosts.get(i), i, pw);
+ }
+
+ N = mPackagesWithBindWidgetPermission.size();
+ pw.println(" ");
+ pw.println("Grants:");
+ for (int i = 0; i < N; i++) {
+ Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i);
+ dumpGrant(grant, i, pw);
}
}
@@ -1547,6 +1595,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
@Override
+ public boolean isRequestPinAppWidgetSupported() {
+ return LocalServices.getService(ShortcutServiceInternal.class)
+ .isRequestPinItemSupported(UserHandle.getCallingUserId(),
+ LauncherApps.PinItemRequest.REQUEST_TYPE_APPWIDGET);
+ }
+
+ @Override
public boolean requestPinAppWidget(String callingPackage, ComponentName componentName,
IntentSender resultSender) {
final int callingUid = Binder.getCallingUid();
diff --git a/services/autofill/java/com/android/server/autofill/AnchoredWindow.java b/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
new file mode 100644
index 000000000000..ed0d23435984
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.DEBUG;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.FrameLayout;
+
+/**
+ * A window above the application that is smartly anchored to a rectangular region.
+ */
+final class AnchoredWindow implements View.OnLayoutChangeListener, View.OnTouchListener {
+ private static final String TAG = "AutoFill";
+
+ private static final int NULL_HEIGHT = -1;
+
+ private final WindowManager mWm;
+ private final IBinder mAppToken;
+ private final View mContentView;
+
+ private final View mWindowSizeListenerView;
+ private final int mMinMargin;
+
+ private int mLastHeight = NULL_HEIGHT;
+ @Nullable
+ private Rect mLastBounds;
+ @Nullable
+ private Rect mLastDisplayBounds;
+
+ /**
+ * Constructor.
+ *
+ * @param wm window manager that draws the content on a window
+ * @param appToken token to pass to window manager
+ * @param contentView content of the window
+ */
+ AnchoredWindow(WindowManager wm, IBinder appToken, View contentView) {
+ mWm = wm;
+ mAppToken = appToken;
+ mContentView = contentView;
+
+ mContentView.addOnLayoutChangeListener(this);
+
+ Context context = contentView.getContext();
+
+ mWindowSizeListenerView = new FrameLayout(context);
+ mWindowSizeListenerView.addOnLayoutChangeListener(this);
+
+ mMinMargin = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.autofill_fill_min_margin);
+ }
+
+ /**
+ * Shows the window.
+ *
+ * @param bounds the region the window should be anchored to
+ */
+ void show(Rect bounds) {
+ if (DEBUG) Slog.d(TAG, "show bounds=" + bounds);
+
+ if (!mWindowSizeListenerView.isAttachedToWindow()) {
+ if (DEBUG) Slog.d(TAG, "adding mWindowSizeListenerView");
+ LayoutParams params = createWindowLayoutParams(
+ mAppToken,
+ LayoutParams.FLAG_NOT_TOUCHABLE); // not touchable
+ params.gravity = Gravity.LEFT | Gravity.TOP;
+ params.x = 0;
+ params.y = 0;
+ params.width = LayoutParams.MATCH_PARENT;
+ params.height = LayoutParams.MATCH_PARENT;
+ mWm.addView(mWindowSizeListenerView, params);
+ }
+
+ updateBounds(bounds);
+ }
+
+ /**
+ * Hides the window.
+ */
+ void hide() {
+ if (DEBUG) Slog.d(TAG, "hide");
+
+ mLastHeight = NULL_HEIGHT;
+ mLastBounds = null;
+ mLastDisplayBounds = null;
+
+ if (mWindowSizeListenerView.isAttachedToWindow()) {
+ if (DEBUG) Slog.d(TAG, "removing mWindowSizeListenerView");
+ mWm.removeView(mWindowSizeListenerView);
+ }
+
+ if (mContentView.isAttachedToWindow()) {
+ if (DEBUG) Slog.d(TAG, "removing mContentView");
+ mContentView.setOnTouchListener(null);
+ mWm.removeView(mContentView);
+ }
+ }
+
+ @Override
+ public void onLayoutChange(View view, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (view == mWindowSizeListenerView) {
+ if (DEBUG) Slog.d(TAG, "onLayoutChange() for mWindowSizeListenerView");
+ // mWindowSizeListenerView layout changed, get the size of the display bounds and update
+ // the window.
+ final Rect displayBounds = new Rect();
+ view.getBoundsOnScreen(displayBounds);
+ updateDisplayBounds(displayBounds);
+ } else if (view == mContentView) {
+ // mContentView layout changed, update the window in case its height changed.
+ if (DEBUG) Slog.d(TAG, "onLayoutChange() for mContentView");
+ updateHeight();
+ }
+ }
+
+ // When the window is touched outside, hide the window.
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ hide();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean updateHeight() {
+ final Rect displayBounds = mLastDisplayBounds;
+ if (displayBounds == null) {
+ return false;
+ }
+
+ mContentView.measure(
+ MeasureSpec.makeMeasureSpec(displayBounds.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(displayBounds.height(), MeasureSpec.AT_MOST));
+ int height = mContentView.getMeasuredHeight();
+ if (height != mLastHeight) {
+ if (DEBUG) Slog.d(TAG, "update height=" + height);
+ mLastHeight = height;
+ update(height, mLastBounds, displayBounds);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void updateBounds(Rect bounds) {
+ if (!bounds.equals(mLastBounds)) {
+ if (DEBUG) Slog.d(TAG, "update bounds=" + bounds);
+ mLastBounds = bounds;
+
+ update(mLastHeight, bounds, mLastDisplayBounds);
+ }
+ }
+
+ private void updateDisplayBounds(Rect displayBounds) {
+ if (!displayBounds.equals(mLastDisplayBounds)) {
+ if (DEBUG) Slog.d(TAG, "update displayBounds=" + displayBounds);
+ mLastDisplayBounds = displayBounds;
+
+ if (!updateHeight()) {
+ update(mLastHeight, mLastBounds, displayBounds);
+ }
+ }
+ }
+
+ // Updates the window if height, bounds, and displayBounds are not null.
+ // Caller should ensure that something changed before calling.
+ private void update(int height, @Nullable Rect bounds, @Nullable Rect displayBounds) {
+ if (height == NULL_HEIGHT || bounds == null || displayBounds == null) {
+ return;
+ }
+
+ if (DEBUG) Slog.d(TAG, "update height=" + height + ", bounds=" + bounds
+ + ", displayBounds=" + displayBounds);
+
+ final LayoutParams params = createWindowLayoutParams(mAppToken,
+ LayoutParams.FLAG_NOT_TOUCH_MODAL // outside touches go to windows behind us
+ | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // outside touches trigger MotionEvent
+ params.setTitle("AutoFill Fill"); // used for debugging
+ updatePosition(params, height, mMinMargin, bounds, displayBounds);
+ if (!mContentView.isAttachedToWindow()) {
+ if (DEBUG) Slog.d(TAG, "adding mContentView");
+ mWm.addView(mContentView, params);
+ mContentView.setOnTouchListener(this);
+ } else {
+ if (DEBUG) Slog.d(TAG, "updating mContentView");
+ mWm.updateViewLayout(mContentView, params);
+ }
+ }
+
+ /**
+ * Updates the position of the window by altering the {@link LayoutParams}.
+ *
+ * <p>The window can be anchored either above or below the bounds. Anchoring the window below
+ * the bounds is preferred, if it fits. Otherwise, anchor the window on the side with more
+ * space.
+ *
+ * @param params the params to update
+ * @param height the requested height of the window
+ * @param minMargin the minimum margin between the window and the display bounds
+ * @param bounds the region the window should be anchored to
+ * @param displayBounds the region in which the window may be displayed
+ */
+ private static void updatePosition(
+ LayoutParams params,
+ int height,
+ int minMargin,
+ Rect bounds,
+ Rect displayBounds) {
+ boolean below;
+ int verticalSpace;
+ final int verticalSpaceBelow = displayBounds.bottom - bounds.bottom - minMargin;
+ if (height <= verticalSpaceBelow) {
+ // Fits below bounds.
+ below = true;
+ verticalSpace = height;
+ } else {
+ final int verticalSpaceAbove = bounds.top - displayBounds.top - minMargin;
+ if (height <= verticalSpaceAbove) {
+ // Fits above bounds.
+ below = false;
+ verticalSpace = height;
+ } else {
+ // Pick above/below based on which has the most space.
+ if (verticalSpaceBelow >= verticalSpaceAbove) {
+ below = true;
+ verticalSpace = verticalSpaceBelow;
+ } else {
+ below = false;
+ verticalSpace = verticalSpaceAbove;
+ }
+ }
+ }
+
+ int gravity;
+ int y;
+ if (below) {
+ if (DEBUG) Slog.d(TAG, "anchorBelow");
+ gravity = Gravity.TOP | Gravity.LEFT;
+ y = bounds.bottom - displayBounds.top;
+ } else {
+ if (DEBUG) Slog.d(TAG, "anchorAbove");
+ gravity = Gravity.BOTTOM | Gravity.LEFT;
+ y = displayBounds.bottom - bounds.top;
+ }
+
+ final int x = bounds.left - displayBounds.left;
+
+ params.gravity = gravity;
+ params.x = x;
+ params.y = y;
+ params.width = bounds.width();
+ params.height = verticalSpace;
+ }
+
+ private static LayoutParams createWindowLayoutParams(IBinder appToken, int flags) {
+ final LayoutParams params = new LayoutParams();
+ params.token = appToken;
+ params.type = LayoutParams.TYPE_PHONE;
+ params.flags =
+ flags
+ | LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events
+ | LayoutParams.FLAG_ALT_FOCUSABLE_IM; // resize for soft input
+ params.format = PixelFormat.TRANSLUCENT;
+ return params;
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 87eaf29fb306..93473503479b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,13 +18,12 @@ package com.android.server.autofill;
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-
-import static com.android.server.autofill.AutoFillUI.MSG_SHOW_ALL_NOTIFICATIONS;
-import static com.android.server.autofill.AutoFillUI.SHOW_ALL_NOTIFICATIONS_DELAY_MS;
+import static com.android.server.autofill.Helper.DEBUG;
+import static com.android.server.autofill.Helper.VERBOSE;
import android.Manifest;
+import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -32,33 +31,36 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Message;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.autofill.IAutoFillManagerService;
import android.text.TextUtils;
-import android.text.format.DateUtils;
+import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TimeUtils;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
-import com.android.server.FgThread;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
/**
* Entry point service for auto-fill management.
@@ -70,38 +72,53 @@ import java.io.PrintWriter;
public final class AutoFillManagerService extends SystemService {
private static final String TAG = "AutoFillManagerService";
- static final boolean DEBUG = true; // TODO: change to false once stable
-
- private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS;
-
- private static final int ARG_NOT_USED = 0;
- protected static final int MSG_UNBIND = 1;
+ private static final int MSG_START_SESSION = 1;
+ private static final int MSG_UPDATE_SESSION = 2;
+ private static final int MSG_FINISH_SESSION = 3;
+ private static final int MSG_REQUEST_SAVE_FOR_USER = 4;
- private final AutoFillManagerServiceStub mServiceStub;
- private final AutoFillUI mUi;
private final Context mContext;
- private final ContentResolver mResolver;
+ private final AutoFillUI mUi;
private final Object mLock = new Object();
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UNBIND:
- removeStaleServiceForUser(msg.arg1);
- return;
- case MSG_SHOW_ALL_NOTIFICATIONS:
- mUi.showAllNotifications();
- return;
- default:
- Slog.w(TAG, "Invalid message: " + msg);
+ private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+ switch (msg.what) {
+ case MSG_START_SESSION: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final int userId = msg.arg1;
+ final IBinder activityToken = (IBinder) args.arg1;
+ final IBinder appCallback = (IBinder) args.arg2;
+ final AutoFillId autoFillId = (AutoFillId) args.arg3;
+ final Rect bounds = (Rect) args.arg4;
+ final AutoFillValue value = (AutoFillValue) args.arg5;
+ handleStartSession(userId, activityToken, appCallback, autoFillId, bounds, value);
+ return;
+ } case MSG_FINISH_SESSION: {
+ handleFinishSession(msg.arg1, (IBinder) msg.obj);
+ return;
+ } case MSG_REQUEST_SAVE_FOR_USER: {
+ handleSaveForUser(msg.arg1);
+ return;
+ } case MSG_UPDATE_SESSION: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final IBinder activityToken = (IBinder) args.arg1;
+ final AutoFillId autoFillId = (AutoFillId) args.arg2;
+ final Rect bounds = (Rect) args.arg3;
+ final AutoFillValue value = (AutoFillValue) args.arg4;
+ final int userId = args.argi5;
+ final int flags = args.argi6;
+ handleUpdateSession(userId, activityToken, autoFillId, bounds, value, flags);
+ return;
+ } default: {
+ Slog.w(TAG, "Invalid message: " + msg);
}
}
-
};
+ private HandlerCaller mHandlerCaller;
+
/**
* Cache of {@link AutoFillManagerServiceImpl} per user id.
* <p>
@@ -112,26 +129,26 @@ public final class AutoFillManagerService extends SystemService {
* Entries on this cache are added on demand and removed when:
* <ol>
* <li>An auto-fill service app is removed.
- * <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change.
- * <li>It has not been interacted with for {@link #SERVICE_BINDING_LIFETIME_MS} ms.
+ * <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change.\
* </ol>
*/
+ // TODO(b/33197203): Update the above comment
@GuardedBy("mLock")
private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>();
+ // TODO(b/33197203): set a different max (or disable it) on low-memory devices.
+ private final LocalLog mRequestsHistory = new LocalLog(100);
+
public AutoFillManagerService(Context context) {
super(context);
-
+ mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
mContext = context;
- mUi = new AutoFillUI(context, this, mLock);
- mResolver = context.getContentResolver();
- mServiceStub = new AutoFillManagerServiceStub();
+ mUi = new AutoFillUI(mContext);
}
@Override
public void onStart() {
- if (DEBUG) Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE);
- publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub);
+ publishBinderService(AUTO_FILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
}
@Override
@@ -139,125 +156,172 @@ public final class AutoFillManagerService extends SystemService {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
new SettingsObserver(BackgroundThread.getHandler());
}
- if (phase == PHASE_BOOT_COMPLETED) {
- // TODO: if sent right away, the notification is not displayed. Since the notification
- // mechanism is a temporary approach anyways, just delay it..
- if (DEBUG)
- Slog.d(TAG, "Showing notifications in " + SHOW_ALL_NOTIFICATIONS_DELAY_MS + "ms");
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ALL_NOTIFICATIONS),
- SHOW_ALL_NOTIFICATIONS_DELAY_MS);
- }
}
private AutoFillManagerServiceImpl newServiceForUser(int userId) {
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
final String componentName = Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+ mContext.getContentResolver(), Settings.Secure.AUTO_FILL_SERVICE, userId);
if (!TextUtils.isEmpty(componentName)) {
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
- serviceInfo =
- AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
+ serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0,
+ userId);
} catch (RuntimeException | RemoteException e) {
- Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+ Slog.e(TAG, "Bad auto-fill service name " + componentName, e);
return null;
}
}
- if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
- + serviceComponent + ", info: " + serviceInfo);
if (serviceInfo == null) {
- Slog.w(TAG, "no service info for " + serviceComponent);
return null;
}
- return new AutoFillManagerServiceImpl(this, mUi, mContext, mLock, FgThread.getHandler(),
- userId, serviceInfo.applicationInfo.uid, serviceComponent,
- SERVICE_BINDING_LIFETIME_MS);
+
+ try {
+ return new AutoFillManagerServiceImpl(mContext, mLock, mRequestsHistory,
+ userId, serviceComponent, mUi);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Auto-fill service not found: " + serviceComponent, e);
+ }
+
+ return null;
}
/**
* Gets the service instance for an user.
*
- * <p>First it tries to return the existing instance from the cache; if it's not cached, it
- * creates a new instance and caches it.
+ * @return service instance or {@code null} if user does not have a service set.
*/
- // TODO(b/33197203): make private once AutoFillUi does not uses notifications
+ @Nullable
AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
AutoFillManagerServiceImpl service = mServicesCache.get(userId);
- if (service != null) {
- if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId);
- service.setLifeExpectancy(SERVICE_BINDING_LIFETIME_MS);
- } else {
+ if (service == null) {
service = newServiceForUser(userId);
- if (service == null) {
- // Already logged
- return null;
- }
- if (DEBUG) Log.d(TAG, "creating new cached service for userId " + userId);
- service.startLocked();
mServicesCache.put(userId, service);
}
- // Keep service connection alive for a while, in case user needs to interact with it
- // (for example, to save the data that was inputted in)
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UNBIND, userId, ARG_NOT_USED),
- SERVICE_BINDING_LIFETIME_MS);
return service;
}
/**
- * Removes a cached service, but respecting its TTL.
+ * Removes a cached service for a given user.
*/
- private void removeStaleServiceForUser(int userId) {
- synchronized (mLock) {
- removeCachedService(userId, false);
+ void removeCachedServiceLocked(int userId) {
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service != null) {
+ mServicesCache.delete(userId);
+ service.destroyLocked();
}
}
- /**
- * Removes a cached service, even if it has TTL.
- */
- void removeCachedServiceForUserLocked(int userId) {
- removeCachedService(userId, true);
+ private void handleStartSession(int userId, IBinder activityToken, IBinder appCallback,
+ AutoFillId autoFillId, Rect bounds, AutoFillValue value) {
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service == null) {
+ return;
+ }
+ service.startSessionLocked(activityToken, appCallback, autoFillId, bounds, value);
+ }
}
- private void removeCachedService(int userId, boolean force) {
- if (DEBUG) Log.d(TAG, "removing cached service for userId " + userId);
- final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
- if (service == null) {
- Log.w(TAG, "removeCachedServiceForUser(): no cached service for userId " + userId);
- return;
+ private void handleFinishSession(int userId, IBinder activityToken) {
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service == null) {
+ return;
+ }
+ service.finishSessionLocked(activityToken);
}
- if (!force) {
- // Check TTL first.
- final long now = SystemClock.uptimeMillis();
- if (service.mEstimateTimeOfDeath > now) {
- if (DEBUG) {
- final StringBuilder msg = new StringBuilder("service has some TTL left: ");
- TimeUtils.formatDuration(service.mEstimateTimeOfDeath - now, msg);
- Log.d(TAG, msg.toString());
- }
+ }
+
+ private void handleUpdateSession(int userId, IBinder activityToken, AutoFillId autoFillId,
+ Rect bounds, AutoFillValue value, int flags) {
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service == null) {
return;
}
+
+ service.updateSessionLocked(activityToken, autoFillId, bounds, value, flags);
}
- mServicesCache.delete(userId);
- service.stopLocked();
+ }
+ private IBinder getTopActivityForUser() {
+ final List<IBinder> topActivities = LocalServices
+ .getService(ActivityManagerInternal.class).getTopVisibleActivities();
+ if (DEBUG) Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+ if (topActivities.isEmpty()) {
+ Slog.w(TAG, "Could not get top activity");
+ return null;
+ }
+ return topActivities.get(0);
+ }
+
+ private void handleSaveForUser(int userId) {
+ final IBinder activityToken = getTopActivityForUser();
+ if (activityToken != null) {
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service == null) {
+ Log.w(TAG, "handleSaveForUser(): no cached service for userId " + userId);
+ return;
+ }
+
+ service.requestSaveForUserLocked(activityToken);
+ }
+ }
}
final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
@Override
- public void requestAutoFill(IBinder activityToken, int userId, Bundle extras, int flags) {
- if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", userId=" + userId);
- mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ public void startSession(IBinder activityToken, IBinder appCallback, AutoFillId autoFillId,
+ Rect bounds, AutoFillValue value) throws RemoteException {
+ // TODO(b/33197203): make sure it's called by resumed / focused activity
+
+ final int userId = UserHandle.getCallingUserId();
+ if (VERBOSE) {
+ Slog.v(TAG, "startSession: autoFillId=" + autoFillId + ", bounds=" + bounds
+ + ", value=" + value);
+ }
- synchronized (mLock) {
- final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- service.requestAutoFill(activityToken, extras, flags);
- }
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = activityToken;
+ args.arg2 = appCallback;
+ args.arg3 = autoFillId;
+ args.arg4 = bounds;
+ args.arg5 = value;
+
+ mHandlerCaller.sendMessage(mHandlerCaller.getHandler().obtainMessage(MSG_START_SESSION,
+ userId, 0, args));
+ }
+
+ @Override
+ public void updateSession(IBinder activityToken, AutoFillId id, Rect bounds,
+ AutoFillValue value, int flags) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "updateSession: flags=" + flags + ", autoFillId=" + id
+ + ", bounds=" + bounds + ", value=" + value);
}
+
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_UPDATE_SESSION,
+ activityToken, id, bounds, value, UserHandle.getCallingUserId(), flags));
+ }
+
+ @Override
+ public void finishSession(IBinder activityToken) throws RemoteException {
+ if (VERBOSE) Slog.v(TAG, "finishSession(): " + activityToken);
+
+ mHandlerCaller.sendMessage(mHandlerCaller.getHandler().obtainMessage(MSG_FINISH_SESSION,
+ UserHandle.getCallingUserId(), 0, activityToken));
+ }
+
+ @Override
+ public void requestSaveForUser(int userId) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageI(MSG_REQUEST_SAVE_FOR_USER,
+ userId));
}
@Override
@@ -282,7 +346,10 @@ public final class AutoFillManagerService extends SystemService {
impl.dumpLocked(" ", pw);
}
}
+ mUi.dump(pw);
}
+ pw.println("Requests history:");
+ mRequestsHistory.reverseDump(fd, pw, args);
}
@Override
@@ -291,7 +358,6 @@ public final class AutoFillManagerService extends SystemService {
(new AutoFillManagerServiceShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
-
}
private final class SettingsObserver extends ContentObserver {
@@ -304,10 +370,8 @@ public final class AutoFillManagerService extends SystemService {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
- if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
synchronized (mLock) {
- removeCachedServiceForUserLocked(userId);
- mUi.updateNotification(userId);
+ removeCachedServiceLocked(userId);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index ae21b07567d8..8c74532532e1 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -16,52 +16,62 @@
package com.android.server.autofill;
-import static com.android.server.autofill.AutoFillManagerService.DEBUG;
+import static android.service.autofill.AutoFillService.EXTRA_ACTIVITY_TOKEN;
+import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
+import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
+import static android.view.autofill.AutoFillManager.FLAG_FOCUS_GAINED;
+import static android.view.autofill.AutoFillManager.FLAG_FOCUS_LOST;
+import static android.view.autofill.AutoFillManager.FLAG_START_SESSION;
+import static android.view.autofill.AutoFillManager.FLAG_VALUE_CHANGED;
+
+import static com.android.server.autofill.Helper.DEBUG;
+import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.findValue;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
import android.app.IActivityManager;
import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
+import android.content.IntentSender;
import android.content.pm.PackageManager;
-import android.icu.text.DateFormat;
+import android.graphics.Rect;
import android.os.Bundle;
-import android.os.DeadObjectException;
-import android.os.Handler;
import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.Looper;
import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
import android.service.autofill.AutoFillService;
import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.FillCallback;
import android.service.autofill.IAutoFillAppCallback;
-import android.service.autofill.IAutoFillServerCallback;
import android.service.autofill.IAutoFillService;
-import android.service.voice.VoiceInteractionSession;
+import android.service.autofill.IFillCallback;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.LocalLog;
import android.util.PrintWriterPrinter;
import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
import android.view.autofill.Dataset;
import android.view.autofill.FillResponse;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
-import com.android.server.LocalServices;
+import com.android.server.FgThread;
import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
@@ -72,26 +82,18 @@ final class AutoFillManagerServiceImpl {
private static final String TAG = "AutoFillManagerServiceImpl";
- /** Used do assign ids to new ServerCallback instances. */
- private static int sServerCallbackCounter = 0;
+ private static final int MSG_SERVICE_SAVE = 1;
private final int mUserId;
- private final int mUid;
private final ComponentName mComponent;
+ private final String mComponentName;
private final Context mContext;
private final IActivityManager mAm;
private final Object mLock;
private final AutoFillServiceInfo mInfo;
- private final AutoFillManagerService mManagerService;
private final AutoFillUI mUi;
- // TODO(b/33197203): improve its usage
- // - set maximum number of entries
- // - disable on low-memory devices.
- private final List<String> mRequestHistory = new LinkedList<>();
-
- @GuardedBy("mLock")
- private final List<QueuedRequest> mQueuedRequests = new LinkedList<>();
+ private final LocalLog mRequestsHistory;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -99,205 +101,153 @@ final class AutoFillManagerServiceImpl {
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
final String reason = intent.getStringExtra("reason");
if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
- // TODO(b/33197203): close any pending UI like account selection (or remove this
- // receiver)
+ mUi.hideAll();
}
}
};
+ private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+ switch (msg.what) {
+ case MSG_SERVICE_SAVE:
+ handleSessionSave((IBinder) msg.obj);
+ break;
+ default:
+ Slog.d(TAG, "invalid msg: " + msg);
+ }
+ };
+
+ private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(),
+ mHandlerCallback, true);
/**
- * Cache of pending ServerCallbacks, keyed by {@link ServerCallback#id}.
+ * Cache of pending {@link Session}s, keyed by {@code activityToken}.
*
- * <p>They're kept until the AutoFillService handles a request, or an error occurs.
+ * <p>They're kept until the {@link AutoFillService} finished handling a request, an error
+ * occurs, or the session times out.
*/
- // TODO(b/33197203): need to make sure service is bound while callback is pending
+ // TODO(b/33197203): need to make sure service is bound while callback is pending and/or
+ // use WeakReference
@GuardedBy("mLock")
- private static final SparseArray<ServerCallback> mServerCallbacks = new SparseArray<>();
-
- private final ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Slog.d(TAG, "onServiceConnected():" + name);
- synchronized (mLock) {
- mService = IAutoFillService.Stub.asInterface(service);
- try {
- mService.onConnected();
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception on service.onConnected(): " + e);
- return;
- }
- if (!mQueuedRequests.isEmpty()) {
- if (DEBUG) Slog.d(TAG, "queued requests:" + mQueuedRequests.size());
- }
- for (final QueuedRequest request: mQueuedRequests) {
- requestAutoFillLocked(request.activityToken, request.extras, request.flags,
- false);
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Slog.d(TAG, name + " disconnected");
- synchronized (mLock) {
- mService = null;
- mManagerService.removeCachedServiceForUserLocked(mUserId);
- }
- }
- };
-
+ private final ArrayMap<IBinder, Session> mSessions = new ArrayMap<>();
/**
- * Receiver of assist data from the app's {@link Activity}, uses the {@code resultData} as
- * the {@link ServerCallback#id}.
+ * Receiver of assist data from the app's {@link Activity}.
*/
private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
if (DEBUG) Slog.d(TAG, "resultCode on mAssistReceiver: " + resultCode);
- final IBinder appBinder = resultData.getBinder(AutoFillService.KEY_CALLBACK);
- if (appBinder == null) {
- Slog.w(TAG, "no app callback on mAssistReceiver's resultData");
+ final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
+
+ if (structure == null) {
+ Slog.w(TAG, "no assist structure for id " + resultCode);
return;
}
- final AssistStructure structure = resultData
- .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
- final Bundle data = resultData.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
- final int flags = resultData.getInt(VoiceInteractionSession.KEY_FLAGS, 0);
- final ServerCallback serverCallback;
+ final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
+ if (receiverExtras == null) {
+ // Should not happen
+ Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
+ return;
+ }
+
+ final IBinder activityToken = receiverExtras.getBinder(EXTRA_ACTIVITY_TOKEN);
+ final Session session;
synchronized (mLock) {
- serverCallback = mServerCallbacks.get(resultCode);
- if (serverCallback == null) {
- Slog.w(TAG, "no server callback for id " + resultCode);
+ session = mSessions.get(activityToken);
+ if (session == null) {
+ Slog.w(TAG, "no server session for activityToken " + activityToken);
return;
}
- serverCallback.appCallback = IAutoFillAppCallback.Stub.asInterface(appBinder);
+ // TODO(b/33197203): since service is fetching the data (to use for save later),
+ // we should optimize what's sent (for example, remove layout containers,
+ // color / font info, etc...)
+ session.mStructure = structure;
}
- mService.autoFill(structure, serverCallback, serverCallback.extras, flags);
- }
- };
- @GuardedBy("mLock")
- private IAutoFillService mService;
- private boolean mBound;
- private boolean mValid;
- // Estimated time when the service will be evicted from the cache.
- long mEstimateTimeOfDeath;
+ // TODO(b/33197203, b/33269702): Must fetch the data so it's available later on
+ // handleSave(), even if if the activity is gone by then, but structure.ensureData()
+ // gives a ONE_WAY warning because system_service could block on app calls.
+ // We need to change AssistStructure so it provides a "one-way" writeToParcel()
+ // method that sends all the data
+ structure.ensureData();
- AutoFillManagerServiceImpl(AutoFillManagerService managerService, AutoFillUI ui,
- Context context, Object lock, Handler handler, int userId, int uid,
- ComponentName component, long ttl) {
- mManagerService = managerService;
- mUi = ui;
+ // Sanitize structure before it's sent to service.
+ structure.sanitizeForParceling(true);
+
+ // TODO(b/33197203): Need to pipe the bundle
+ session.mRemoteFillService.onFillRequest(structure, null);
+ }
+ };
+
+ AutoFillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
+ int userId, ComponentName component, AutoFillUI ui)
+ throws PackageManager.NameNotFoundException {
mContext = context;
mLock = lock;
+ mRequestsHistory = requestsHistory;
mUserId = userId;
- mUid = uid;
mComponent = component;
+ mComponentName = mComponent.flattenToShortString();
mAm = ActivityManager.getService();
- setLifeExpectancy(ttl);
-
- final AutoFillServiceInfo info;
- try {
- info = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Auto-fill service not found: " + component, e);
- mInfo = null;
- mValid = false;
- return;
- }
- mInfo = info;
- if (mInfo.getParseError() != null) {
- Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError());
- mValid = false;
- return;
- }
+ mUi = ui;
+ mInfo = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
- mValid = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
+ mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
}
- void setLifeExpectancy(long ttl) {
- mEstimateTimeOfDeath = SystemClock.uptimeMillis() + ttl;
- }
-
- void startLocked() {
- if (DEBUG) Slog.d(TAG, "startLocked()");
-
- final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE);
- intent.setComponent(mComponent);
- mBound = mContext.bindServiceAsUser(intent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUserId));
-
- if (!mBound) {
- Slog.w(TAG, "Failed binding to auto-fill service " + mComponent);
- return;
- }
- if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
- }
/**
- * Asks service to auto-fill an activity.
- *
- * @param activityToken activity token
- * @param extras bundle to be passed to the {@link AutoFillService} method.
- * @param flags optional flags.
+ * Used by {@link AutoFillManagerServiceShellCommand} to request save for the current top app.
*/
- void requestAutoFill(@Nullable IBinder activityToken, @Nullable Bundle extras, int flags) {
- synchronized (mLock) {
- if (!mBound) {
- Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
- return;
- }
+ void requestSaveForUserLocked(IBinder activityToken) {
+ final Session session = mSessions.get(activityToken);
+ if (session == null) {
+ Slog.w(TAG, "requestSaveForUserLocked(): no session for " + activityToken);
+ return;
}
- // TODO(b/33197203): activityToken should probably not be null, but we need to wait until
- // the UI is triggering the call (for now it's trough 'adb shell cmd autofill request'
- if (activityToken == null) {
- // Let's get top activities from all visible stacks.
+ session.callSaveLocked();
+ }
- // TODO(b/33197203): overload getTopVisibleActivities() to take userId, otherwise it
- // could return activities for different users when a work profile app is displayed in
- // another window (in a multi-window environment).
- final List<IBinder> topActivities = LocalServices
- .getService(ActivityManagerInternal.class).getTopVisibleActivities();
- if (DEBUG)
- Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
- if (topActivities.isEmpty()) {
- Slog.w(TAG, "Could not get top activity");
- return;
- }
- activityToken = topActivities.get(0);
- }
+ void startSessionLocked(IBinder activityToken, IBinder appCallbackToken, AutoFillId autoFillId,
+ Rect bounds, AutoFillValue value) {
+ final String historyItem = "s=" + mComponentName + " u=" + mUserId + " a=" + activityToken
+ + " i=" + autoFillId + " b=" + bounds + " v=" + value;
+ mRequestsHistory.log(historyItem);
- final String historyItem =
- DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
- synchronized (mLock) {
- mRequestHistory.add(historyItem);
- requestAutoFillLocked(activityToken, extras, flags, true);
+ // TODO(b/33197203): Handle partitioning
+ final Session session = mSessions.get(activityToken);
+ if (session != null) {
+ // Already started...
+ return;
}
+
+ final Session newSession = createSessionByTokenLocked(activityToken, appCallbackToken);
+ newSession.updateLocked(autoFillId, bounds, value, FLAG_START_SESSION);
+ newSession.enableSessionLocked();
}
- private void requestAutoFillLocked(IBinder activityToken, @Nullable Bundle extras, int flags,
- boolean queueIfNecessary) {
- if (mService == null) {
- if (!queueIfNecessary) {
- Slog.w(TAG, "requestAutoFillLocked(): service is null");
- return;
- }
- if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it");
- mQueuedRequests.add(new QueuedRequest(activityToken, extras, flags));
+ void finishSessionLocked(IBinder activityToken) {
+ if (DEBUG) Slog.d(TAG, "finishSessionLocked(): " + activityToken);
+ final Session session = mSessions.get(activityToken);
+
+ if (session == null) {
+ Slog.w(TAG, "finishSessionLocked(): no session for " + activityToken);
return;
}
- final int callbackId = ++sServerCallbackCounter;
- final ServerCallback serverCallback = new ServerCallback(callbackId, extras);
- mServerCallbacks.put(callbackId, serverCallback);
+ mUi.hideFillUi();
+ session.showSaveLocked();
+ }
+
+ private Session createSessionByTokenLocked(IBinder activityToken, IBinder appCallbackToken) {
+
+ final Session newSession = new Session(mContext, activityToken, appCallbackToken);
+ mSessions.put(activityToken, newSession);
/*
* TODO(b/33197203): apply security checks below:
@@ -308,215 +258,756 @@ final class AutoFillManagerServiceImpl {
*/
try {
// TODO(b/33197203): add MetricsLogger call
- if (!mAm.requestAutoFillData(mAssistReceiver, null, callbackId, activityToken, flags)) {
+ final Bundle receiverExtras = new Bundle();
+ receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken);
+ if (!mAm.requestAutoFillData(mAssistReceiver, receiverExtras, activityToken)) {
// TODO(b/33197203): might need a way to warn user (perhaps a new method on
// AutoFillService).
Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
}
} catch (RemoteException e) {
- // Should happen, it's a local call.
+ // Should not happen, it's a local call.
}
+ return newSession;
}
- void stopLocked() {
- if (DEBUG) Slog.d(TAG, "stopLocked()");
+ void updateSessionLocked(IBinder activityToken, AutoFillId autoFillId, Rect bounds,
+ AutoFillValue value, int flags) {
- // Sanity check.
- if (mService == null) {
- Slog.w(TAG, "service already null on shutdown");
+ // TODO(b/33197203): add MetricsLogger call
+ final Session session = mSessions.get(activityToken);
+ if (session == null) {
+ Slog.w(TAG, "updateSessionLocked(): session gone for " + activityToken);
return;
}
- try {
- mService.onDisconnected();
- } catch (RemoteException e) {
- if (! (e instanceof DeadObjectException)) {
- Slog.w(TAG, "Exception calling service.onDisconnected(): " + e);
- }
- } finally {
- mService = null;
- }
- if (mBound) {
- mContext.unbindService(mConnection);
- mBound = false;
- }
- if (mValid) {
- mContext.unregisterReceiver(mBroadcastReceiver);
- }
+ session.updateLocked(autoFillId, bounds, value, flags);
}
- /**
- * Called by {@link AutoFillUI} to fill an activity after the user selected a dataset.
- */
- void autoFillApp(int callbackId, Dataset dataset) {
- // TODO(b/33197203): add MetricsLogger call
-
- if (dataset == null) {
- Slog.w(TAG, "autoFillApp(): no dataset for callback id " + callbackId);
- return;
- }
+ private void handleSessionSave(IBinder activityToken) {
- final ServerCallback serverCallback;
synchronized (mLock) {
- serverCallback = mServerCallbacks.get(callbackId);
- if (serverCallback == null) {
- Slog.w(TAG, "autoFillApp(): no server callback with id " + callbackId);
- return;
- }
- if (serverCallback.appCallback == null) {
- Slog.w(TAG, "autoFillApp(): no app callback for server callback " + callbackId);
+ final Session session = mSessions.get(activityToken);
+ if (session == null) {
+ Slog.w(TAG, "handleSessionSave(): already gone: " + activityToken);
+
return;
}
- // TODO(b/33197203): use a handler?
- try {
- if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
- serverCallback.appCallback.autoFill(dataset);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error auto-filling activity: " + e);
- }
- removeServerCallbackLocked(callbackId);
+ session.callSaveLocked();
}
}
- void removeServerCallbackLocked(int id) {
- if (DEBUG) Slog.d(TAG, "Removing " + id + " from server callbacks");
- mServerCallbacks.remove(id);
- }
+ void destroyLocked() {
+ if (VERBOSE) Slog.v(TAG, "destroyLocked()");
- void dumpLocked(String prefix, PrintWriter pw) {
- if (!mValid) {
- pw.print(" NOT VALID: ");
- if (mInfo == null) {
- pw.println("no info");
- } else {
- pw.println(mInfo.getParseError());
- }
- return;
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ for (Session session : mSessions.values()) {
+ session.destroyLocked();
}
+ mSessions.clear();
+ }
+ void dumpLocked(String prefix, PrintWriter pw) {
final String prefix2 = prefix + " ";
- pw.print(prefix); pw.print("mUserId="); pw.println(mUserId);
- pw.print(prefix); pw.print("mUid="); pw.println(mUid);
- pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
- pw.print(prefix); pw.print("mBound="); pw.println(mBound);
- pw.print(prefix); pw.print("mService="); pw.println(mService);
- pw.print(prefix); pw.print("mEstimateTimeOfDeath=");
- TimeUtils.formatDuration(mEstimateTimeOfDeath, SystemClock.uptimeMillis(), pw);
- pw.println();
+ pw.print(prefix); pw.println("Component:"); pw.println(mComponentName);
- if (DEBUG) {
+ if (VERBOSE) {
// ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
- pw.print(prefix); pw.println("Service info:");
+ pw.print(prefix); pw.println("ServiceInfo:");
mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
}
- if (mRequestHistory.isEmpty()) {
- pw.print(prefix); pw.println("No history");
- } else {
- pw.print(prefix); pw.println("History:");
- for (int i = 0; i < mRequestHistory.size(); i++) {
- pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mRequestHistory.get(i));
- }
- }
- if (mQueuedRequests.isEmpty()) {
- pw.print(prefix); pw.println("No queued requests");
- } else {
- pw.print(prefix); pw.println("Queued requests:");
- for (int i = 0; i < mQueuedRequests.size(); i++) {
- pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i));
- }
- }
-
- pw.print(prefix); pw.print("sServerCallbackCounter="); pw.println(sServerCallbackCounter);
- final int size = mServerCallbacks.size();
+ final int size = mSessions.size();
if (size == 0) {
- pw.print(prefix); pw.println("No server callbacks");
+ pw.print(prefix); pw.println("No sessions");
} else {
- pw.print(prefix); pw.print(size); pw.println(" server callbacks:");
+ pw.print(prefix); pw.print(size); pw.println(" sessions:");
for (int i = 0; i < size; i++) {
- pw.print(prefix2); pw.print(mServerCallbacks.keyAt(i));
- final ServerCallback callback = mServerCallbacks.valueAt(i);
- if (callback.appCallback == null) {
- pw.println("(no appCallback)");
- } else {
- pw.print(" (app callback: "); pw.print(callback.appCallback) ; pw.println(")");
- }
+ pw.print(prefix); pw.print("#"); pw.println(i + 1);
+ mSessions.valueAt(i).dumpLocked(prefix2, pw);
}
- pw.println();
}
}
@Override
public String toString() {
- return "[AutoFillManagerServiceImpl: userId=" + mUserId + ", uid=" + mUid
- + ", component=" + mComponent.flattenToShortString() + "]";
+ return "AutoFillManagerServiceImpl: [userId=" + mUserId
+ + ", component=" + mComponentName + "]";
}
- private static final class QueuedRequest {
- final IBinder activityToken;
- final Bundle extras;
- final int flags;
+ /**
+ * State for a given view with a AutoFillId.
+ *
+ * <p>This class holds state about a view and calls its listener when the fill UI is ready to
+ * be displayed for the view.
+ */
+ static final class ViewState {
+ interface Listener {
+ /**
+ * Called when the fill UI is ready to be shown for this view.
+ */
+ void onFillReady(ViewState viewState, FillResponse fillResponse, Rect bounds,
+ @Nullable AutoFillValue value);
+ }
+
+ final AutoFillId mId;
+ private final Listener mListener;
+ // // TODO(b/33197203): does it really need a reference to the session's response?
+ private FillResponse mResponse;
+ private AutoFillValue mAutoFillValue;
+ private Rect mBounds;
+
+ private boolean mValueUpdated;
+
+ ViewState(AutoFillId id, Listener listener) {
+ mId = id;
+ mListener = listener;
+ }
+
+ /**
+ * Response should only be set once.
+ */
+ void setResponse(FillResponse response) {
+ mResponse = response;
+ maybeCallOnFillReady();
+ }
+
+ // TODO(b/33197203): need to refactor / rename / document this method to make it clear that
+ // it can change the value and update the UI; similarly, should replace code that
+ // directly sets mAutoFilLValue to use encapsulation.
+ void update(@Nullable AutoFillValue autoFillValue, @Nullable Rect bounds) {
+ if (autoFillValue != null) {
+ mAutoFillValue = autoFillValue;
+ }
+ if (bounds != null) {
+ mBounds = bounds;
+ }
+
+ maybeCallOnFillReady();
+ }
- QueuedRequest(IBinder activityToken, Bundle extras, int flags) {
- this.activityToken = activityToken;
- this.extras = extras;
- this.flags = flags;
+ /**
+ * Calls {@link Listener#onFillReady(ViewState, FillResponse, Rect, AutoFillValue)} if the
+ * fill UI is ready to be displayed (i.e. when response and bounds are set).
+ */
+ void maybeCallOnFillReady() {
+ if (mResponse != null && mBounds != null) {
+ mListener.onFillReady(this, mResponse, mBounds, mAutoFillValue);
+ }
}
@Override
public String toString() {
- return "flags: " + flags + " token: " + activityToken;
+ if (!DEBUG) return super.toString();
+
+ return "ViewState: [id=" + mId + ", value=" + mAutoFillValue + ", bounds=" + mBounds
+ + ", updated = " + mValueUpdated + "]";
}
+
+ void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("id:" ); pw.println(mId);
+ pw.print(prefix); pw.print("value:" ); pw.println(mAutoFillValue);
+ pw.print(prefix); pw.print("updated:" ); pw.println(mValueUpdated);
+ pw.print(prefix); pw.print("bounds:" ); pw.println(mBounds);
+ }
+
}
/**
- * A bridge between the {@link AutoFillService} implementation and the activity being
- * auto-filled (represented through the {@link IAutoFillAppCallback}).
+ * A session for a given activity.
+ *
+ * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track
+ * of the current {@link ViewState} to display the appropriate UI.
+ *
+ * <p>Although the auto-fill requests and callbacks are stateless from the service's point of
+ * view, we need to keep state in the framework side for cases such as authentication. For
+ * example, when service return a {@link FillResponse} that contains all the fields needed
+ * to fill the activity but it requires authentication first, that response need to be held
+ * until the user authenticates or it times out.
*/
- private final class ServerCallback extends IAutoFillServerCallback.Stub {
+ // TODO(b/33197203): make sure sessions are removed (and tested by CTS):
+ // - On all authentication scenarios.
+ // - When user does not interact back after a while.
+ // - When service is unbound.
+ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
+ AutoFillUI.AutoFillUiCallback {
+ private final IBinder mActivityToken;
+
+ @GuardedBy("mLock")
+ private final Map<AutoFillId, ViewState> mViewStates = new ArrayMap<>();
- private final int id;
- private final Bundle extras;
- private IAutoFillAppCallback appCallback;
+ @GuardedBy("mLock")
+ @Nullable
+ private ViewState mCurrentViewState;
- private ServerCallback(int id, Bundle extras) {
- this.id = id;
- this.extras = extras;
+ private final IAutoFillAppCallback mAppCallback;
+
+ @GuardedBy("mLock")
+ RemoteFillService mRemoteFillService;
+
+ // TODO(b/33197203): Get a response per view instead of per activity.
+ @GuardedBy("mLock")
+ private FillResponse mCurrentResponse;
+
+ /**
+ * Used to remember which {@link Dataset} filled the session.
+ */
+ // TODO(b/33197203): might need more than one once we support partitions
+ @GuardedBy("mLock")
+ private Dataset mAutoFilledDataset;
+
+ /**
+ * Assist structure sent by the app; it will be updated (sanitized, change values for save)
+ * before sent to {@link AutoFillService}.
+ */
+ @GuardedBy("mLock")
+ private AssistStructure mStructure;
+
+ private Session(Context context, IBinder activityToken, IBinder appCallback) {
+ mRemoteFillService = new RemoteFillService(context, mComponent, mUserId, this);
+ mActivityToken = activityToken;
+
+ mAppCallback = IAutoFillAppCallback.Stub.asInterface(appCallback);
+ try {
+ appCallback.linkToDeath(() -> {
+ if (DEBUG) Slog.d(TAG, "app binder died");
+
+ removeSelf();
+ }, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "linkToDeath() on mAppCallback failed: " + e);
+ }
}
+
+ // FillServiceCallbacks
@Override
- public void showResponse(FillResponse response) {
+ public void onFillRequestSuccess(FillResponse response) {
// TODO(b/33197203): add MetricsLogger call
- if (DEBUG) Slog.d(TAG, "showResponse(): " + response);
-
- mUi.showOptions(mUserId, id, response);
+ if (response == null) {
+ removeSelf();
+ return;
+ }
+ synchronized (mLock) {
+ processResponseLocked(response);
+ }
}
+ // FillServiceCallbacks
@Override
- public void showError(String message) {
+ public void onFillRequestFailure(CharSequence message) {
// TODO(b/33197203): add MetricsLogger call
- if (DEBUG) Slog.d(TAG, "showError(): " + message);
-
- mUi.showError(message);
+ getUiForShowing().showError(message);
+ removeSelf();
+ }
+ // FillServiceCallbacks
+ @Override
+ public void onSaveRequestSuccess() {
+ // TODO(b/33197203): add MetricsLogger call
+ // Nothing left to do...
removeSelf();
}
+ // FillServiceCallbacks
@Override
- public void highlightSavedFields(AutoFillId[] ids) {
+ public void onSaveRequestFailure(CharSequence message) {
// TODO(b/33197203): add MetricsLogger call
- if (DEBUG) Slog.d(TAG, "showSaved(): " + Arrays.toString(ids));
+ getUiForShowing().showError(message);
+ removeSelf();
+ }
+
+ // FillServiceCallbacks
+ @Override
+ public void authenticate(IntentSender intent, Intent fillInIntent) {
+ startAuthIntent(intent, fillInIntent);
+ }
- mUi.highlightSavedFields(ids);
+ // FillServiceCallbacks
+ @Override
+ public void onServiceDied(RemoteFillService service) {
+ // TODO(b/33197203): implement
+ }
- removeSelf();
+ // AutoFillUiCallback
+ @Override
+ public void fill(Dataset dataset) {
+ autoFill(dataset);
+ }
+
+ // AutoFillUiCallback
+ @Override
+ public void save() {
+ mHandlerCaller.getHandler().obtainMessage(MSG_SERVICE_SAVE, mActivityToken)
+ .sendToTarget();
+ }
+
+ /**
+ * Show the save UI, when session can be saved.
+ */
+ public void showSaveLocked() {
+ if (mStructure == null) {
+ // Sanity check; should not happen...
+ Slog.wtf(TAG, "showSaveLocked(): no mStructure");
+ return;
+ }
+ final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
+ if (VERBOSE) Slog.v(TAG, "showSaveLocked(): savableIds=" + savableIds);
+
+ if (savableIds.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "showSaveLocked(): service doesn't want to save");
+ return;
+ }
+
+ final int size = savableIds.size();
+ for (int i = 0; i < size; i++) {
+ final AutoFillId id = savableIds.valueAt(i);
+ final ViewState state = mViewStates.get(id);
+ if (state != null && state.mValueUpdated) {
+ final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
+ if (state.mAutoFillValue == null || state.mAutoFillValue.equals(filledValue)) {
+ continue;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
+ + state.mAutoFillValue);
+ }
+
+ mUi.showSaveUi();
+ return;
+ }
+ }
+ // Nothing changed...
+ if (DEBUG) Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities");
+ }
+
+ /**
+ * Calls service when user requested save.
+ */
+ private void callSaveLocked() {
+ if (DEBUG) Slog.d(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
+
+ // TODO(b/33197203): hookup extras and make sure they're tested by CTS
+ final Bundle extras = null;
+// // TODO(b/33197203): make sure the extras are tested by CTS
+// final Bundle responseExtras = mCurrentResponse == null ? null
+// : mCurrentResponse.getExtras();
+// final Bundle datasetExtras = mAutoFilledDataset == null ? null
+// : mAutoFilledDataset.getExtras();
+// final Bundle extras = (responseExtras == null && datasetExtras == null)
+// ? null : new Bundle();
+// if (responseExtras != null) {
+// if (DEBUG) {
+// Slog.d(TAG, "response extras on save extras: "
+// + bundleToString(responseExtras));
+// }
+// extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, responseExtras);
+// }
+// if (datasetExtras != null) {
+// if (DEBUG) {
+// Slog.d(TAG, "dataset extras on save extras: " + bundleToString(datasetExtras));
+// }
+// extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetExtras);
+// }
+
+
+ for (Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
+ final AutoFillValue value = entry.getValue().mAutoFillValue;
+ if (value == null) {
+ if (VERBOSE) Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
+ continue;
+ }
+ final AutoFillId id = entry.getKey();
+ final ViewNode node = findViewNodeByIdLocked(id);
+ if (node == null) {
+ Slog.w(TAG, "callSaveLocked(): did not find node with id " + id);
+ continue;
+ }
+ if (DEBUG) Slog.d(TAG, "callSaveLocked(): updating " + id + " to " + value);
+
+ node.updateAutoFillValue(value);
+ }
+
+ mStructure.sanitizeForParceling(false);
+
+ if (VERBOSE) {
+ Slog.v(TAG, "Dumping " + mStructure + " before calling service.save()");
+ mStructure.dump();
+ }
+
+ mRemoteFillService.onSaveRequest(mStructure, extras);
+ }
+
+ void updateLocked(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
+ if (DEBUG) Slog.d(TAG, "updateLocked(): id=" + id + ", flags=" + flags);
+
+ if (mAutoFilledDataset != null && (flags & FLAG_VALUE_CHANGED) == 0) {
+ // TODO(b/33197203): ignoring because we don't support partitions yet
+ if (DEBUG) Slog.d(TAG, "updateLocked(): ignoring " + flags + " after auto-filled");
+ return;
+ }
+
+ ViewState viewState = mViewStates.get(id);
+ if (viewState == null) {
+ viewState = new ViewState(id, this);
+ mViewStates.put(id, viewState);
+ }
+
+ if ((flags & FLAG_START_SESSION) != 0 ) {
+ // View is triggering auto-fill.
+ mCurrentViewState = viewState;
+ viewState.update(value, bounds);
+ return;
+ }
+
+ if ((flags & FLAG_VALUE_CHANGED) != 0 && value != null &&
+ !value.equals(viewState.mAutoFillValue)) {
+ viewState.mValueUpdated = true;
+
+ // Must check if this update was caused by auto-filling the view, in which
+ // case we just update the value, but not the UI.
+ if (mAutoFilledDataset != null) {
+ final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
+ if (value.equals(filledValue)) {
+ viewState.mAutoFillValue = value;
+ return;
+ }
+ }
+
+ // Just change value, don't update the UI
+ viewState.mAutoFillValue = value;
+ return;
+ }
+
+ if ((flags & FLAG_FOCUS_GAINED) != 0) {
+ // Remove the UI if the ViewState has changed.
+ if (mCurrentViewState != viewState) {
+ mUi.hideFillUi();
+ mCurrentViewState = viewState;
+ }
+
+ // If the ViewState is ready to be displayed, onReady() will be called.
+ viewState.update(value, bounds);
+
+ // TODO(b/33197203): Remove when there is a response per activity.
+ if (mCurrentResponse != null) {
+ viewState.setResponse(mCurrentResponse);
+ }
+
+ return;
+ }
+
+ if ((flags & FLAG_FOCUS_LOST) != 0) {
+ if (mCurrentViewState == viewState) {
+ mUi.hideFillUi();
+ mCurrentViewState = null;
+ }
+ return;
+ }
+
+ Slog.w(TAG, "unknown flags " + flags);
+ }
+
+ @Override
+ public void onFillReady(ViewState viewState, FillResponse response, Rect bounds,
+ @Nullable AutoFillValue value) {
+ String filterText = "";
+ if (value != null) {
+ // TODO(b/33197203): Handle other AutoFillValue types
+ final CharSequence text = value.getTextValue();
+ if (text != null) {
+ filterText = text.toString();
+ }
+ }
+
+ getUiForShowing().showFillUi(mActivityToken, viewState, response.getDatasets(),
+ bounds, filterText);
+ }
+
+ private void processResponseLocked(FillResponse response) {
+ if (DEBUG) Slog.d(TAG, "processResponseLocked(authRequired="
+ + response.getAuthentication() +"):" + response);
+
+ // TODO(b/33197203): add MetricsLogger calls
+
+ mCurrentResponse = response;
+
+ if (mCurrentResponse.getAuthentication() != null) {
+ // Handle authentication.
+ final Intent fillInIntent = createAuthFillInIntent(response.getId(), mStructure,
+ new Bundle(), new FillCallback(new IFillCallback.Stub() {
+ @Override
+ public void onCancellable(ICancellationSignal cancellation) {
+ // TODO(b/33197203): Handle cancellation
+ }
+
+ @Override
+ public void onSuccess(FillResponse response) {
+ mCurrentResponse = createAuthenticatedResponse(
+ mCurrentResponse, response);
+ processResponseLocked(mCurrentResponse);
+ }
+
+ @Override
+ public void onFailure(CharSequence message) {
+ getUiForShowing().showError(message);
+ removeSelf();
+ }
+ }));
+
+ getUiForShowing().showFillResponseAuthRequest(
+ mCurrentResponse.getAuthentication(), fillInIntent);
+ return;
+ }
+
+ final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
+ if (savableIds == null || savableIds.isEmpty()) {
+ // NOTE: it's assuming the response has no datasets, since when a dataset is added
+ // it's view id is automatically added to savable_ids
+ if (DEBUG) Slog.d(TAG, "processResponseLocked(): nothing to do");
+
+ removeSelf();
+ return;
+ }
+
+ // TODO(b/33197203): Consider using mCurrentResponse, depends on partitioning design
+ if (mCurrentViewState != null) {
+ mCurrentViewState.setResponse(mCurrentResponse);
+ }
+ }
+
+ void autoFill(Dataset dataset) {
+ synchronized (mLock) {
+ // Autofill it directly...
+ if (dataset.getAuthentication() == null) {
+ autoFillApp(dataset);
+ return;
+ }
+
+ // ...or handle authentication.
+ Intent fillInIntent = createAuthFillInIntent(dataset.getId(), mStructure,
+ new Bundle(), new FillCallback(new IFillCallback.Stub() {
+ @Override
+ public void onCancellable(ICancellationSignal cancellation) {
+ // TODO(b/33197203): Handle cancellation
+ }
+
+ @Override
+ public void onSuccess(FillResponse response) {
+ mCurrentResponse = createAuthenticatedResponse(
+ mCurrentResponse, response);
+ final Dataset augmentedDataset = Helper.findDatasetById(dataset.getId(),
+ mCurrentResponse);
+ if (augmentedDataset != null) {
+ autoFill(augmentedDataset);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence message) {
+ getUiForShowing().showError(message);
+ removeSelf();
+ }
+ }));
+
+ startAuthIntent(dataset.getAuthentication(), fillInIntent);
+ }
+ }
+
+ private Intent createAuthFillInIntent(String itemId, AssistStructure structure,
+ Bundle extras, FillCallback fillCallback) {
+ Intent fillInIntent = new Intent();
+ fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_ITEM_ID, itemId);
+ fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_ASSIST_STRUCTURE, structure);
+ fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_EXTRAS, extras);
+ fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_CALLBACK, fillCallback);
+ return fillInIntent;
+ }
+
+ private void startAuthIntent(IntentSender intent, Intent fillInIntent) {
+ try {
+ mAppCallback.startIntentSender(intent, fillInIntent);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error launching auth intent", e);
+ }
+ }
+
+ void dumpLocked(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
+ pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
+ pw.print(prefix); pw.print("mAutoFilledDataset: "); pw.println(mAutoFilledDataset);
+ pw.print(prefix); pw.print("mCurrentViewStates: "); pw.println(mCurrentViewState);
+ pw.print(prefix); pw.print("mViewStates: "); pw.println(mViewStates.size());
+ final String prefix2 = prefix + " ";
+ for (Map.Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
+ pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
+ entry.getValue().dump(prefix2, pw);
+ }
+ if (VERBOSE) {
+ pw.print(prefix); pw.print("mStructure: " );
+ // TODO(b/33197203): add method do dump AssistStructure on pw
+ if (mStructure != null) {
+ pw.println("look at logcat" );
+ mStructure.dump(); // dumps to logcat
+ } else {
+ pw.println("null");
+ }
+ }
+
+ mRemoteFillService.dump(prefix, pw);
+ }
+
+ void autoFillApp(Dataset dataset) {
+ synchronized (mLock) {
+ try {
+ if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+
+ mAppCallback.autoFill(dataset);
+ mAutoFilledDataset = dataset;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error auto-filling activity: " + e);
+ }
+ }
+ }
+
+ void enableSessionLocked() {
+ if (DEBUG) Slog.d(TAG, "enableSessionLocked()");
+
+ try {
+ mAppCallback.enableSession();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error enabling session: " + e);
+ }
+ }
+
+ private AutoFillUI getUiForShowing() {
+ mUi.setCallback(this, mActivityToken);
+ return mUi;
+ }
+
+ private ViewNode findViewNodeByIdLocked(AutoFillId id) {
+ final int size = mStructure.getWindowNodeCount();
+ for (int i = 0; i < size; i++) {
+ final WindowNode window = mStructure.getWindowNodeAt(i);
+ final ViewNode root = window.getRootViewNode();
+ if (id.equals(root.getAutoFillId())) {
+ return root;
+ }
+ final ViewNode child = findViewNodeByIdLocked(root, id);
+ if (child != null) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ private ViewNode findViewNodeByIdLocked(ViewNode parent, AutoFillId id) {
+ final int childrenSize = parent.getChildCount();
+ if (childrenSize > 0) {
+ for (int i = 0; i < childrenSize; i++) {
+ final ViewNode child = parent.getChildAt(i);
+ if (id.equals(child.getAutoFillId())) {
+ return child;
+ }
+ final ViewNode grandChild = findViewNodeByIdLocked(child, id);
+ if (grandChild != null && id.equals(grandChild.getAutoFillId())) {
+ return grandChild;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void destroyLocked() {
+ mRemoteFillService.destroy();
+ mUi.hideAll();
+ mUi.setCallback(null, null);
}
private void removeSelf() {
+ if (VERBOSE) Slog.v(TAG, "removeSelf()");
+
synchronized (mLock) {
- removeServerCallbackLocked(id);
+ destroyLocked();
+ mSessions.remove(mActivityToken);
+ }
+ }
+
+ /**
+ * Creates a response from the {@code original} and an {@code update} by
+ * replacing all items that needed authentication (response or datasets)
+ * with their updated version if the latter does not need authentication.
+ * New datasets that don't require auth are appended.
+ *
+ * @param original The original response requiring auth at some level.
+ * @param update An updated response with auth not needed anymore at some level.
+ * @return A new response with updated items where auth is not needed anymore.
+ */
+ // TODO(b/33197203) Unit test
+ FillResponse createAuthenticatedResponse(FillResponse original, FillResponse update) {
+ // Can update only if ids match
+ if (!original.getId().equals(update.getId())) {
+ return original;
+ }
+
+ // If the original required auth and the update doesn't, the update wins
+ // but only if none of the update's datasets requires authentication.
+ if (original.getAuthentication() != null && update.getAuthentication() == null) {
+ ArraySet<Dataset> updateDatasets = update.getDatasets();
+ final int udpateDatasetCount = updateDatasets.size();
+ for (int i = 0; i < udpateDatasetCount; i++) {
+ Dataset updateDataset = updateDatasets.valueAt(i);
+ if (updateDataset.getAuthentication() != null) {
+ return original;
+ }
+ }
+ return update;
+ }
+
+ // If no auth on response level we create a response that has all
+ // datasets from the original with the ones that required auth but
+ // not anymore updated and new ones not requiring auth appended.
+
+ // The update shouldn't require auth
+ if (update.getAuthentication() != null) {
+ return original;
+ }
+
+ final FillResponse.Builder builder = new FillResponse.Builder(original.getId());
+
+ // Update existing datasets
+ final ArraySet<Dataset> origDatasets = original.getDatasets();
+ final int origDatasetCount = origDatasets.size();
+ for (int i = 0; i < origDatasetCount; i++) {
+ Dataset origDataset = origDatasets.valueAt(i);
+ ArraySet<Dataset> updateDatasets = update.getDatasets();
+ final int updateDatasetCount = updateDatasets.size();
+ for (int j = 0; j < updateDatasetCount; j++) {
+ Dataset updateDataset = updateDatasets.valueAt(j);
+ if (origDataset.getId().equals(updateDataset.getId())) {
+ // The update shouldn't require auth
+ if (updateDataset.getAuthentication() == null) {
+ origDataset = updateDataset;
+ updateDatasets.removeAt(j);
+ }
+ break;
+ }
+ }
+ builder.addDataset(origDataset);
}
+
+ // Add new datasets
+ final ArraySet<Dataset> updateDatasets = update.getDatasets();
+ final int updateDatasetCount = updateDatasets.size();
+ for (int i = 0; i < updateDatasetCount; i++) {
+ final Dataset updateDataset = updateDatasets.valueAt(i);
+ builder.addDataset(updateDataset);
+ }
+
+ // For now no extras and savable id updates.
+
+ return builder.build();
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index 26f24519ffc8..201a8890aad0 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -16,11 +16,7 @@
package com.android.server.autofill;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-
import android.app.ActivityManager;
-import android.os.Bundle;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -44,10 +40,8 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
final PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
- case "fill":
- return requestAutoFill(AUTO_FILL_FLAG_TYPE_FILL);
case "save":
- return requestAutoFill(AUTO_FILL_FLAG_TYPE_SAVE);
+ return requestSave();
default:
return handleDefaultCommands(cmd);
}
@@ -64,17 +58,15 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
pw.println(" help");
pw.println(" Prints this help text.");
pw.println("");
- pw.println(" fill [--user USER_ID]");
- pw.println(" Request provider to auto-fill the top activity. ");
pw.println(" save [--user USER_ID]");
pw.println(" Request provider to save contents of the top activity. ");
pw.println("");
}
}
- private int requestAutoFill(int flags) throws RemoteException {
+ private int requestSave() throws RemoteException {
final int userId = getUserIdFromArgs();
- mService.requestAutoFill(null, userId, null, flags);
+ mService.requestSaveForUser(userId);
return 0;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
index 08e81d36f9cf..e9fc0440ba3a 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -15,69 +15,105 @@
*/
package com.android.server.autofill;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+import static com.android.server.autofill.Helper.DEBUG;
-import static com.android.server.autofill.AutoFillManagerService.DEBUG;
-
-import android.app.Activity;
-import android.app.AppGlobals;
+import android.annotation.Nullable;
import android.app.Notification;
-import android.app.Notification.Action;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
+import android.content.IntentSender;
+import android.graphics.Rect;
import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.service.autofill.AutoFillService;
-import android.text.TextUtils;
-import android.util.Log;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.os.Looper;
+import android.text.format.DateUtils;
import android.util.Slog;
import android.view.autofill.Dataset;
-import android.view.autofill.AutoFillId;
import android.view.autofill.FillResponse;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import android.widget.Toast;
+import com.android.internal.os.HandlerCaller;
import com.android.server.UiThread;
+import com.android.server.autofill.AutoFillManagerServiceImpl.ViewState;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
+import java.io.PrintWriter;
/**
* Handles all auto-fill related UI tasks.
*/
// TODO(b/33197203): document exactly what once the auto-fill bar is implemented
final class AutoFillUI {
-
private static final String TAG = "AutoFillUI";
+ private static final long SNACK_BAR_LIFETIME_MS = 30 * DateUtils.SECOND_IN_MILLIS;
+ private static final int MSG_HIDE_SNACK_BAR = 1;
+
+ private static final String EXTRA_AUTH_INTENT_SENDER =
+ "com.android.server.autofill.extra.AUTH_INTENT_SENDER";
+ private static final String EXTRA_AUTH_FILL_IN_INTENT =
+ "com.android.server.autofill.extra.AUTH_FILL_IN_INTENT";
private final Context mContext;
+ private final WindowManager mWm;
+
+ // TODO(b/33197203) Fix locking - some state requires lock and some not - requires refactoring
+
+ // Fill UI variables
+ private AnchoredWindow mFillWindow;
+ private DatasetPicker mFillView;
+ private ViewState mViewState;
+
+ private AutoFillUiCallback mCallback;
+ private IBinder mActivityToken;
+
+ private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+ switch (msg.what) {
+ case MSG_HIDE_SNACK_BAR: {
+ hideSnackbarUiThread();
+ return;
+ }
+ default: {
+ Slog.w(TAG, "Invalid message: " + msg);
+ }
+ }
+ };
+ private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(),
+ mHandlerCallback, true);
+
+ /**
+ * Custom snackbar UI used for saving autofill or other informational messages.
+ */
+ private View mSnackbar;
- AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
+ AutoFillUI(Context context) {
mContext = context;
- mResolver = context.getContentResolver();
- mService = service;
- mLock = lock;
+ mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ }
+
+ void setCallback(AutoFillUiCallback callback, IBinder activityToken) {
+ hideAll();
+ mCallback = callback;
+ mActivityToken = activityToken;
}
/**
* Displays an error message to the user.
*/
- void showError(String message) {
+ void showError(CharSequence message) {
+ if (!hasCallback()) {
+ return;
+ }
+ hideAll();
// TODO(b/33197203): proper implementation
UiThread.getHandler().runWithScissors(() -> {
Toast.makeText(mContext, "AutoFill error: " + message, Toast.LENGTH_LONG).show();
@@ -85,224 +121,209 @@ final class AutoFillUI {
}
/**
- * Highlights in the {@link Activity} the fields saved by the service.
+ * Hides the fill UI.
*/
- void highlightSavedFields(AutoFillId[] ids) {
- // TODO(b/33197203): proper implementation (must be handled by activity)
+ void hideFillUi() {
UiThread.getHandler().runWithScissors(() -> {
- Toast.makeText(mContext, "AutoFill: service saved ids " + Arrays.toString(ids),
- Toast.LENGTH_LONG).show();
+ hideFillUiUiThread();
}, 0);
}
- /**
- * Shows the options from a {@link FillResponse} so the user can pick up the proper
- * {@link Dataset} (when the response has one).
- */
- void showOptions(int userId, int callbackId, FillResponse response) {
- // TODO(b/33197203): proper implementation
- // TODO(b/33197203): make sure if removes the callback from cache
- showOptionsNotification(userId, callbackId, response);
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- // TODO(b/33197203): temporary code using a notification to request auto-fill. //
- // Will be removed once UX decide the right way to present it to the user. //
- /////////////////////////////////////////////////////////////////////////////////
+ @android.annotation.UiThread
+ private void hideFillUiUiThread() {
+ if (mFillWindow != null) {
+ if (DEBUG) Slog.d(TAG, "hideFillUiUiThread(): hide" + mFillWindow);
+ mFillWindow.hide();
+ }
- // TODO(b/33197203): remove from frameworks/base/core/res/AndroidManifest.xml once not used
- private static final String NOTIFICATION_AUTO_FILL_INTENT =
- "com.android.internal.autofill.action.REQUEST_AUTOFILL";
+ mViewState = null;
+ mFillView = null;
+ mFillWindow = null;
+ }
- // Extras used in the notification intents
- private static final String EXTRA_USER_ID = "user_id";
- private static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
- private static final String EXTRA_CALLBACK_ID = "callback_id";
- private static final String EXTRA_FILL_RESPONSE = "fill_response";
- private static final String EXTRA_DATASET = "dataset";
+ /**
+ * Shows the fill UI, removing the previous fill UI if the has changed.
+ *
+ * @param appToken the token of the app to be autofilled
+ * @param viewState the view state, compared by reference to know if new UI should be shown
+ * @param datasets the datasets to show, not used if viewState is the same
+ * @param bounds bounds of the view to be filled, used if changed
+ * @param filterText text of the view to be filled, used if changed
+ */
+ void showFillUi(IBinder appToken, ViewState viewState, @Nullable ArraySet<Dataset> datasets,
+ Rect bounds, String filterText) {
+ if (!hasCallback()) {
+ return;
+ }
- private static final String TYPE_EMULATE = "emulate";
- private static final String TYPE_OPTIONS = "options";
- private static final String TYPE_DELETE_CALLBACK = "delete_callback";
- private static final String TYPE_PICK_DATASET = "pick_dataset";
- private static final String TYPE_SAVE = "save";
+ UiThread.getHandler().runWithScissors(() -> {
+ hideSnackbarUiThread();
+ hideFillResponseAuthUiUiThread();
+ }, 0);
- static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
- static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
+ if (datasets == null) {
+ // TODO(b/33197203): shouldn't be called, but keeping the WTF for a while just to be
+ // safe, otherwise it would crash system server...
+ Slog.wtf(TAG, "showFillUI(): no dataset");
+ return;
+ }
- private BroadcastReceiver mNotificationReceiver;
- private final ContentResolver mResolver;
- private final AutoFillManagerService mService;
- private final Object mLock;
+ UiThread.getHandler().runWithScissors(() -> {
+ if (mViewState == null || !mViewState.mId.equals(viewState.mId)) {
+ hideFillUiUiThread();
- // Hack used to generate unique pending intents
- static int sResultCode = 0;
+ mViewState = viewState;
- final class NotificationReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
+ mFillView = new DatasetPicker(mContext, datasets,
+ (dataset) -> {
+ final AutoFillUiCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ }
+ callback.fill(dataset);
+ hideFillUi();
+ });
- final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
- if (service == null) {
- Slog.w(TAG, "no auto-fill service for user " + userId);
- return;
- }
+ mFillWindow = new AnchoredWindow(mWm, appToken, mFillView);
- final int callbackId = intent.getIntExtra(EXTRA_CALLBACK_ID, -1);
- final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
- if (type == null) {
- Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
- return;
+ if (DEBUG) Slog.d(TAG, "showFillUi(): view changed");
}
- final FillResponse fillData = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
- final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
- final Bundle datasetArgs = dataset == null ? null : dataset.getExtras();
- final Bundle fillDataArgs = fillData == null ? null : fillData.getExtras();
- // Bundle sent on AutoFillService methods - only set if service provided a bundle
- final Bundle extras = (datasetArgs == null && fillDataArgs == null)
- ? null : new Bundle();
+ if (DEBUG) Slog.d(TAG, "showFillUi(): bounds=" + bounds + ", filterText=" + filterText);
+ mFillView.update(filterText);
+ mFillWindow.show(bounds);
+ }, 0);
+ }
- if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
- + ", callbackId=" + callbackId);
- synchronized (mLock) {
- switch (type) {
- case TYPE_EMULATE:
- service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_FILL);
- break;
- case TYPE_SAVE:
- if (datasetArgs != null) {
- if (DEBUG) Log.d(TAG, "filldata args on save notificataion: " +
- bundleToString(fillDataArgs));
- extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, fillDataArgs);
- }
- if (dataset != null) {
- if (DEBUG) Log.d(TAG, "dataset args on save notificataion: " +
- bundleToString(datasetArgs));
- extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
- }
- service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_SAVE);
- break;
- case TYPE_DELETE_CALLBACK:
- service.removeServerCallbackLocked(callbackId);
- break;
- case TYPE_PICK_DATASET:
- service.autoFillApp(callbackId, dataset);
- // Must cancel notification because it might be comming from action
- if (DEBUG) Log.d(TAG, "Cancelling notification");
- NotificationManager.from(mContext).cancel(TYPE_OPTIONS, userId);
-
- if (datasetArgs != null) {
- if (DEBUG) Log.d(TAG, "adding dataset's extra_data on save intent: "
- + bundleToString(datasetArgs));
- extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
- }
-
- // Also show notification with option to save the data
- showSaveNotification(userId, fillData, dataset);
- break;
- default: {
- Slog.w(TAG, "Unknown notification type: " + type);
- }
- }
- }
+ /**
+ * Shows an UI affordance indicating that user action is required before a {@link FillResponse}
+ * can be used.
+ *
+ * <p>It typically replaces the auto-fill bar with a message saying "Press fingerprint or tap to
+ * autofill" or "Tap to autofill", depending on the value of {@code usesFingerprint}.
+ */
+ void showFillResponseAuthRequest(IntentSender intent, Intent fillInIntent) {
+ if (!hasCallback()) {
+ return;
}
+ hideAll();
+ UiThread.getHandler().runWithScissors(() -> {
+ // TODO(b/33197203): proper implementation
+ showFillResponseAuthUiUiThread(intent, fillInIntent);
+ }, 0);
}
- private ComponentName getProviderForUser(int userId) {
- ComponentName serviceComponent = null;
- ServiceInfo serviceInfo = null;
- final String componentName = Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
- if (!TextUtils.isEmpty(componentName)) {
- try {
- serviceComponent = ComponentName.unflattenFromString(componentName);
- serviceInfo =
- AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
- } catch (RuntimeException | RemoteException e) {
- Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
- return null;
- }
+ /**
+ * Shows the UI asking the user to save for auto-fill.
+ */
+ void showSaveUi() {
+ if (!hasCallback()) {
+ return;
}
+ hideAll();
+ UiThread.getHandler().runWithScissors(() -> {
+ showSnackbarUiThread(new SavePrompt(mContext,
+ new SavePrompt.OnSaveListener() {
+ @Override
+ public void onSaveClick() {
+ hideSnackbarUiThread();
+ // TODO(b/33197203): add MetricsLogger call
+ mCallback.save();
+ }
- if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
- + serviceComponent + ", info: " + serviceInfo);
- if (serviceInfo == null) {
- Slog.w(TAG, "no service info for " + serviceComponent);
- return null;
- }
- return serviceComponent;
+ @Override
+ public void onCancelClick() {
+ // TODO(b/33197203): add MetricsLogger call
+ hideSnackbarUiThread();
+ }
+ }));
+ }, 0);
+ }
+
+ /**
+ * Hides all UI affordances.
+ */
+ void hideAll() {
+ UiThread.getHandler().runWithScissors(() -> {
+ hideSnackbarUiThread();
+ hideFillUiUiThread();
+ hideFillResponseAuthUiUiThread();
+ }, 0);
}
- void showAllNotifications() {
- final UserManager userManager =
- (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ void dump(PrintWriter pw) {
+ pw.println("AufoFill UI");
+ final String prefix = " ";
+ pw.print(prefix); pw.print("sResultCode: "); pw.println(sResultCode);
+ pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
+ pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar);
+ pw.print(prefix); pw.print("mViewState: "); pw.println(mViewState);
+ }
- final List<UserInfo> allUsers = userManager.getUsers(true);
+ //similar to a snackbar, but can be a bit custom since it is more than just text. This will
+ //allow two buttons for saving or not saving the autofill for instance as well.
+ private void showSnackbarUiThread(View snackBar) {
+ final LayoutParams params = new LayoutParams();
+ params.setTitle("AutoFill Save");
+ params.type = LayoutParams.TYPE_PHONE; // TODO(b/33197203) use app window token
+ params.flags =
+ LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events,
+ | LayoutParams.FLAG_ALT_FOCUSABLE_IM // resize for soft input
+ | LayoutParams.FLAG_NOT_TOUCH_MODAL; // outside touches go to windows behind us
+ params.softInputMode =
+ LayoutParams.SOFT_INPUT_ADJUST_PAN; // pan with soft input
+ params.gravity = Gravity.BOTTOM | Gravity.START;
+ params.width = LayoutParams.MATCH_PARENT;
+ params.height = LayoutParams.WRAP_CONTENT;
- for (UserInfo user : allUsers) {
- final ComponentName serviceComponent = getProviderForUser(user.id);
- if (serviceComponent != null) {
- showMainNotification(serviceComponent, user.id);
- }
+ UiThread.getHandler().runWithScissors(() -> {
+ mSnackbar = snackBar;
+ mWm.addView(mSnackbar, params);
+ }, 0);
+
+ if (DEBUG) {
+ Slog.d(TAG, "showSnackbar(): auto dismissing it in " + SNACK_BAR_LIFETIME_MS + " ms");
}
+ mHandlerCaller.sendMessageDelayed(mHandlerCaller.obtainMessage(MSG_HIDE_SNACK_BAR),
+ SNACK_BAR_LIFETIME_MS);
}
- void updateNotification(int userId) {
- final ComponentName serviceComponent = getProviderForUser(userId);
- if (serviceComponent == null) {
- cancelMainNotification(userId);
- } else {
- showMainNotification(serviceComponent, userId);
+ private void hideSnackbarUiThread() {
+ mHandlerCaller.getHandler().removeMessages(MSG_HIDE_SNACK_BAR);
+ if (mSnackbar != null) {
+ mWm.removeView(mSnackbar);
+ mSnackbar = null;
}
}
- private static Intent newNotificationIntent(int userId, String type) {
- final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
- intent.putExtra(EXTRA_USER_ID, userId);
- intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
- return intent;
+ private boolean hasCallback() {
+ synchronized (mLock) {
+ return mCallback != null;
+ }
}
- private PendingIntent newPickDatasetPI(int userId, int callbackId, FillResponse response,
- Dataset dataset) {
- final int resultCode = ++ sResultCode;
- if (DEBUG) Log.d(TAG, "newPickDatasetPI: userId=" + userId + ", callback=" + callbackId
- + ", resultCode=" + resultCode);
-
- final Intent intent = newNotificationIntent(userId, TYPE_PICK_DATASET);
- intent.putExtra(EXTRA_CALLBACK_ID, callbackId);
- intent.putExtra(EXTRA_FILL_RESPONSE, response);
- intent.putExtra(EXTRA_DATASET, dataset);
- return PendingIntent.getBroadcast(mContext, resultCode, intent,
- PendingIntent.FLAG_ONE_SHOT);
+ interface AutoFillUiCallback {
+ void authenticate(IntentSender intent, Intent fillInIntent);
+ void fill(Dataset dataset);
+ void save();
}
- private static String bundleToString(Bundle bundle) {
- if (bundle == null) {
- return "null";
- }
- final Set<String> keySet = bundle.keySet();
- final StringBuilder builder = new StringBuilder("[Bundle with ").append(keySet.size())
- .append(" keys:");
- for (String key : keySet) {
- final Object value = bundle.get(key);
- builder.append(' ').append(key).append('=');
- builder.append((value instanceof Object[])
- ? Arrays.toString((Objects[]) value) : value);
- }
- return builder.append(']').toString();
- }
+ /////////////////////////////////////////////////////////////////////////////////
+ // TODO(b/33197203): temporary code using a notification to request auto-fill. //
+ // Will be removed once UX decide the right way to present it to the user. //
+ /////////////////////////////////////////////////////////////////////////////////
- /**
- * Shows a permanent notification that triggers the auto-fill workflow for the given user.
- *
- * <p>It emulates calling the auto-fill service when the IME is shown.
- */
- private void showMainNotification(ComponentName serviceComponent, int userId) {
- if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
+ // TODO(b/33197203): remove from frameworks/base/core/res/AndroidManifest.xml once not used
+ private static final String NOTIFICATION_AUTO_FILL_INTENT =
+ "com.android.internal.autofill.action.REQUEST_AUTOFILL";
+
+ private BroadcastReceiver mNotificationReceiver;
+ private final Object mLock = new Object();
+ // Hack used to generate unique pending intents
+ static int sResultCode = 0;
+
+ private void ensureNotificationListener() {
synchronized (mLock) {
if (mNotificationReceiver == null) {
mNotificationReceiver = new NotificationReceiver();
@@ -310,161 +331,78 @@ final class AutoFillUI {
new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
}
}
+ }
- final Intent fillIntent = newNotificationIntent(userId, TYPE_EMULATE);
- final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
- -1, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- final String packageName = serviceComponent.getPackageName();
- String providerName = null;
- final PackageManager pm = mContext.getPackageManager();
- try {
- final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
- if (info != null) {
- providerName = pm.getApplicationLabel(info).toString();
+ final class NotificationReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final AutoFillUiCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ }
+ if (callback != null) {
+ IntentSender intentSender = intent.getParcelableExtra(EXTRA_AUTH_INTENT_SENDER);
+ Intent fillInIntent = intent.getParcelableExtra(EXTRA_AUTH_FILL_IN_INTENT);
+ callback.authenticate(intentSender, fillInIntent);
}
- } catch (Exception e) {
- providerName = packageName;
+ collapseStatusBar();
}
- final String title = "AutoFill IME Emulation";
- final String subTitle = "Tap notification to start auto-fill workflow (by '" + providerName
- + "' on top activity on user " + userId + ".\n"
- + "Once provider replies, a new notification will show your options.";
-
- final Notification notification = new Notification.Builder(mContext)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setOngoing(true)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setLocalOnly(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setStyle(new Notification.BigTextStyle().bigText(subTitle))
- .setContentIntent(fillPendingIntent)
- .build();
- NotificationManager.from(mContext).notify(TYPE_EMULATE, userId, notification);
}
- /**
- * Cancels the permament notification created by
- * {@link #showMainNotification(ComponentName, int)}.
- */
- private void cancelMainNotification(int userId) {
- if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
- NotificationManager.from(mContext).cancel(TYPE_EMULATE, userId);
- }
+ @android.annotation.UiThread
+ private void showFillResponseAuthUiUiThread(IntentSender intent, Intent fillInIntent) {
+ final String title = "AutoFill Authentication";
+ final StringBuilder subTitle = new StringBuilder("Provider require user authentication.\n");
- /**
- * Shows a notification with the results of an auto-fill request, using notications actions
- * to emulate the auto-fill bar buttons displaying the dataset names.
- */
- private void showOptionsNotification(int userId, int callbackId, FillResponse response) {
- final long token = Binder.clearCallingIdentity();
- try {
- showOptionsNotificationAsSystem(userId, callbackId, response);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
+ final Intent authIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+ authIntent.putExtra(EXTRA_AUTH_INTENT_SENDER, intent);
+ authIntent.putExtra(EXTRA_AUTH_FILL_IN_INTENT, fillInIntent);
- private void showOptionsNotificationAsSystem(int userId, int callbackId,
- FillResponse response) {
- // Make sure server callback is removed from cache if user cancels the notification.
- final Intent deleteIntent = newNotificationIntent(userId, TYPE_DELETE_CALLBACK);
- deleteIntent.putExtra(EXTRA_CALLBACK_ID, callbackId);
- final PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext,
- ++sResultCode, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
+ final PendingIntent authPendingIntent = PendingIntent.getBroadcast(
+ mContext, ++sResultCode, authIntent, PendingIntent.FLAG_ONE_SHOT);
- final String title = "AutoFill Options";
+ subTitle.append("Tap notification to launch its authentication UI.");
- final Notification.Builder notification = new Notification.Builder(mContext)
- .setCategory(Notification.CATEGORY_SYSTEM)
+ final Notification.Builder notification = newNotificationBuilder()
+ .setAutoCancel(true)
.setOngoing(false)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setLocalOnly(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setDeleteIntent(deletePendingIntent)
- .setContentTitle(title);
-
- boolean autoCancel = true;
- final String subTitle;
- final List<Dataset> datasets;
- final AutoFillId[] savableIds;
- if (response != null) {
- datasets = response.getDatasets();
- savableIds = response.getSavableIds();
- } else {
- datasets = null;
- savableIds = null;
- }
- boolean showSave = false;
- if (datasets == null ) {
- subTitle = "No options to auto-fill this activity.";
- } else if (datasets.isEmpty()) {
- if (savableIds.length == 0) {
- subTitle = "No options to auto-fill this activity.";
- } else {
- subTitle = "No options to auto-fill this activity, but provider can save ids:\n"
- + Arrays.toString(savableIds);
- showSave = true;
- }
- } else {
- final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
- if (service == null) {
- subTitle = "No auto-fill service for user " + userId;
- Slog.w(TAG, subTitle);
- } else {
- autoCancel = false;
- final int size = datasets.size();
- subTitle = "There are " + size + " option(s).\n"
- + "Use the notification action(s) to select the proper one.";
- for (Dataset dataset : datasets) {
- final CharSequence name = dataset.getName();
- final PendingIntent pi = newPickDatasetPI(userId, callbackId, response, dataset);
- notification.addAction(new Action.Builder(null, name, pi).build());
- }
- }
- }
-
- notification.setAutoCancel(autoCancel);
- notification.setStyle(new Notification.BigTextStyle().bigText(subTitle));
+ .setContentTitle(title)
+ .setStyle(new Notification.BigTextStyle().bigText(subTitle.toString()))
+ .setContentIntent(authPendingIntent);
- NotificationManager.from(mContext).notify(TYPE_OPTIONS, userId, notification.build());
+ ensureNotificationListener();
- if (showSave) {
- showSaveNotification(userId, response, null);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ NotificationManager.from(mContext).notify(0, notification.build());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
- private void showSaveNotification(int userId, FillResponse response, Dataset dataset) {
- final Intent saveIntent = newNotificationIntent(userId, TYPE_SAVE);
- saveIntent.putExtra(EXTRA_FILL_RESPONSE, response);
- if (dataset != null) {
- saveIntent.putExtra(EXTRA_DATASET, dataset);
+ @android.annotation.UiThread
+ private void hideFillResponseAuthUiUiThread() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ NotificationManager.from(mContext).cancel(0);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
- ++sResultCode, saveIntent, PendingIntent.FLAG_ONE_SHOT);
-
- final String title = "AutoFill Save";
- final String subTitle = "Tap notification to ask provider to save fields: \n"
- + Arrays.toString(response.getSavableIds());
+ }
- final Notification notification = new Notification.Builder(mContext)
+ private Notification.Builder newNotificationBuilder() {
+ return new Notification.Builder(mContext)
.setCategory(Notification.CATEGORY_SYSTEM)
- .setAutoCancel(true)
- .setOngoing(false)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setLocalOnly(true)
.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentIntent(savePendingIntent)
- .setStyle(new Notification.BigTextStyle().bigText(subTitle))
- .build();
- NotificationManager.from(mContext).notify(TYPE_SAVE, userId, notification);
+ com.android.internal.R.color.system_notification_accent_color));
}
+ private void collapseStatusBar() {
+ final StatusBarManager sbm = (StatusBarManager) mContext.getSystemService("statusbar");
+ sbm.collapsePanels();
+ }
/////////////////////////////////////////
// End of temporary notification code. //
/////////////////////////////////////////
diff --git a/services/autofill/java/com/android/server/autofill/DatasetPicker.java b/services/autofill/java/com/android/server/autofill/DatasetPicker.java
new file mode 100644
index 000000000000..8212cf15d257
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/DatasetPicker.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.ArraySet;
+import android.view.autofill.Dataset;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Filter.FilterListener;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * View for dataset picker.
+ *
+ * <p>A fill session starts when a View is clicked and FillResponse is supplied.
+ * <p>A fill session ends when 1) the user takes action in the UI, 2) another View is clicked, or
+ * 3) the View is detached.
+ */
+final class DatasetPicker extends ListView implements OnItemClickListener {
+ interface Listener {
+ void onDatasetPicked(Dataset dataset);
+ }
+
+ private final Listener mListener;
+
+ DatasetPicker(Context context, ArraySet<Dataset> datasets, Listener listener) {
+ super(context);
+ mListener = listener;
+
+ final List<ViewItem> items = new ArrayList<>(datasets.size());
+ for (Dataset dataset : datasets) {
+ items.add(new ViewItem(dataset));
+ }
+
+ final ArrayAdapter<ViewItem> adapter = new ArrayAdapter<ViewItem>(
+ context,
+ android.R.layout.simple_list_item_1,
+ android.R.id.text1,
+ items) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final TextView textView = (TextView) super.getView(position, convertView, parent);
+ textView.setMinHeight(
+ getDimen(com.android.internal.R.dimen.autofill_fill_item_height));
+ return textView;
+ }
+ };
+ setAdapter(adapter);
+ setBackgroundColor(Color.WHITE);
+ setDivider(null);
+ setElevation(getDimen(com.android.internal.R.dimen.autofill_fill_elevation));
+ setOnItemClickListener(this);
+ }
+
+ public void update(String prefix) {
+ final ArrayAdapter<ViewItem> adapter = (ArrayAdapter) getAdapter();
+ adapter.getFilter().filter(prefix, new FilterListener() {
+ @Override
+ public void onFilterComplete(int count) {
+ setVisibility(count > 0 ? View.VISIBLE : View.GONE);
+ }
+ });
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
+ if (mListener != null) {
+ final ViewItem vi = (ViewItem) adapterView.getItemAtPosition(pos);
+ mListener.onDatasetPicked(vi.getData());
+ }
+ }
+
+ private int getDimen(int resId) {
+ return getContext().getResources().getDimensionPixelSize(resId);
+ }
+
+ private static class ViewItem {
+ private final Dataset mData;
+
+ ViewItem(Dataset data) {
+ mData = data;
+ }
+
+ public Dataset getData() {
+ return mData;
+ }
+
+ @Override
+ public String toString() {
+ // used by ArrayAdapter
+ return mData.getName().toString();
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
new file mode 100644
index 000000000000..7400a64c36f8
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.Dataset;
+import android.view.autofill.FillResponse;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Set;
+
+final class Helper {
+
+ static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+ static final boolean VERBOSE = false;
+ static final String REDACTED = "[REDACTED]";
+
+ static void append(StringBuilder builder, Bundle bundle) {
+ if (bundle == null) {
+ builder.append("N/A");
+ } else if (!DEBUG) {
+ builder.append(REDACTED);
+ } else {
+ final Set<String> keySet = bundle.keySet();
+ builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
+ for (String key : keySet) {
+ final Object value = bundle.get(key);
+ builder.append(' ').append(key).append('=');
+ builder.append((value instanceof Object[])
+ ? Arrays.toString((Objects[]) value) : value);
+ }
+ builder.append(']');
+ }
+ }
+
+ static String bundleToString(Bundle bundle) {
+ final StringBuilder builder = new StringBuilder();
+ append(builder, bundle);
+ return builder.toString();
+ }
+
+ /**
+ * Gets the value of a {@link Dataset} field by its id, or {@code null} if not found.
+ */
+ @Nullable
+ static AutoFillValue findValue(Dataset dataset, AutoFillId id) {
+ if (dataset != null) {
+ final ArrayList<AutoFillId> ids = dataset.getFieldIds();
+ final int size = ids.size();
+ for (int i = 0; i < size; i++) {
+ if (id.equals(ids.get(i))) {
+ return dataset.getFieldValues().get(i);
+ }
+
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds a data set by id in a response.
+ *
+ * @param id The dataset id.
+ * @param response The response to search.
+ * @return The dataset if found or null.
+ */
+ static Dataset findDatasetById(String id, FillResponse response) {
+ ArraySet<Dataset> datasets = response.getDatasets();
+ if (datasets == null || datasets.isEmpty()) {
+ return null;
+ }
+ final int datasetCount = datasets.size();
+ for (int i = 0; i < datasetCount; i++) {
+ Dataset dataset = datasets.valueAt(i);
+ if (dataset.getId().equals(id)) {
+ return dataset;
+ }
+ }
+ return null;
+ }
+
+ private Helper() {
+ throw new UnsupportedOperationException("contains static members only");
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
new file mode 100644
index 000000000000..c070f779c6f9
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.ICancellationSignal;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.IAutoFillService;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.ISaveCallback;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.autofill.FillResponse;
+import com.android.internal.os.HandlerCaller;
+import com.android.server.FgThread;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * This class represents a remote fill service. It abstracts away the binding
+ * and unbinding from the remote implementation.
+ *
+ * <p>Clients can call methods of this class without worrying about when and
+ * how to bind/unbind/timeout. All state of this class is modified on a handler
+ * thread.
+ */
+final class RemoteFillService implements DeathRecipient {
+ private static final String LOG_TAG = "RemoteFillService";
+
+ private static final boolean DEBUG = Helper.DEBUG;
+
+ // How long after the last interaction with the service we would unbind
+ private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ private final Context mContext;
+
+ private final ComponentName mComponentName;
+
+ private final Intent mIntent;
+
+ private final FillServiceCallbacks mCallbacks;
+
+ private final int mUserId;
+
+ private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
+
+ private final HandlerCaller mHandler;
+
+ private IAutoFillService mAutoFillService;
+
+ private boolean mBinding;
+
+ private boolean mDestroyed;
+
+ private boolean mServiceDied;
+
+ private boolean mCompleted;
+
+ private PendingRequest mPendingRequest;
+
+ public interface FillServiceCallbacks {
+ void onFillRequestSuccess(FillResponse response);
+ void onFillRequestFailure(CharSequence message);
+ void onSaveRequestSuccess();
+ void onSaveRequestFailure(CharSequence message);
+ void onServiceDied(RemoteFillService service);
+ }
+
+ public RemoteFillService(Context context, ComponentName componentName,
+ int userId, FillServiceCallbacks callbacks) {
+ mContext = context;
+ mCallbacks = callbacks;
+ mComponentName = componentName;
+ mIntent = new Intent(AutoFillService.SERVICE_INTERFACE)
+ .setComponent(mComponentName);
+ mUserId = userId;
+ mHandler = new MyHandler(context);
+ }
+
+ public void destroy() {
+ mHandler.obtainMessage(MyHandler.MSG_DESTROY).sendToTarget();
+ }
+
+ private void handleDestroy() {
+ if (mPendingRequest != null) {
+ mPendingRequest.cancel();
+ mPendingRequest = null;
+ }
+ ensureUnbound();
+ mDestroyed = true;
+ }
+
+ @Override
+ public void binderDied() {
+ mHandler.obtainMessage(MyHandler.MSG_BINDER_DIED).sendToTarget();
+ }
+
+ private void handleBinderDied() {
+ if (mAutoFillService != null) {
+ mAutoFillService.asBinder().unlinkToDeath(this, 0);
+ }
+ mAutoFillService = null;
+ mServiceDied = true;
+ mCallbacks.onServiceDied(this);
+ }
+
+ public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+ cancelScheduledUnbind();
+ PendingFillRequest request = new PendingFillRequest(structure, extras, this);
+ mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+ }
+
+ public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+ cancelScheduledUnbind();
+ PendingSaveRequest request = new PendingSaveRequest(structure, extras, this);
+ mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+ }
+
+ // Note: we are dumping without a lock held so this is a bit racy but
+ // adding a lock to a class that offloads to a handler thread would
+ // mean adding a lock adding overhead to normal runtime operation.
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ String tab = " ";
+ pw.append(prefix).append("service:").println();
+ pw.append(prefix).append(tab).append("userId=")
+ .append(String.valueOf(mUserId)).println();
+ pw.append(prefix).append(tab).append("componentName=")
+ .append(mComponentName.flattenToString()).println();
+ pw.append(prefix).append(tab).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append(tab).append("bound=")
+ .append(String.valueOf(isBound())).println();
+ pw.append(prefix).append(tab).append("hasPendingRequest=")
+ .append(String.valueOf(mPendingRequest != null)).println();
+ pw.println();
+ }
+
+ private void cancelScheduledUnbind() {
+ mHandler.removeMessages(MyHandler.MSG_UNBIND);
+ }
+
+ private void scheduleUnbind() {
+ cancelScheduledUnbind();
+ Message message = mHandler.obtainMessage(MyHandler.MSG_UNBIND);
+ mHandler.sendMessageDelayed(message, TIMEOUT_IDLE_BIND_MILLIS);
+ }
+
+ private void handleUnbind() {
+ ensureUnbound();
+ }
+
+ private void handlePendingRequest(PendingRequest pendingRequest) {
+ if (mDestroyed || mCompleted) {
+ return;
+ }
+ if (pendingRequest.isFinal()) {
+ mCompleted = true;
+ }
+ if (!isBound()) {
+ if (mPendingRequest != null) {
+ mPendingRequest.cancel();
+ }
+ mPendingRequest = pendingRequest;
+ ensureBound();
+ } else {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "[user: " + mUserId + "] handleOnFillRequest()");
+ }
+ pendingRequest.run();
+ }
+ }
+
+ private boolean isBound() {
+ return mAutoFillService != null;
+ }
+
+ private void ensureBound() {
+ if (isBound() || mBinding) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
+ }
+ mBinding = true;
+
+ boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(mUserId));
+
+ if (!willBind) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
+ }
+ mBinding = false;
+
+ if (!mServiceDied) {
+ handleBinderDied();
+ }
+ }
+ }
+
+ private void ensureUnbound() {
+ if (!isBound() && !mBinding) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
+ }
+ mBinding = false;
+ if (isBound()) {
+ mAutoFillService.asBinder().unlinkToDeath(this, 0);
+ mAutoFillService = null;
+ }
+ mContext.unbindService(mServiceConnection);
+ }
+
+ private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
+ FillResponse response) {
+ mHandler.getHandler().post(() -> {
+ if (handleResponseCallbackCommon(pendingRequest)) {
+ mCallbacks.onFillRequestSuccess(response);
+ }
+ });
+ }
+
+ private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
+ CharSequence message) {
+ mHandler.getHandler().post(() -> {
+ if (handleResponseCallbackCommon(pendingRequest)) {
+ mCallbacks.onFillRequestFailure(message);
+ }
+ });
+ }
+
+ private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
+ mHandler.getHandler().post(() -> {
+ if (handleResponseCallbackCommon(pendingRequest)) {
+ mCallbacks.onSaveRequestSuccess();
+ }
+ });
+ }
+
+ private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
+ CharSequence message) {
+ mHandler.getHandler().post(() -> {
+ if (handleResponseCallbackCommon(pendingRequest)) {
+ mCallbacks.onSaveRequestFailure(message);
+ }
+ });
+ }
+
+ private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) {
+ if (mDestroyed) {
+ return false;
+ }
+ if (mPendingRequest == pendingRequest) {
+ mPendingRequest = null;
+ }
+ if (mPendingRequest == null) {
+ scheduleUnbind();
+ }
+ return true;
+ }
+
+ private class RemoteServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (mDestroyed || !mBinding) {
+ mContext.unbindService(mServiceConnection);
+ return;
+ }
+ mBinding = false;
+ mAutoFillService = IAutoFillService.Stub.asInterface(service);
+ try {
+ service.linkToDeath(RemoteFillService.this, 0);
+ } catch (RemoteException re) {
+ handleBinderDied();
+ return;
+ }
+
+ if (mPendingRequest != null) {
+ handlePendingRequest(mPendingRequest);
+ }
+
+ mServiceDied = false;
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinding = true;
+ mAutoFillService = null;
+ }
+ }
+
+ private final class MyHandler extends HandlerCaller {
+ public static final int MSG_DESTROY = 1;
+ public static final int MSG_BINDER_DIED = 2;
+ public static final int MSG_UNBIND = 3;
+ public static final int MSG_ON_PENDING_REQUEST = 4;
+
+ public MyHandler(Context context) {
+ // Cannot use lambda - doesn't compile
+ super(context, FgThread.getHandler().getLooper(), new Callback() {
+ @Override
+ public void executeMessage(Message message) {
+ if (mDestroyed) {
+ Slog.w(LOG_TAG, "Not handling " + message + " as service for "
+ + mComponentName + " is already destroyed");
+ return;
+ }
+ switch (message.what) {
+ case MSG_DESTROY: {
+ handleDestroy();
+ } break;
+
+ case MSG_BINDER_DIED: {
+ handleBinderDied();
+ } break;
+
+ case MSG_UNBIND: {
+ handleUnbind();
+ } break;
+
+ case MSG_ON_PENDING_REQUEST: {
+ handlePendingRequest((PendingRequest) message.obj);
+ } break;
+ }
+ }
+ }, false);
+ }
+ }
+
+ private static abstract class PendingRequest implements Runnable {
+ void cancel() {
+
+ }
+
+ /**
+ * @return whether this request leads to a final state where no
+ * other requests can be made.
+ */
+ boolean isFinal() {
+ return false;
+ }
+ }
+
+ private static final class PendingFillRequest extends PendingRequest {
+ private final Object mLock = new Object();
+ private final WeakReference<RemoteFillService> mWeakService;
+ private AssistStructure mStructure;
+ private Bundle mExtras;
+ private final IFillCallback mCallback;
+ private ICancellationSignal mCancellation;
+ private boolean mCancelled;
+
+ public PendingFillRequest(AssistStructure structure,
+ Bundle extras, RemoteFillService service) {
+ mStructure = structure;
+ mExtras = extras;
+ mWeakService = new WeakReference<>(service);
+ mCallback = new IFillCallback.Stub() {
+ @Override
+ public void onCancellable(ICancellationSignal cancellation) {
+ synchronized (mLock) {
+ final boolean cancelled;
+ synchronized (mLock) {
+ mCancellation = cancellation;
+ cancelled = mCancelled;
+ }
+ if (cancelled) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error requesting a cancellation", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onSuccess(FillResponse response) {
+ RemoteFillService remoteService = mWeakService.get();
+ if (remoteService != null) {
+ remoteService.dispatchOnFillRequestSuccess(
+ PendingFillRequest.this, response);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence message) {
+ RemoteFillService remoteService = mWeakService.get();
+ if (remoteService != null) {
+ remoteService.dispatchOnFillRequestFailure(
+ PendingFillRequest.this, message);
+ }
+ }
+ };
+ }
+
+ @Override
+ public void run() {
+ RemoteFillService remoteService = mWeakService.get();
+ if (remoteService != null) {
+ try {
+ remoteService.mAutoFillService.onFillRequest(mStructure,
+ mExtras, mCallback);
+ synchronized (mLock) {
+ mStructure = null;
+ mExtras = null;
+ }
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error calling on fill request", e);
+ cancel();
+ }
+ }
+ }
+
+ @Override
+ public void cancel() {
+ final ICancellationSignal cancellation;
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
+ }
+ mCancelled = true;
+ cancellation = mCancellation;
+ }
+ if (cancellation == null) {
+ return;
+ }
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error cancelling a fill request", e);
+ }
+ }
+ }
+
+ private static final class PendingSaveRequest extends PendingRequest {
+ private final Object mLock = new Object();
+ private final WeakReference<RemoteFillService> mWeakService;
+ private AssistStructure mStructure;
+ private Bundle mExtras;
+ private final ISaveCallback mCallback;
+
+ public PendingSaveRequest(@NonNull AssistStructure structure,
+ @Nullable Bundle extras, @NonNull RemoteFillService service) {
+ mStructure = structure;
+ mExtras = extras;
+ mWeakService = new WeakReference<>(service);
+ mCallback = new ISaveCallback.Stub() {
+ @Override
+ public void onSuccess() {
+ RemoteFillService service = mWeakService.get();
+ if (service != null) {
+ service.dispatchOnSaveRequestSuccess(
+ PendingSaveRequest.this);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence message) {
+ RemoteFillService service = mWeakService.get();
+ if (service != null) {
+ service.dispatchOnSaveRequestFailure(
+ PendingSaveRequest.this, message);
+ }
+ }
+ };
+ }
+
+ @Override
+ public void run() {
+ RemoteFillService service = mWeakService.get();
+ if (service != null) {
+ try {
+ service.mAutoFillService.onSaveRequest(mStructure,
+ mExtras, mCallback);
+ synchronized (mLock) {
+ mStructure = null;
+ mExtras = null;
+ }
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error calling on save request", e);
+ }
+ }
+ }
+
+ @Override
+ public boolean isFinal() {
+ return true;
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/SavePrompt.java b/services/autofill/java/com/android/server/autofill/SavePrompt.java
new file mode 100644
index 000000000000..f0b51e260dcd
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/SavePrompt.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
+import android.widget.TextView;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * Autofill Save Prompt
+ */
+final class SavePrompt extends RelativeLayout {
+ public interface OnSaveListener {
+ void onSaveClick();
+ void onCancelClick();
+ }
+
+ private final TextView mNoButton;
+ private final TextView mYesButton;
+ private final OnSaveListener mListener;
+
+ SavePrompt(Context context, OnSaveListener listener) {
+ super(context);
+ mListener = listener;
+ LayoutInflater inflater = LayoutInflater.from(context);
+ View view = inflater.inflate(R.layout.autofill_save, this);
+
+ mNoButton = (TextView) view.findViewById(R.id.autofill_save_no);
+ mNoButton.setOnClickListener((v) -> {
+ mListener.onCancelClick();
+ });
+
+ mYesButton = (TextView) view.findViewById(R.id.autofill_save_yes);
+ mYesButton.setOnClickListener((v) -> {
+ mListener.onSaveClick();
+ });
+
+ //addView(view);
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 7e825860ead3..88c05b55116b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -34,13 +34,15 @@ import android.app.backup.BackupProgress;
import android.app.backup.BackupTransport;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
-import android.app.backup.IBackupObserver;
-import android.app.backup.RestoreDescription;
-import android.app.backup.RestoreSet;
import android.app.backup.IBackupManager;
+import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.app.backup.RestoreDescription;
+import android.app.backup.RestoreSet;
+import android.app.backup.SelectBackupTransportCallback;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -55,16 +57,15 @@ import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Environment.UserEnvironment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -79,15 +80,12 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.Environment.UserEnvironment;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
@@ -105,6 +103,8 @@ import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -139,7 +139,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Random;
@@ -166,8 +165,6 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
-import libcore.io.IoUtils;
-
public class BackupManagerService {
private static final String TAG = "BackupManagerService";
@@ -271,6 +268,8 @@ public class BackupManagerService {
private IStorageManager mStorageManager;
IBackupManager mBackupManagerBinder;
+ private final TransportManager mTransportManager;
+
boolean mEnabled; // access to this is synchronized on 'this'
boolean mProvisioned;
boolean mAutoRestore;
@@ -322,16 +321,6 @@ public class BackupManagerService {
final Object mClearDataLock = new Object();
volatile boolean mClearingData;
- // Transport bookkeeping
- final ArraySet<ComponentName> mTransportWhitelist;
- final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
- final ArrayMap<String,String> mTransportNames
- = new ArrayMap<String,String>(); // component name -> registration name
- final ArrayMap<String,IBackupTransport> mTransports
- = new ArrayMap<String,IBackupTransport>(); // registration name -> binder
- final ArrayMap<String,TransportConnection> mTransportConnections
- = new ArrayMap<String,TransportConnection>();
- String mCurrentTransport;
ActiveRestoreSession mActiveRestoreSession;
// Watch the device provisioning operation during setup
@@ -756,7 +745,7 @@ public class BackupManagerService {
{
mLastBackupPass = System.currentTimeMillis();
- IBackupTransport transport = getTransport(mCurrentTransport);
+ IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport == null) {
Slog.v(TAG, "Backup requested but no transport available");
synchronized (mQueueLock) {
@@ -1202,32 +1191,19 @@ public class BackupManagerService {
// Set up our transport options and initialize the default transport
// TODO: Don't create transports that we don't need to?
SystemConfig systemConfig = SystemConfig.getInstance();
- mTransportWhitelist = systemConfig.getBackupTransportWhitelist();
+ Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
String transport = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.BACKUP_TRANSPORT);
if (TextUtils.isEmpty(transport)) {
transport = null;
}
- mCurrentTransport = transport;
- if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
+ String currentTransport = transport;
+ if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
- // Find all transport hosts and bind to their services
- // TODO: http://b/22388012
- List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
- mTransportServiceIntent, 0, UserHandle.USER_SYSTEM);
- if (DEBUG) {
- Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
- }
- if (hosts != null) {
- for (int i = 0; i < hosts.size(); i++) {
- final ServiceInfo transportService = hosts.get(i).serviceInfo;
- if (MORE_DEBUG) {
- Slog.v(TAG, " " + transportService.packageName + "/" + transportService.name);
- }
- tryBindTransport(transportService);
- }
- }
+ mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
+ mTransportBoundListener);
+ mTransportManager.registerAllTransports();
// Now that we know about valid backup participants, parse any
// leftover journal files into the pending backup set
@@ -1751,7 +1727,7 @@ public class BackupManagerService {
mBackupHandler.removeMessages(MSG_RETRY_INIT);
try {
- IBackupTransport transport = getTransport(transportName);
+ IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
if (transport != null) {
String transportDirName = transport.transportDirName();
File stateDir = new File(mBaseStateDir, transportDirName);
@@ -1829,49 +1805,39 @@ public class BackupManagerService {
}
}
- // Add a transport to our set of available backends. If 'transport' is null, this
- // is an unregistration, and the transport's entry is removed from our bookkeeping.
- private void registerTransport(String name, String component, IBackupTransport transport) {
- synchronized (mTransports) {
- if (DEBUG) Slog.v(TAG, "Registering transport "
- + component + "::" + name + " = " + transport);
- if (transport != null) {
- mTransports.put(name, transport);
- mTransportNames.put(component, name);
- } else {
- mTransports.remove(mTransportNames.get(component));
- mTransportNames.remove(component);
- // Nothing further to do in the unregistration case
- return;
- }
- }
-
- // If the init sentinel file exists, we need to be sure to perform the init
- // as soon as practical. We also create the state directory at registration
- // time to ensure it's present from the outset.
- try {
- String transportName = transport.transportDirName();
- File stateDir = new File(mBaseStateDir, transportName);
- stateDir.mkdirs();
+ private TransportManager.TransportBoundListener mTransportBoundListener =
+ new TransportManager.TransportBoundListener() {
+ @Override
+ public boolean onTransportBound(IBackupTransport transport) {
+ // If the init sentinel file exists, we need to be sure to perform the init
+ // as soon as practical. We also create the state directory at registration
+ // time to ensure it's present from the outset.
+ String name = null;
+ try {
+ name = transport.name();
+ String transportDirName = transport.transportDirName();
+ File stateDir = new File(mBaseStateDir, transportDirName);
+ stateDir.mkdirs();
- File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
- if (initSentinel.exists()) {
- synchronized (mQueueLock) {
- mPendingInits.add(name);
+ File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
+ if (initSentinel.exists()) {
+ synchronized (mQueueLock) {
+ mPendingInits.add(name);
- // TODO: pick a better starting time than now + 1 minute
- long delay = 1000 * 60; // one minute, in milliseconds
- mAlarmManager.set(AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + delay, mRunInitIntent);
+ // TODO: pick a better starting time than now + 1 minute
+ long delay = 1000 * 60; // one minute, in milliseconds
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP,
+ System.currentTimeMillis() + delay, mRunInitIntent);
+ }
}
+ return true;
+ } catch (Exception e) {
+ // the transport threw when asked its file naming prefs; declare it invalid
+ Slog.w(TAG, "Failed to regiser transport: " + name);
+ return false;
}
- } catch (Exception e) {
- // the transport threw when asked its file naming prefs; declare it invalid
- Slog.e(TAG, "Unable to register transport as " + name);
- mTransportNames.remove(component);
- mTransports.remove(name);
}
- }
+ };
// ----- Track installation/removal of packages -----
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -1899,75 +1865,17 @@ public class BackupManagerService {
// At package-changed we only care about looking at new transport states
if (changed) {
- try {
- String[] components =
- intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ String[] components =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- if (MORE_DEBUG) {
- Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
- for (int i = 0; i < components.length; i++) {
- Slog.i(TAG, " * " + components[i]);
- }
- }
-
- // In general we need to try to bind any time we see a component enable
- // state change, because that change may have made a transport available.
- // However, because we currently only support a single transport component
- // per package, we can skip the bind attempt if the change (a) affects a
- // package known to host a transport, but (b) does not affect the known
- // transport component itself.
- //
- // In addition, if the change *is* to a known transport component, we need
- // to unbind it before retrying the binding.
- boolean tryBind = true;
- synchronized (mTransports) {
- TransportConnection conn = mTransportConnections.get(pkgName);
- if (conn != null) {
- // We have a bound transport in this package; do we need to rebind it?
- final ServiceInfo svc = conn.mTransport;
- ComponentName svcName =
- new ComponentName(svc.packageName, svc.name);
- if (svc.packageName.equals(pkgName)) {
- final String className = svcName.getClassName();
- if (MORE_DEBUG) {
- Slog.i(TAG, "Checking need to rebind " + className);
- }
- // See whether it's the transport component within this package
- boolean isTransport = false;
- for (int i = 0; i < components.length; i++) {
- if (className.equals(components[i])) {
- // Okay, it's an existing transport component.
- final String flatName = svcName.flattenToShortString();
- mContext.unbindService(conn);
- mTransportConnections.remove(pkgName);
- mTransports.remove(mTransportNames.get(flatName));
- mTransportNames.remove(flatName);
- isTransport = true;
- break;
- }
- }
- if (!isTransport) {
- // A non-transport component within a package that is hosting
- // a bound transport
- tryBind = false;
- }
- }
- }
- }
- // and now (re)bind as appropriate
- if (tryBind) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Yes, need to recheck binding");
- }
- PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
- checkForTransportAndBind(app);
- }
- } catch (NameNotFoundException e) {
- // Nope, can't find it - just ignore
- if (MORE_DEBUG) {
- Slog.w(TAG, "Can't find changed package " + pkgName);
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+ for (int i = 0; i < components.length; i++) {
+ Slog.i(TAG, " * " + components[i]);
}
}
+
+ mTransportManager.onPackageChanged(pkgName, components);
return; // nothing more to do in the PACKAGE_CHANGED case
}
@@ -2015,19 +1923,7 @@ public class BackupManagerService {
writeFullBackupScheduleAsync();
}
- // Transport maintenance: rebind to known existing transports that have
- // just been updated; and bind to any newly-installed transport services.
- synchronized (mTransports) {
- final TransportConnection conn = mTransportConnections.get(packageName);
- if (conn != null) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Transport package changed; rebinding");
- }
- bindTransport(conn.mTransport);
- } else {
- checkForTransportAndBind(app);
- }
- }
+ mTransportManager.onPackageAdded(packageName);
} catch (NameNotFoundException e) {
// doesn't really exist; ignore it
@@ -2051,107 +1947,13 @@ public class BackupManagerService {
removePackageParticipantsLocked(pkgList, uid);
}
}
+ for (String pkgName : pkgList) {
+ mTransportManager.onPackageRemoved(pkgName);
+ }
}
}
};
- // ----- Track connection to transports service -----
- class TransportConnection implements ServiceConnection {
- ServiceInfo mTransport;
-
- public TransportConnection(ServiceInfo transport) {
- mTransport = transport;
- }
-
- @Override
- public void onServiceConnected(ComponentName component, IBinder service) {
- if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
- final String name = component.flattenToShortString();
- try {
- IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
- registerTransport(transport.name(), name, transport);
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 1);
- } catch (Exception e) {
- Slog.e(TAG, "Unable to register transport " + component
- + ": " + e.getMessage());
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName component) {
- if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
- final String name = component.flattenToShortString();
- EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
- registerTransport(null, name, null);
- }
- };
-
- // Check whether the given package hosts a transport, and bind if so
- void checkForTransportAndBind(PackageInfo pkgInfo) {
- Intent intent = new Intent(mTransportServiceIntent)
- .setPackage(pkgInfo.packageName);
- // TODO: http://b/22388012
- List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
- intent, 0, UserHandle.USER_SYSTEM);
- if (hosts != null) {
- final int N = hosts.size();
- for (int i = 0; i < N; i++) {
- final ServiceInfo info = hosts.get(i).serviceInfo;
- tryBindTransport(info);
- }
- }
- }
-
- // Verify that the service exists and is hosted by a privileged app, then proceed to bind
- boolean tryBindTransport(ServiceInfo info) {
- try {
- PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
- if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- != 0) {
- return bindTransport(info);
- } else {
- Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Problem resolving transport package " + info.packageName);
- }
- return false;
- }
-
- // Actually bind; presumes that we have already validated the transport service
- boolean bindTransport(ServiceInfo transport) {
- ComponentName svcName = new ComponentName(transport.packageName, transport.name);
- if (!mTransportWhitelist.contains(svcName)) {
- Slog.w(TAG, "Proposed transport " + svcName + " not whitelisted; ignoring");
- return false;
- }
-
- if (MORE_DEBUG) {
- Slog.i(TAG, "Binding to transport host " + svcName);
- }
- Intent intent = new Intent(mTransportServiceIntent);
- intent.setComponent(svcName);
-
- TransportConnection connection;
- synchronized (mTransports) {
- connection = mTransportConnections.get(transport.packageName);
- if (null == connection) {
- connection = new TransportConnection(transport);
- mTransportConnections.put(transport.packageName, connection);
- } else {
- // This is a rebind due to package upgrade. The service won't be
- // automatically relaunched for us until we explicitly rebind, but
- // we need to unbind the now-orphaned original connection.
- mContext.unbindService(connection);
- }
- }
- // TODO: http://b/22388012
- return mContext.bindServiceAsUser(intent,
- connection, Context.BIND_AUTO_CREATE,
- UserHandle.SYSTEM);
- }
-
// Add the backup agents in the given packages to our set of known backup participants.
// If 'packageNames' is null, adds all backup agents in the whole system.
void addPackageParticipantsLocked(String[] packageNames) {
@@ -2352,34 +2154,12 @@ public class BackupManagerService {
}
}
- // Return the given transport
- private IBackupTransport getTransport(String transportName) {
- synchronized (mTransports) {
- IBackupTransport transport = mTransports.get(transportName);
- if (transport == null) {
- Slog.w(TAG, "Requested unavailable transport: " + transportName);
- }
- return transport;
- }
- }
-
// What name is this transport registered under...?
private String getTransportName(IBackupTransport transport) {
if (MORE_DEBUG) {
Slog.v(TAG, "Searching for transport name of " + transport);
}
- synchronized (mTransports) {
- final int N = mTransports.size();
- for (int i = 0; i < N; i++) {
- if (mTransports.valueAt(i).equals(transport)) {
- if (MORE_DEBUG) {
- Slog.v(TAG, " Name found: " + mTransports.keyAt(i));
- }
- return mTransports.keyAt(i);
- }
- }
- }
- return null;
+ return mTransportManager.getTransportName(transport);
}
// fire off a backup agent, blocking until it attaches or times out
@@ -2505,7 +2285,7 @@ public class BackupManagerService {
throw new IllegalArgumentException("No packages are provided for backup");
}
- IBackupTransport transport = getTransport(mCurrentTransport);
+ IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport == null) {
sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
return BackupManager.ERROR_TRANSPORT_ABORTED;
@@ -3025,7 +2805,7 @@ public class BackupManagerService {
if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning");
addBackupTrace("init required; rerunning");
try {
- final String name = getTransportName(mTransport);
+ final String name = mTransportManager.getTransportName(mTransport);
if (name != null) {
mPendingInits.add(name);
} else {
@@ -4503,7 +4283,7 @@ public class BackupManagerService {
return;
}
- IBackupTransport transport = getTransport(mCurrentTransport);
+ IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport == null) {
Slog.w(TAG, "Transport not present; full data backup not performed");
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
@@ -5119,7 +4899,7 @@ public class BackupManagerService {
headBusy = false;
- if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
+ if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
if (MORE_DEBUG) {
Slog.i(TAG, "Preconditions not met; not running full backup");
}
@@ -9115,7 +8895,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
public void run() {
try {
for (String transportName : mQueue) {
- IBackupTransport transport = getTransport(transportName);
+ IBackupTransport transport =
+ mTransportManager.getTransportBinder(transportName);
if (transport == null) {
Slog.e(TAG, "Requested init for " + transportName + " but not found");
continue;
@@ -9312,7 +9093,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process");
mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
synchronized (mQueueLock) {
- final IBackupTransport transport = getTransport(transportName);
+ final IBackupTransport transport =
+ mTransportManager.getTransportBinder(transportName);
if (transport == null) {
// transport is currently unavailable -- make sure to retry
Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
@@ -9450,7 +9232,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
throw new IllegalStateException("Restore supported only for the device owner");
}
- if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
+ if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?");
} else {
if (DEBUG) {
@@ -9718,10 +9500,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
if (wasEnabled && mProvisioned) {
// NOTE: we currently flush every registered transport, not just
// the currently-active one.
- HashSet<String> allTransports;
- synchronized (mTransports) {
- allTransports = new HashSet<String>(mTransports.keySet());
- }
+ String[] allTransports = mTransportManager.getBoundTransportNames();
// build the set of transports for which we are posting an init
for (String transport : allTransports) {
recordInitPendingLocked(true, transport);
@@ -9774,36 +9553,27 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
public String getCurrentTransport() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getCurrentTransport");
- if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
- return mCurrentTransport;
+ String currentTransport = mTransportManager.getCurrentTransportName();
+ if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + currentTransport);
+ return currentTransport;
}
// Report all known, available backup transports
public String[] listAllTransports() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
- String[] list = null;
- ArrayList<String> known = new ArrayList<String>();
- for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
- if (entry.getValue() != null) {
- known.add(entry.getKey());
- }
- }
+ return mTransportManager.getBoundTransportNames();
+ }
- if (known.size() > 0) {
- list = new String[known.size()];
- known.toArray(list);
- }
- return list;
+ public ComponentName[] listAllTransportComponents() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "listAllTransportComponents");
+ return mTransportManager.getAllTransportCompenents();
}
public String[] getTransportWhitelist() {
// No permission check, intentionally.
- String[] whitelist = new String[mTransportWhitelist.size()];
- for (int i = mTransportWhitelist.size() - 1; i >= 0; i--) {
- whitelist[i] = mTransportWhitelist.valueAt(i).flattenToShortString();
- }
- return whitelist;
+ return mTransportManager.getTransportWhitelist().toArray(new String[0]);
}
// Select which transport to use for the next backup operation.
@@ -9811,20 +9581,56 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"selectBackupTransport");
- synchronized (mTransports) {
- final long oldId = Binder.clearCallingIdentity();
- try {
- String prevTransport = mCurrentTransport;
- mCurrentTransport = transport;
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ String prevTransport = mTransportManager.selectTransport(transport);
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT, transport);
+ Slog.v(TAG, "selectBackupTransport() set " + mTransportManager.getCurrentTransportName()
+ + " returning " + prevTransport);
+ return prevTransport;
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+
+ public void selectBackupTransportAsync(final ComponentName transport,
+ final ISelectBackupTransportCallback listener) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "selectBackupTransportAsync");
+
+ final long oldId = Binder.clearCallingIdentity();
+
+ Slog.v(TAG, "selectBackupTransportAsync() called with transport " +
+ transport.flattenToShortString());
+
+ mTransportManager.ensureTransportReady(transport, new SelectBackupTransportCallback() {
+ @Override
+ public void onSuccess(String transportName) {
+ mTransportManager.selectTransport(transportName);
Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, transport);
- Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
- + " returning " + prevTransport);
- return prevTransport;
- } finally {
- Binder.restoreCallingIdentity(oldId);
+ Settings.Secure.BACKUP_TRANSPORT,
+ mTransportManager.getCurrentTransportName());
+ Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString());
+ try {
+ listener.onSuccess(transportName);
+ } catch (RemoteException e) {
+ // Nothing to do here.
+ }
}
- }
+
+ @Override
+ public void onFailure(int reason) {
+ Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString());
+ try {
+ listener.onFailure(reason);
+ } catch (RemoteException e) {
+ // Nothing to do here.
+ }
+ }
+ });
+
+ Binder.restoreCallingIdentity(oldId);
}
// Supply the configuration Intent for the given transport. If the name is not one
@@ -9834,18 +9640,16 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getConfigurationIntent");
- synchronized (mTransports) {
- final IBackupTransport transport = mTransports.get(transportName);
- if (transport != null) {
- try {
- final Intent intent = transport.configurationIntent();
- if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
- + intent);
- return intent;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
- }
+ final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
+ if (transport != null) {
+ try {
+ final Intent intent = transport.configurationIntent();
+ if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
+ + intent);
+ return intent;
+ } catch (Exception e) {
+ /* fall through to return null */
+ Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
}
}
@@ -9861,17 +9665,15 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDestinationString");
- synchronized (mTransports) {
- final IBackupTransport transport = mTransports.get(transportName);
- if (transport != null) {
- try {
- final String text = transport.currentDestinationString();
- if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
- return text;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get string from transport: " + e.getMessage());
- }
+ final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
+ if (transport != null) {
+ try {
+ final String text = transport.currentDestinationString();
+ if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
+ return text;
+ } catch (Exception e) {
+ /* fall through to return null */
+ Slog.e(TAG, "Unable to get string from transport: " + e.getMessage());
}
}
@@ -9883,18 +9685,16 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementIntent");
- synchronized (mTransports) {
- final IBackupTransport transport = mTransports.get(transportName);
- if (transport != null) {
- try {
- final Intent intent = transport.dataManagementIntent();
- if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
- + intent);
- return intent;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
- }
+ final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
+ if (transport != null) {
+ try {
+ final Intent intent = transport.dataManagementIntent();
+ if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
+ + intent);
+ return intent;
+ } catch (Exception e) {
+ /* fall through to return null */
+ Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
}
}
@@ -9907,17 +9707,15 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementLabel");
- synchronized (mTransports) {
- final IBackupTransport transport = mTransports.get(transportName);
- if (transport != null) {
- try {
- final String text = transport.dataManagementLabel();
- if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
- return text;
- } catch (Exception e) {
- /* fall through to return null */
- Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
- }
+ final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
+ if (transport != null) {
+ try {
+ final String text = transport.dataManagementLabel();
+ if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
+ return text;
+ } catch (Exception e) {
+ /* fall through to return null */
+ Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
}
}
@@ -9979,7 +9777,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
// Do we have a transport to fetch data for us?
- IBackupTransport transport = getTransport(mCurrentTransport);
+ IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport == null) {
if (DEBUG) Slog.w(TAG, "No transport");
skip = true;
@@ -10033,7 +9831,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
boolean needPermission = true;
if (transport == null) {
- transport = mCurrentTransport;
+ transport = mTransportManager.getCurrentTransportName();
if (packageName != null) {
PackageInfo app = null;
@@ -10127,7 +9925,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
appIsStopped(packageInfo.applicationInfo)) {
return false;
}
- IBackupTransport transport = getTransport(mCurrentTransport);
+ IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport != null) {
try {
return transport.isAppEligibleForBackup(packageInfo,
@@ -10156,7 +9954,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
ActiveRestoreSession(String packageName, String transport) {
mPackageName = packageName;
- mRestoreTransport = getTransport(transport);
+ mRestoreTransport = mTransportManager.getTransportBinder(transport);
}
public void markTimedOut() {
@@ -10515,7 +10313,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled());
pw.println("Transport whitelist:");
- for (ComponentName transport : mTransportWhitelist) {
+ for (ComponentName transport : mTransportManager.getTransportWhitelist()) {
pw.print(" ");
pw.println(transport.flattenToShortString());
}
@@ -10524,9 +10322,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
final String[] transports = listAllTransports();
if (transports != null) {
for (String t : listAllTransports()) {
- pw.println((t.equals(mCurrentTransport) ? " * " : " ") + t);
+ pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * " : " ") + t);
try {
- IBackupTransport transport = getTransport(t);
+ IBackupTransport transport = mTransportManager.getTransportBinder(t);
File dir = new File(mBaseStateDir, transport.transportDirName());
pw.println(" destination: " + transport.currentDestinationString());
pw.println(" intent: " + transport.configurationIntent());
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index d677f5ee04a8..a1a2c95e1eac 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -20,6 +20,8 @@ import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -275,6 +277,12 @@ public class Trampoline extends IBackupManager.Stub {
}
@Override
+ public ComponentName[] listAllTransportComponents() throws RemoteException {
+ BackupManagerService svc = mService;
+ return (svc != null) ? svc.listAllTransportComponents() : null;
+ }
+
+ @Override
public String[] getTransportWhitelist() {
BackupManagerService svc = mService;
return (svc != null) ? svc.getTransportWhitelist() : null;
@@ -287,6 +295,15 @@ public class Trampoline extends IBackupManager.Stub {
}
@Override
+ public void selectBackupTransportAsync(ComponentName transport,
+ ISelectBackupTransportCallback listener) throws RemoteException {
+ BackupManagerService svc = mService;
+ if (svc != null) {
+ svc.selectBackupTransportAsync(transport, listener);
+ }
+ }
+
+ @Override
public Intent getConfigurationIntent(String transport) throws RemoteException {
BackupManagerService svc = mService;
return (svc != null) ? svc.getConfigurationIntent(transport) : null;
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
new file mode 100644
index 000000000000..93d5a1ea8880
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup;
+
+import android.app.backup.BackupManager;
+import android.app.backup.SelectBackupTransportCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.backup.IBackupTransport;
+import com.android.server.EventLogTags;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Handles in-memory bookkeeping of all BackupTransport objects.
+ */
+class TransportManager {
+
+ private static final String TAG = "BackupTransportManager";
+
+ private static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
+
+ private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+ private final Set<ComponentName> mTransportWhitelist;
+
+ /**
+ * This listener is called after we bind to any transport. If it returns true, this is a valid
+ * transport.
+ */
+ private final TransportBoundListener mTransportBoundListener;
+
+ private String mCurrentTransportName;
+
+ /** Lock on this before accessing mValidTransports and mBoundTransports. */
+ private final Object mTransportLock = new Object();
+
+ /**
+ * We have detected these transports on the device. Unless in exceptional cases, we are also
+ * bound to all of these.
+ */
+ @GuardedBy("mTransportLock")
+ private final Map<ComponentName, TransportConnection> mValidTransports = new ArrayMap<>();
+
+ /** We are currently bound to these transports. */
+ @GuardedBy("mTransportLock")
+ private final Map<String, ComponentName> mBoundTransports = new ArrayMap<>();
+
+ TransportManager(Context context, Set<ComponentName> whitelist, String defaultTransport,
+ TransportBoundListener listener) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mTransportWhitelist = whitelist;
+ mCurrentTransportName = defaultTransport;
+ mTransportBoundListener = listener;
+ }
+
+ void onPackageAdded(String packageName) {
+ // New package added. Bind to all transports it contains.
+ synchronized (mTransportLock) {
+ log_verbose("Package added. Binding to all transports. " + packageName);
+ bindToAllInternal(packageName, null /* all components */);
+ }
+ }
+
+ void onPackageRemoved(String packageName) {
+ // Package removed. Remove all its transports from our list. These transports have already
+ // been removed from mBoundTransports because onServiceDisconnected would already been
+ // called on TransportConnection objects.
+ synchronized (mTransportLock) {
+ for (ComponentName transport : mValidTransports.keySet()) {
+ if (transport.getPackageName().equals(packageName)) {
+ TransportConnection removed = mValidTransports.remove(transport);
+ if (removed != null) {
+ mContext.unbindService(removed);
+ log_verbose("Package removed, Removing transport: " +
+ transport.flattenToShortString());
+ }
+ }
+ }
+ }
+ }
+
+ void onPackageChanged(String packageName, String[] components) {
+ synchronized (mTransportLock) {
+ // Remove all changed components from mValidTransports. We'll bind to them again
+ // and re-add them if still valid.
+ for (String component : components) {
+ ComponentName componentName = new ComponentName(packageName, component);
+ TransportConnection removed = mValidTransports.remove(componentName);
+ if (removed != null) {
+ mContext.unbindService(removed);
+ log_verbose("Package changed. Removing transport: " +
+ componentName.flattenToShortString());
+ }
+ }
+ bindToAllInternal(packageName, components);
+ }
+ }
+
+ IBackupTransport getTransportBinder(String transportName) {
+ synchronized (mTransportLock) {
+ ComponentName component = mBoundTransports.get(transportName);
+ if (component == null) {
+ Slog.w(TAG, "Transport " + transportName + " not bound.");
+ return null;
+ }
+ TransportConnection conn = mValidTransports.get(component);
+ if (conn == null) {
+ Slog.w(TAG, "Transport " + transportName + " not valid.");
+ return null;
+ }
+ return conn.getBinder();
+ }
+ }
+
+ IBackupTransport getCurrentTransportBinder() {
+ return getTransportBinder(mCurrentTransportName);
+ }
+
+ String getTransportName(IBackupTransport binder) {
+ synchronized (mTransportLock) {
+ for (TransportConnection conn : mValidTransports.values()) {
+ if (conn.getBinder() == binder) {
+ return conn.getName();
+ }
+ }
+ }
+ return null;
+ }
+
+ String[] getBoundTransportNames() {
+ synchronized (mTransportLock) {
+ return mBoundTransports.keySet().toArray(new String[0]);
+ }
+ }
+
+ ComponentName[] getAllTransportCompenents() {
+ synchronized (mTransportLock) {
+ return mValidTransports.keySet().toArray(new ComponentName[0]);
+ }
+ }
+
+ String getCurrentTransportName() {
+ return mCurrentTransportName;
+ }
+
+ Set<ComponentName> getTransportWhitelist() {
+ return mTransportWhitelist;
+ }
+
+ String selectTransport(String transport) {
+ synchronized (mTransportLock) {
+ String prevTransport = mCurrentTransportName;
+ mCurrentTransportName = transport;
+ return prevTransport;
+ }
+ }
+
+ void ensureTransportReady(ComponentName transportComponent, SelectBackupTransportCallback listener) {
+ synchronized (mTransportLock) {
+ TransportConnection conn = mValidTransports.get(transportComponent);
+ if (conn == null) {
+ listener.onFailure(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
+ return;
+ }
+ // Transport can be unbound if the process hosting it crashed.
+ conn.bindIfUnbound();
+ conn.addListener(listener);
+ }
+ }
+
+ void registerAllTransports() {
+ bindToAllInternal(null /* all packages */, null /* all components */);
+ }
+
+ /**
+ * Bind to all transports belonging to the given package and the given component list.
+ * null acts a wildcard.
+ *
+ * If packageName is null, bind to all transports in all packages.
+ * If components is null, bind to all transports in the given package.
+ */
+ private void bindToAllInternal(String packageName, String[] components) {
+ PackageInfo pkgInfo = null;
+ if (packageName != null) {
+ try {
+ pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Package not found: " + packageName);
+ return;
+ }
+ }
+
+ Intent intent = new Intent(mTransportServiceIntent);
+ if (packageName != null) {
+ intent.setPackage(packageName);
+ }
+
+ List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
+ intent, 0, UserHandle.USER_SYSTEM);
+ if (hosts != null) {
+ for (ResolveInfo host : hosts) {
+ final ServiceInfo info = host.serviceInfo;
+ boolean shouldBind = false;
+ if (components != null && packageName != null) {
+ for (String component : components) {
+ ComponentName cn = new ComponentName(pkgInfo.packageName, component);
+ if (info.getComponentName().equals(cn)) {
+ shouldBind = true;
+ break;
+ }
+ }
+ } else {
+ shouldBind = true;
+ }
+ if (shouldBind && isTransportTrusted(info.getComponentName())) {
+ tryBindTransport(info);
+ }
+ }
+ }
+ }
+
+ /** Transport has to be whitelisted and privileged. */
+ private boolean isTransportTrusted(ComponentName transport) {
+ if (!mTransportWhitelist.contains(transport)) {
+ Slog.w(TAG, "BackupTransport " + transport.flattenToShortString() +
+ " not whitelisted.");
+ return false;
+ }
+ try {
+ PackageInfo packInfo = mPackageManager.getPackageInfo(transport.getPackageName(), 0);
+ if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ == 0) {
+ Slog.w(TAG, "Transport package " + transport.getPackageName() + " not privileged");
+ return false;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Package not found.", e);
+ return false;
+ }
+ return true;
+ }
+
+ private void tryBindTransport(ServiceInfo transport) {
+ Slog.d(TAG, "Binding to transport: " + transport.getComponentName().flattenToShortString());
+ // TODO: b/22388012 (Multi user backup and restore)
+ TransportConnection connection = new TransportConnection(transport.getComponentName());
+ if (bindToTransport(transport.getComponentName(), connection)) {
+ synchronized (mTransportLock) {
+ mValidTransports.put(transport.getComponentName(), connection);
+ }
+ } else {
+ Slog.w(TAG, "Couldn't bind to transport " + transport.getComponentName());
+ }
+ }
+
+ private boolean bindToTransport(ComponentName componentName, ServiceConnection connection) {
+ Intent intent = new Intent(mTransportServiceIntent)
+ .setComponent(componentName);
+ return mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
+ UserHandle.SYSTEM);
+ }
+
+ private class TransportConnection implements ServiceConnection {
+
+ // Hold mTransportsLock to access these fields so as to provide a consistent view of them.
+ private IBackupTransport mBinder;
+ private final List<SelectBackupTransportCallback> mListeners = new ArrayList<>();
+ private String mTransportName;
+
+ private final ComponentName mTransportComponent;
+
+ private TransportConnection(ComponentName transportComponent) {
+ mTransportComponent = transportComponent;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName component, IBinder binder) {
+ synchronized (mTransportLock) {
+ mBinder = IBackupTransport.Stub.asInterface(binder);
+ boolean success = false;
+
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
+ component.flattenToShortString(), 1);
+
+ try {
+ mTransportName = mBinder.name();
+ // BackupManager requests some fields from the transport. If they are
+ // invalid, throw away this transport.
+ success = mTransportBoundListener.onTransportBound(mBinder);
+ } catch (RemoteException e) {
+ success = false;
+ Slog.e(TAG, "Couldn't get transport name.", e);
+ } finally {
+ if (success) {
+ Slog.d(TAG, "Bound to transport: " + component.flattenToShortString());
+ mBoundTransports.put(mTransportName, component);
+ for (SelectBackupTransportCallback listener : mListeners) {
+ listener.onSuccess(mTransportName);
+ }
+ } else {
+ Slog.w(TAG, "Bound to transport " + component.flattenToShortString() +
+ " but it is invalid");
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
+ component.flattenToShortString(), 0);
+ mContext.unbindService(this);
+ mValidTransports.remove(component);
+ mBinder = null;
+ for (SelectBackupTransportCallback listener : mListeners) {
+ listener.onFailure(BackupManager.ERROR_TRANSPORT_INVALID);
+ }
+ }
+ mListeners.clear();
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName component) {
+ synchronized (mTransportLock) {
+ mBinder = null;
+ mBoundTransports.remove(mTransportName);
+ }
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
+ component.flattenToShortString(), 0);
+ Slog.w(TAG, "Disconnected from transport " + component.flattenToShortString());
+ }
+
+ private IBackupTransport getBinder() {
+ synchronized (mTransportLock) {
+ return mBinder;
+ }
+ }
+
+ private String getName() {
+ synchronized (mTransportLock) {
+ return mTransportName;
+ }
+ }
+
+ private void bindIfUnbound() {
+ synchronized (mTransportLock) {
+ if (mBinder == null) {
+ Slog.d(TAG,
+ "Rebinding to transport " + mTransportComponent.flattenToShortString());
+ bindToTransport(mTransportComponent, this);
+ }
+ }
+ }
+
+ private void addListener(SelectBackupTransportCallback listener) {
+ synchronized (mTransportLock) {
+ if (mBinder == null) {
+ // We are waiting for bind to complete. If mBinder is set to null after the bind
+ // is complete due to transport being invalid, we won't find 'this' connection
+ // object in mValidTransports list and this function can't be called.
+ mListeners.add(listener);
+ } else {
+ listener.onSuccess(mTransportName);
+ }
+ }
+ }
+ }
+
+ interface TransportBoundListener {
+ /** Should return true if this is a valid transport. */
+ boolean onTransportBound(IBackupTransport binder);
+ }
+
+ private static void log_verbose(String message) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Slog.v(TAG, message);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0e07ec0e27f4..b1560e6d5f78 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -275,7 +275,7 @@ class AlarmManagerService extends SystemService {
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
- Slog.e(TAG, "Bad device idle settings", e);
+ Slog.e(TAG, "Bad alarm manager settings", e);
}
MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 1f6294533e95..dc0e3e1bbf03 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -41,6 +41,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.media.AudioAttributes;
import android.os.AsyncTask;
import android.os.Binder;
@@ -294,6 +295,25 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ packageManagerInternal.setExternalSourcesPolicy(
+ new PackageManagerInternal.ExternalSourcesPolicy() {
+ @Override
+ public int getPackageTrustedToInstallApps(String packageName, int uid) {
+ int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+ uid, packageName);
+ switch (appOpMode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
+ case AppOpsManager.MODE_ERRORED:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
+ default:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
+ }
+ }
+ });
+
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
storageManagerInternal.addExternalStoragePolicy(
diff --git a/services/core/java/com/android/server/BackgroundDexOptJobService.java b/services/core/java/com/android/server/BackgroundDexOptJobService.java
new file mode 100644
index 000000000000..69e6ac50fa8a
--- /dev/null
+++ b/services/core/java/com/android/server/BackgroundDexOptJobService.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Environment;
+import android.os.ServiceManager;
+import android.os.storage.StorageManager;
+import android.util.ArraySet;
+import android.util.Log;
+import com.android.server.pm.PackageManagerService;
+
+import java.io.File;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.TimeUnit;
+
+public class BackgroundDexOptJobService extends JobService {
+ private static final String TAG = "BackgroundDexOptJobService";
+
+ private static final boolean DEBUG = false;
+
+ private static final int JOB_IDLE_OPTIMIZE = 800;
+ private static final int JOB_POST_BOOT_UPDATE = 801;
+
+ private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
+ ? TimeUnit.MINUTES.toMillis(1)
+ : TimeUnit.DAYS.toMillis(1);
+
+ private static ComponentName sDexoptServiceName = new ComponentName(
+ "android",
+ BackgroundDexOptJobService.class.getName());
+
+ /**
+ * Set of failed packages remembered across job runs.
+ */
+ static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
+
+ /**
+ * Atomics set to true if the JobScheduler requests an abort.
+ */
+ final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
+ final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
+
+ /**
+ * Atomic set to true if one job should exit early because another job was started.
+ */
+ final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
+
+ private final File mDataDir = Environment.getDataDirectory();
+
+ public static void schedule(Context context) {
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ // Schedule a one-off job which scans installed packages and updates
+ // out-of-date oat files.
+ js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
+ .setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
+ .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
+ .build());
+
+ // Schedule a daily job which scans installed packages and compiles
+ // those with fresh profiling data.
+ js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .setPeriodic(IDLE_OPTIMIZATION_PERIOD)
+ .build());
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Jobs scheduled");
+ }
+ }
+
+ public static void notifyPackageChanged(String packageName) {
+ // The idle maintanance job skips packages which previously failed to
+ // compile. The given package has changed and may successfully compile
+ // now. Remove it from the list of known failing packages.
+ synchronized (sFailedPackageNames) {
+ sFailedPackageNames.remove(packageName);
+ }
+ }
+
+ // Returns the current battery level as a 0-100 integer.
+ private int getBatteryLevel() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent intent = registerReceiver(null, filter);
+ int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+
+ if (level < 0 || scale <= 0) {
+ // Battery data unavailable. This should never happen, so assume the worst.
+ return 0;
+ }
+
+ return (100 * level / scale);
+ }
+
+ private long getLowStorageThreshold() {
+ @SuppressWarnings("deprecation")
+ final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
+ if (lowThreshold == 0) {
+ Log.e(TAG, "Invalid low storage threshold");
+ }
+
+ return lowThreshold;
+ }
+
+ private boolean runPostBootUpdate(final JobParameters jobParams,
+ final PackageManagerService pm, final ArraySet<String> pkgs) {
+ if (mExitPostBootUpdate.get()) {
+ // This job has already been superseded. Do not start it.
+ return false;
+ }
+ new Thread("BackgroundDexOptService_PostBootUpdate") {
+ @Override
+ public void run() {
+ postBootUpdate(jobParams, pm, pkgs);
+ }
+
+ }.start();
+ return true;
+ }
+
+ private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
+ ArraySet<String> pkgs) {
+ // Load low battery threshold from the system config. This is a 0-100 integer.
+ final int lowBatteryThreshold = getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ final long lowThreshold = getLowStorageThreshold();
+
+ mAbortPostBootUpdate.set(false);
+
+ for (String pkg : pkgs) {
+ if (mAbortPostBootUpdate.get()) {
+ // JobScheduler requested an early abort.
+ return;
+ }
+ if (mExitPostBootUpdate.get()) {
+ // Different job, which supersedes this one, is running.
+ break;
+ }
+ if (getBatteryLevel() < lowBatteryThreshold) {
+ // Rather bail than completely drain the battery.
+ break;
+ }
+ long usableSpace = mDataDir.getUsableSpace();
+ if (usableSpace < lowThreshold) {
+ // Rather bail than completely fill up the disk.
+ Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+ usableSpace);
+ break;
+ }
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Updating package " + pkg);
+ }
+
+ // Update package if needed. Note that there can be no race between concurrent
+ // jobs because PackageDexOptimizer.performDexOpt is synchronized.
+
+ // checkProfiles is false to avoid merging profiles during boot which
+ // might interfere with background compilation (b/28612421).
+ // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
+ // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
+ // trade-off worth doing to save boot time work.
+ pm.performDexOpt(pkg,
+ /* checkProfiles */ false,
+ PackageManagerService.REASON_BOOT,
+ /* force */ false);
+ }
+ // Ran to completion, so we abandon our timeslice and do not reschedule.
+ jobFinished(jobParams, /* reschedule */ false);
+ }
+
+ private boolean runIdleOptimization(final JobParameters jobParams,
+ final PackageManagerService pm, final ArraySet<String> pkgs) {
+ new Thread("BackgroundDexOptService_IdleOptimization") {
+ @Override
+ public void run() {
+ idleOptimization(jobParams, pm, pkgs);
+ }
+ }.start();
+ return true;
+ }
+
+ private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
+ ArraySet<String> pkgs) {
+ Log.i(TAG, "Performing idle optimizations");
+ // If post-boot update is still running, request that it exits early.
+ mExitPostBootUpdate.set(true);
+
+ mAbortIdleOptimization.set(false);
+
+ final long lowThreshold = getLowStorageThreshold();
+ for (String pkg : pkgs) {
+ if (mAbortIdleOptimization.get()) {
+ // JobScheduler requested an early abort.
+ return;
+ }
+
+ synchronized (sFailedPackageNames) {
+ if (sFailedPackageNames.contains(pkg)) {
+ // Skip previously failing package
+ continue;
+ }
+ }
+
+ long usableSpace = mDataDir.getUsableSpace();
+ if (usableSpace < lowThreshold) {
+ // Rather bail than completely fill up the disk.
+ Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+ usableSpace);
+ break;
+ }
+
+ // Conservatively add package to the list of failing ones in case performDexOpt
+ // never returns.
+ synchronized (sFailedPackageNames) {
+ sFailedPackageNames.add(pkg);
+ }
+ // Optimize package if needed. Note that there can be no race between
+ // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
+ if (pm.performDexOpt(pkg,
+ /* checkProfiles */ true,
+ PackageManagerService.REASON_BACKGROUND_DEXOPT,
+ /* force */ false)) {
+ // Dexopt succeeded, remove package from the list of failing ones.
+ synchronized (sFailedPackageNames) {
+ sFailedPackageNames.remove(pkg);
+ }
+ }
+ }
+ // Ran to completion, so we abandon our timeslice and do not reschedule.
+ jobFinished(jobParams, /* reschedule */ false);
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "onStartJob");
+ }
+
+ // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
+ // the checks above. This check is not "live" - the value is determined by a background
+ // restart with a period of ~1 minute.
+ PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
+ if (pm.isStorageLow()) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Low storage, skipping this run");
+ }
+ return false;
+ }
+
+ final ArraySet<String> pkgs = pm.getOptimizablePackages();
+ if (pkgs == null || pkgs.isEmpty()) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "No packages to optimize");
+ }
+ return false;
+ }
+
+ if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
+ return runPostBootUpdate(params, pm, pkgs);
+ } else {
+ return runIdleOptimization(params, pm, pkgs);
+ }
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "onStopJob");
+ }
+
+ if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
+ mAbortPostBootUpdate.set(true);
+ } else {
+ mAbortIdleOptimization.set(true);
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index dd550f22f992..6248cab0ce10 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -49,8 +49,10 @@ import android.os.SystemClock;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.battery.BatteryServiceDumpProto;
import android.util.EventLog;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -801,6 +803,35 @@ public final class BatteryService extends SystemService {
}
}
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ synchronized (mLock) {
+ proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
+ int batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_NONE;
+ if (mBatteryProps.chargerAcOnline) {
+ batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_AC;
+ } else if (mBatteryProps.chargerUsbOnline) {
+ batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_USB;
+ } else if (mBatteryProps.chargerWirelessOnline) {
+ batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_WIRELESS;
+ }
+ proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
+ proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
+ proto.write(BatteryServiceDumpProto.STATUS, mBatteryProps.batteryStatus);
+ proto.write(BatteryServiceDumpProto.HEALTH, mBatteryProps.batteryHealth);
+ proto.write(BatteryServiceDumpProto.IS_PRESENT, mBatteryProps.batteryPresent);
+ proto.write(BatteryServiceDumpProto.LEVEL, mBatteryProps.batteryLevel);
+ proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
+ proto.write(BatteryServiceDumpProto.VOLTAGE, mBatteryProps.batteryVoltage);
+ proto.write(BatteryServiceDumpProto.TEMPERATURE, mBatteryProps.batteryTemperature);
+ proto.write(BatteryServiceDumpProto.TECHNOLOGY, mBatteryProps.batteryTechnology);
+ }
+ proto.flush();
+ }
+
private final class Led {
private final Light mBatteryLight;
@@ -878,7 +909,11 @@ public final class BatteryService extends SystemService {
return;
}
- dumpInternal(fd, pw, args);
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpInternal(fd, pw, args);
+ }
}
@Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index e7f1d16fcc61..f31555327b01 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -50,6 +50,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -59,6 +60,8 @@ import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
+import com.android.server.pm.PackageManagerService;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.ConcurrentHashMap;
@@ -218,6 +221,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
@Override
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
+ if (!newRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)
+ && !prevRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)) {
+ // The relevant restriction has not changed - do nothing.
+ return;
+ }
final boolean bluetoothDisallowed =
newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
if ((mEnable || mEnableExternal) && bluetoothDisallowed) {
@@ -228,6 +236,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
e);
}
}
+ updateOppLauncherComponentState(bluetoothDisallowed);
}
};
@@ -953,7 +962,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
- if (isBluetoothDisallowed()) {
+ final boolean isBluetoothDisallowed = isBluetoothDisallowed();
+ PackageManagerService packageManagerService =
+ (PackageManagerService) ServiceManager.getService("package");
+ if (packageManagerService != null && !packageManagerService.isOnlyCoreApps()) {
+ updateOppLauncherComponentState(isBluetoothDisallowed);
+ }
+ if (isBluetoothDisallowed) {
return;
}
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
@@ -2011,6 +2026,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
+ /**
+ * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
+ * offered to the user if Bluetooth is disallowed. Puts the component to its default state if
+ * Bluetooth is not disallowed.
+ *
+ * @param bluetoothDisallowed whether the {@link UserManager.DISALLOW_BLUETOOTH} user
+ * restriction was set.
+ */
+ private void updateOppLauncherComponentState(boolean bluetoothDisallowed) {
+ final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
+ "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
+ final int newState = bluetoothDisallowed
+ ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ try {
+ mContext.getPackageManager()
+ .setComponentEnabledSetting(oppLauncherComponent, newState, 0);
+ } catch (Exception e) {
+ // The component was not found, do nothing.
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -2034,21 +2071,32 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
writer.println(" time since enabled: " + onDurationString + "\n");
}
- writer.println("Enable log:");
- for (ActiveLog log : mActiveLogs) {
- writer.println(log);
+ if (mActiveLogs.size() == 0) {
+ writer.println("Bluetooth never enabled!");
+ } else {
+ writer.println("Enable log:");
+ for (ActiveLog log : mActiveLogs) {
+ writer.println(" " + log);
+ }
}
- writer.println("\n" + mBleApps.size() + " BLE Apps registered:");
+ String bleAppString = "No BLE Apps registered.";
+ if (mBleApps.size() == 1) {
+ bleAppString = "1 BLE App registered:";
+ } else if (mBleApps.size() > 1) {
+ bleAppString = mBleApps.size() + " BLE Apps registered:";
+ }
+ writer.println("\n" + bleAppString);
for (ClientDeathRecipient app : mBleApps.values()) {
- writer.println(app.getPackageName());
+ writer.println(" " + app.getPackageName());
}
+ writer.println("");
writer.flush();
if (args.length == 0) {
- // Add arg to produce output
- args = new String[1];
- args[0] = "--print";
+ // Add arg to produce output
+ args = new String[1];
+ args[0] = "--print";
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f3f8da885d0b..719a64e32241 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -78,7 +78,7 @@ import android.net.Uri;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -499,7 +499,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final IpConnectivityLog mMetricsLog;
@VisibleForTesting
- final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
/**
* Implements support for the legacy "one network per network type" model.
@@ -690,11 +690,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
- @VisibleForTesting
- protected HandlerThread createHandlerThread() {
- return new HandlerThread("ConnectivityServiceThread");
- }
-
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
this(context, netManager, statsService, policyManager, new IpConnectivityLog());
@@ -715,7 +710,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDefaultMobileDataRequest = createInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
- mHandlerThread = createHandlerThread();
+ mHandlerThread = new HandlerThread("ConnectivityServiceThread");
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -854,9 +849,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
- mAvoidBadWifiTracker = createAvoidBadWifiTracker(
+ mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
- mAvoidBadWifiTracker.start();
+ mMultinetworkPolicyTracker.start();
}
private NetworkRequest createInternetRequestForTransport(
@@ -2789,7 +2784,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
public boolean avoidBadWifi() {
- return mAvoidBadWifiTracker.currentValue();
+ return mMultinetworkPolicyTracker.getAvoidBadWifi();
}
private void rematchForAvoidBadWifiUpdate() {
@@ -2802,9 +2797,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// TODO: Evaluate whether this is of interest to other consumers of
- // AvoidBadWifiTracker and worth moving out of here.
+ // MultinetworkPolicyTracker and worth moving out of here.
private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
- final boolean configRestrict = mAvoidBadWifiTracker.configRestrictsAvoidBadWifi();
+ final boolean configRestrict = mMultinetworkPolicyTracker.configRestrictsAvoidBadWifi();
if (!configRestrict) {
pw.println("Bad Wi-Fi avoidance: unrestricted");
return;
@@ -2814,7 +2809,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.increaseIndent();
pw.println("Config restrict: " + configRestrict);
- final String value = mAvoidBadWifiTracker.getSettingsValue();
+ final String value = mMultinetworkPolicyTracker.getAvoidBadWifiSetting();
String description;
// Can't use a switch statement because strings are legal case labels, but null is not.
if ("0".equals(value)) {
@@ -2882,11 +2877,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
- mAvoidBadWifiTracker.shouldNotifyWifiUnvalidated()) {
+ mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
}
+ @Override
+ public int getMultipathPreference(Network network) {
+ enforceAccessPermission();
+
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai != null && !nai.networkInfo.isMetered()) {
+ return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
+ }
+
+ return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
+ }
+
private class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
@@ -5550,8 +5557,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@VisibleForTesting
- AvoidBadWifiTracker createAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
- return new AvoidBadWifiTracker(c, h, r);
+ MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+ return new MultinetworkPolicyTracker(c, h, r);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index bee1f9729eea..08cb1094ae38 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -926,13 +926,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return;
}
final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
- context, mSystemReady, mSettings.getEnabledInputMethodListLocked());
+ context, mSettings.getEnabledInputMethodListLocked());
if (suitableImes.isEmpty()) {
Slog.i(TAG, "No default found");
return;
}
final InputMethodInfo defIm = suitableImes.get(0);
- Slog.i(TAG, "Default found, using " + defIm.getId());
+ if (DEBUG) {
+ Slog.i(TAG, "Default found, using " + defIm.getId());
+ }
setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
}
@@ -1123,6 +1125,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return true;
}
+ // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
+ Debug.getCallers(10));
return false;
@@ -1134,8 +1137,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
* @param token The window token given to the input method when it was started.
* @return true if and only if non-null valid token is specified.
*/
- private boolean calledWithValidToken(IBinder token) {
- if (token == null || mCurToken != token) {
+ private boolean calledWithValidToken(@Nullable IBinder token) {
+ if (token == null && Binder.getCallingPid() == Process.myPid()) {
+ if (DEBUG) {
+ // TODO(b/34851776): Basically it's the caller's fault if we reach here.
+ Slog.d(TAG, "Bug 34851776 is detected callers=" + Debug.getCallers(10));
+ }
+ return false;
+ }
+ if (token == null || token != mCurToken) {
+ // TODO(b/34886274): The semantics of this verification is actually not well-defined.
+ Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
+ + " uid:" + Binder.getCallingUid() + " token:" + token);
return false;
}
return true;
@@ -1284,7 +1297,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return flags;
}
- InputBindResult attachNewInputLocked(boolean initial) {
+ InputBindResult attachNewInputLocked(
+ /* @InputMethodClient.StartInputReason */ final int startInputReason, boolean initial) {
if (!mBoundToMethod) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
@@ -1338,20 +1352,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// because if the focus changes some time before or after, the
// next client receiving focus that has any interest in input will
// be calling through here after that change happens.
- Slog.w(TAG, "Starting input on non-focused client " + cs.client
- + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+ if (DEBUG) {
+ Slog.w(TAG, "Starting input on non-focused client " + cs.client
+ + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+ }
return null;
}
} catch (RemoteException e) {
}
return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- controlFlags);
+ controlFlags, startInputReason);
}
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
- @NonNull EditorInfo attribute, int controlFlags) {
+ @NonNull EditorInfo attribute, int controlFlags,
+ /* @InputMethodClient.StartInputReason */ final int startInputReason) {
// If no method is currently selected, do nothing.
if (mCurMethodId == null) {
return mNoBinding;
@@ -1393,7 +1410,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (cs.curSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
- return attachNewInputLocked(
+ return attachNewInputLocked(startInputReason,
(controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
}
if (mHaveConnection) {
@@ -1457,7 +1474,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurId = info.getId();
mCurToken = new Binder();
try {
- if (true || DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, DEFAULT_DISPLAY);
} catch (RemoteException e) {
}
@@ -1534,7 +1551,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
clearClientSessionLocked(mCurClient);
mCurClient.curSession = new SessionState(mCurClient,
method, session, channel);
- InputBindResult res = attachNewInputLocked(true);
+ InputBindResult res = attachNewInputLocked(
+ InputMethodClient.START_INPUT_REASON_SESSION_CREATED_BY_IME, true);
if (res.method != null) {
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
MSG_BIND_CLIENT, mCurClient.client, res));
@@ -1660,15 +1678,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void updateStatusIcon(IBinder token, String packageName, int iconId) {
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring updateStatusIcon due to an invalid token. uid:" + uid
- + " token:" + token);
- return;
- }
+ synchronized (mMethodMap) {
+ if (!calledWithValidToken(token)) {
+ return;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
if (iconId == 0) {
if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
if (mStatusBar != null) {
@@ -1693,9 +1708,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mStatusBar.setIconVisibility(mSlotIme, true);
}
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
}
@@ -1767,9 +1782,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring setImeWindowStatus due to an invalid token. uid:" + uid
- + " token:" + token);
return;
}
@@ -1789,9 +1801,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Caution! This method is called in this class. Handle multi-user carefully
private void updateSystemUiLocked(IBinder token, int vis, int backDisposition) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring updateSystemUiLocked due to an invalid token. uid:" + uid
- + " token:" + token);
return;
}
@@ -2259,8 +2268,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// because if the focus changes some time before or after, the
// next client receiving focus that has any interest in input will
// be calling through here after that change happens.
- Slog.w(TAG, "Focus gain on non-focused client " + cs.client
- + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+ if (DEBUG) {
+ Slog.w(TAG, "Focus gain on non-focused client " + cs.client
+ + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+ }
return null;
}
} catch (RemoteException e) {
@@ -2275,11 +2286,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurFocusedWindow == windowToken) {
- Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
- + " attribute=" + attribute + ", token = " + windowToken);
+ if (DEBUG) {
+ Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ + " attribute=" + attribute + ", token = " + windowToken);
+ }
if (attribute != null) {
return startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, controlFlags);
+ attribute, controlFlags, startInputReason);
}
return null;
}
@@ -2329,7 +2342,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext,
- missingMethods, attribute, controlFlags);
+ missingMethods, attribute, controlFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2355,7 +2368,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext,
- missingMethods, attribute, controlFlags);
+ missingMethods, attribute, controlFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2365,7 +2378,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, controlFlags);
+ attribute, controlFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2374,7 +2387,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!didStart && attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- controlFlags);
+ controlFlags, startInputReason);
}
}
} finally {
@@ -2519,9 +2532,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
synchronized (mMethodMap) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring switchToNextInputMethod due to an invalid token. uid:" + uid
- + " token:" + token);
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
@@ -2543,9 +2553,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
synchronized (mMethodMap) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring shouldOfferSwitchingToNextInputMethod due to an invalid "
- + "token. uid:" + uid + " token:" + token);
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
@@ -2634,20 +2641,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!calledFromValidUser()) {
return;
}
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring clearLastInputMethodWindowForTransition due to an "
- + "invalid token. uid:" + uid + " token:" + token);
- return;
- }
+ synchronized (mMethodMap) {
+ if (!calledWithValidToken(token)) {
+ return;
}
- mWindowManagerInternal.clearLastInputMethodWindowForTransition();
- } finally {
- Binder.restoreCallingIdentity(ident);
}
+ mWindowManagerInternal.clearLastInputMethodWindowForTransition();
}
@Override
@@ -2707,9 +2706,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
synchronized (mMethodMap) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring hideInputMethod due to an invalid token. uid:"
- + uid + " token:" + token);
return;
}
long ident = Binder.clearCallingIdentity();
@@ -2728,9 +2724,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
synchronized (mMethodMap) {
if (!calledWithValidToken(token)) {
- final int uid = Binder.getCallingUid();
- Slog.e(TAG, "Ignoring showMySoftInput due to an invalid token. uid:"
- + uid + " token:" + token);
return;
}
long ident = Binder.clearCallingIdentity();
@@ -3038,22 +3031,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
mSettings.getCurrentUserId());
- final HashMap<String, List<InputMethodSubtype>> additionalSubtypes =
+ final HashMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
mFileManager.getAllAdditionalInputMethodSubtypes();
for (int i = 0; i < services.size(); ++i) {
ResolveInfo ri = services.get(i);
ServiceInfo si = ri.serviceInfo;
- ComponentName compName = new ComponentName(si.packageName, si.name);
- if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(
- si.permission)) {
- Slog.w(TAG, "Skipping input method " + compName
+ final String imeId = InputMethodInfo.computeId(ri);
+ if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
+ Slog.w(TAG, "Skipping input method " + imeId
+ ": it does not require the permission "
+ android.Manifest.permission.BIND_INPUT_METHOD);
continue;
}
- if (DEBUG) Slog.d(TAG, "Checking " + compName);
+ if (DEBUG) Slog.d(TAG, "Checking " + imeId);
+ final List<InputMethodSubtype> additionalSubtypes = additionalSubtypeMap.get(imeId);
try {
InputMethodInfo p = new InputMethodInfo(mContext, ri, additionalSubtypes);
mMethodList.add(p);
@@ -3064,7 +3057,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.d(TAG, "Found an input method " + p);
}
} catch (Exception e) {
- Slog.wtf(TAG, "Unable to load input method " + compName, e);
+ Slog.wtf(TAG, "Unable to load input method " + imeId, e);
}
}
@@ -3081,7 +3074,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
if (!enabledImeFound) {
- Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
+ if (DEBUG) {
+ Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
+ }
resetDefaultEnabledIme = true;
resetSelectedInputMethodAndSubtypeLocked("");
}
@@ -3089,7 +3084,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (resetDefaultEnabledIme) {
final ArrayList<InputMethodInfo> defaultEnabledIme =
- InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, mMethodList);
+ InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList);
final int N = defaultEnabledIme.size();
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = defaultEnabledIme.get(i);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6cc72deb7faa..42eb958bba0b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManager;
+import android.annotation.NonNull;
import android.content.pm.PackageManagerInternal;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
@@ -62,6 +63,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.IBatchedLocationCallback;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
import android.location.IGnssStatusProvider;
@@ -101,6 +103,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
/**
@@ -132,6 +135,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final String FUSED_LOCATION_SERVICE_ACTION =
"com.android.location.service.FusedLocationProvider";
+ private static final String GMSCORE_PACKAGE = "com.android.google.gms";
+
private static final int MSG_LOCATION_CHANGED = 1;
private static final long NANOS_PER_MILLI = 1000000L;
@@ -140,7 +145,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
// default background throttling interval if not overriden in settings
- private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 1000;
+ private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
// Location Providers may sometimes deliver location updates
// slightly faster that requested - provide grace period so
@@ -214,16 +219,24 @@ public class LocationManagerService extends ILocationManager.Stub {
private final HashMap<String, Location> mLastLocationCoarseInterval =
new HashMap<>();
- // all providers that operate over proxy, for authorizing incoming location
+ // all providers that operate over proxy, for authorizing incoming location and whitelisting
+ // throttling
private final ArrayList<LocationProviderProxy> mProxyProviders =
new ArrayList<>();
+ private String[] mBackgroundThrottlePackageWhitelist = new String[]{};
+
// current active user on the device - other users are denied location data
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
+ private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
+ private IBatchedLocationCallback mGnssBatchingCallback;
+ private LinkedCallback mGnssBatchingDeathCallback;
+ private boolean mGnssBatchingInProgress = false;
+
public LocationManagerService(Context context) {
super();
mContext = context;
@@ -359,6 +372,26 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
}, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
+ true,
+ new ContentObserver(mLocationHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ String setting = Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+ if (setting == null) {
+ setting = "";
+ }
+
+ mBackgroundThrottlePackageWhitelist = setting.split(",");
+ updateProvidersLocked();
+ }
+ }
+ }, UserHandle.USER_ALL);
mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
// listen for user change
@@ -520,6 +553,7 @@ public class LocationManagerService extends ILocationManager.Stub {
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
+ mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
addProviderLocked(gnssProvider);
@@ -1048,13 +1082,197 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
@Override
public int getGnssYearOfHardware() {
- if (mGnssNavigationMessageProvider != null) {
+ if (mGnssSystemInfoProvider != null) {
return mGnssSystemInfoProvider.getGnssYearOfHardware();
} else {
return 0;
}
}
+ /**
+ * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
+ * (try to) access GNSS information at this layer.
+ */
+ private boolean hasGnssPermissions(String packageName) {
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ checkResolutionLevelIsSufficientForProviderUse(
+ allowedResolutionLevel,
+ LocationManager.GPS_PROVIDER);
+
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
+ long identity = Binder.clearCallingIdentity();
+ boolean hasLocationAccess;
+ try {
+ hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ return hasLocationAccess;
+ }
+
+ /**
+ * Returns the GNSS batching size, if available.
+ */
+ @Override
+ public int getGnssBatchSize(String packageName) {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware batching");
+
+ if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
+ return mGnssBatchingProvider.getSize();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Adds a callback for GNSS Batching events, if permissions allow, which are transported
+ * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
+ */
+ @Override
+ public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware batching");
+
+ if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
+ return false;
+ }
+
+ mGnssBatchingCallback = callback;
+ mGnssBatchingDeathCallback = new LinkedCallback(callback);
+ try {
+ callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
+ } catch (RemoteException e) {
+ // if the remote process registering the listener is already dead, just swallow the
+ // exception and return
+ Log.e(TAG, "Remote listener already died.", e);
+ return false;
+ }
+
+ return true;
+ }
+
+ private class LinkedCallback implements IBinder.DeathRecipient {
+ private final IBatchedLocationCallback mCallback;
+
+ public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
+ mCallback = callback;
+ }
+
+ @NonNull
+ public IBatchedLocationCallback getUnderlyingListener() {
+ return mCallback;
+ }
+
+ @Override
+ public void binderDied() {
+ Log.d(TAG, "Remote Batching Callback died: " + mCallback);
+ stopGnssBatch();
+ removeGnssBatchingCallback();
+ }
+ }
+
+ /**
+ * Removes callback for GNSS batching
+ */
+ @Override
+ public void removeGnssBatchingCallback() {
+ try {
+ mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
+ 0 /* flags */);
+ } catch (NoSuchElementException e) {
+ // if the death callback isn't connected (it should be...), log error, swallow the
+ // exception and return
+ Log.e(TAG, "Couldn't unlink death callback.", e);
+ }
+ mGnssBatchingCallback = null;
+ mGnssBatchingDeathCallback = null;
+ }
+
+
+ /**
+ * Starts GNSS batching, if available.
+ */
+ @Override
+ public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware batching");
+
+ if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
+ return false;
+ }
+
+ if (mGnssBatchingInProgress) {
+ // Current design does not expect multiple starts to be called repeatedly
+ Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
+ // Try to clean up anyway, and continue
+ stopGnssBatch();
+ }
+
+ mGnssBatchingInProgress = true;
+ return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+ }
+
+ /**
+ * Flushes a GNSS batch in progress
+ */
+ @Override
+ public void flushGnssBatch(String packageName) {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware batching");
+
+ if (!hasGnssPermissions(packageName)) {
+ Log.e(TAG, "flushGnssBatch called without GNSS permissions");
+ return;
+ }
+
+ if (!mGnssBatchingInProgress) {
+ Log.w(TAG, "flushGnssBatch called with no batch in progress");
+ }
+
+ if (mGnssBatchingProvider != null) {
+ mGnssBatchingProvider.flush();
+ }
+ }
+
+ /**
+ * Stops GNSS batching
+ */
+ @Override
+ public boolean stopGnssBatch() {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware batching");
+
+ if (mGnssBatchingProvider != null) {
+ mGnssBatchingInProgress = false;
+ return mGnssBatchingProvider.stop();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void reportLocationBatch(List<Location> locations) {
+ checkCallerIsProvider();
+
+ // Currently used only for GNSS locations - update permissions check if changed
+ if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
+ if (mGnssBatchingCallback == null) {
+ Slog.e(TAG, "reportLocationBatch() called without active Callback");
+ return;
+ }
+ try {
+ mGnssBatchingCallback.onLocationBatch(locations);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
+ }
+ } else {
+ Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
+ }
+ }
+
private void addProviderLocked(LocationProviderInterface provider) {
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
@@ -1066,19 +1284,6 @@ public class LocationManagerService extends ILocationManager.Stub {
mProvidersByName.remove(provider.getName());
}
- private boolean isOverlayProviderPackageLocked(String packageName) {
- for (LocationProviderInterface provider : mProviders) {
- if (provider instanceof LocationProviderProxy) {
- if (packageName.equals(
- ((LocationProviderProxy) provider).getConnectedPackageName())) {
- return true;
- }
- }
- }
-
- return false;
- }
-
/**
* Returns "true" if access to the specified location provider is allowed by the current
* user's settings. Access to all location providers is forbidden to non-location-provider
@@ -1542,8 +1747,28 @@ public class LocationManagerService extends ILocationManager.Stub {
p.setRequest(providerRequest, worksource);
}
- private boolean isThrottlingExemptLocked(Receiver recevier) {
- return isOverlayProviderPackageLocked(recevier.mPackageName);
+ private boolean isThrottlingExemptLocked(Receiver receiver) {
+ if (receiver.mUid == Process.SYSTEM_UID) {
+ return true;
+ }
+
+ if (receiver.mPackageName.equals(GMSCORE_PACKAGE)) {
+ return true;
+ }
+
+ for (LocationProviderProxy provider : mProxyProviders) {
+ if (receiver.mPackageName.equals(provider.getConnectedPackageName())) {
+ return true;
+ }
+ }
+
+ for (String whitelistedPackage : mBackgroundThrottlePackageWhitelist) {
+ if (receiver.mPackageName.equals(whitelistedPackage)) {
+ return true;
+ }
+ }
+
+ return false;
}
private class UpdateRecord {
@@ -1766,7 +1991,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + " "
+ (record.mIsForegroundUid ? "foreground" : "background")
- + (isOverlayProviderPackageLocked(receiver.mPackageName) ? " [whitelisted]" : "") + ")");
+ + (isThrottlingExemptLocked(receiver) ? " [whitelisted]" : "") + ")");
UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
if (oldRecord != null) {
@@ -1968,22 +2193,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
- int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
- LocationManager.GPS_PROVIDER);
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
- try {
- if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
- return false;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- if (mGnssStatusProvider == null) {
+ if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
return false;
}
@@ -2011,22 +2221,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public boolean addGnssMeasurementsListener(
IGnssMeasurementsListener listener,
String packageName) {
- int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForProviderUse(
- allowedResolutionLevel,
- LocationManager.GPS_PROVIDER);
-
- int pid = Binder.getCallingPid();
- int uid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
- boolean hasLocationAccess;
- try {
- hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- if (!hasLocationAccess || mGnssMeasurementsProvider == null) {
+ if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
return false;
}
return mGnssMeasurementsProvider.addListener(listener);
@@ -2043,22 +2238,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public boolean addGnssNavigationMessageListener(
IGnssNavigationMessageListener listener,
String packageName) {
- int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForProviderUse(
- allowedResolutionLevel,
- LocationManager.GPS_PROVIDER);
-
- int pid = Binder.getCallingPid();
- int uid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
- boolean hasLocationAccess;
- try {
- hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- if (!hasLocationAccess || mGnssNavigationMessageProvider == null) {
+ if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
return false;
}
return mGnssNavigationMessageProvider.addListener(listener);
@@ -2834,6 +3014,9 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.println(":");
provider.dump(fd, pw, args);
}
+ if (mGnssBatchingInProgress) {
+ pw.println(" GNSS batching in progress");
+ }
}
}
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 2d40e8eebdb5..8ef34dce438b 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -23,6 +23,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -70,6 +71,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -123,20 +125,23 @@ public class LockSettingsService extends ILockSettings.Stub {
private final Object mSeparateChallengeLock = new Object();
+ private final Injector mInjector;
private final Context mContext;
private final Handler mHandler;
- private final LockSettingsStorage mStorage;
+ @VisibleForTesting
+ protected final LockSettingsStorage mStorage;
private final LockSettingsStrongAuth mStrongAuth;
private final SynchronizedStrongAuthTracker mStrongAuthTracker;
- private LockPatternUtils mLockPatternUtils;
- private boolean mFirstCallToVold;
- private IGateKeeperService mGateKeeperService;
- private NotificationManager mNotificationManager;
- private UserManager mUserManager;
+ private final LockPatternUtils mLockPatternUtils;
+ private final NotificationManager mNotificationManager;
+ private final UserManager mUserManager;
+ private final IActivityManager mActivityManager;
- private final KeyStore mKeyStore = KeyStore.getInstance();
+ private final KeyStore mKeyStore;
+ private boolean mFirstCallToVold;
+ protected IGateKeeperService mGateKeeperService;
/**
* The UIDs that are used for system credential storage in keystore.
*/
@@ -177,7 +182,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+ @VisibleForTesting
+ protected static class SynchronizedStrongAuthTracker
+ extends LockPatternUtils.StrongAuthTracker {
public SynchronizedStrongAuthTracker(Context context) {
super(context);
}
@@ -196,8 +203,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- void register() {
- mStrongAuth.registerStrongAuthTracker(this.mStub);
+ void register(LockSettingsStrongAuth strongAuth) {
+ strongAuth.registerStrongAuthTracker(this.mStub);
}
}
@@ -211,7 +218,7 @@ public class LockSettingsService extends ILockSettings.Stub {
public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
// Only for managed profile
- if (!UserManager.get(mContext).getUserInfo(managedUserId).isManagedProfile()) {
+ if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
return;
}
// Do not tie managed profile when work challenge is enabled
@@ -258,38 +265,103 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ static class Injector {
+
+ protected Context mContext;
+
+ public Injector(Context context) {
+ mContext = context;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public Handler getHandler() {
+ return new Handler();
+ }
+
+ public LockSettingsStorage getStorage() {
+ final LockSettingsStorage storage = new LockSettingsStorage(mContext);
+ storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
+ @Override
+ public void initialize(SQLiteDatabase db) {
+ // Get the lockscreen default from a system property, if available
+ boolean lockScreenDisable = SystemProperties.getBoolean(
+ "ro.lockscreen.disable.default", false);
+ if (lockScreenDisable) {
+ storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
+ }
+ }
+ });
+ return storage;
+ }
+
+ public LockSettingsStrongAuth getStrongAuth() {
+ return new LockSettingsStrongAuth(mContext);
+ }
+
+ public SynchronizedStrongAuthTracker getStrongAuthTracker() {
+ return new SynchronizedStrongAuthTracker(mContext);
+ }
+
+ public IActivityManager getActivityManager() {
+ return ActivityManager.getService();
+ }
+
+ public LockPatternUtils getLockPatternUtils() {
+ return new LockPatternUtils(mContext);
+ }
+
+ public NotificationManager getNotificationManager() {
+ return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ public UserManager getUserManager() {
+ return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+
+ public KeyStore getKeyStore() {
+ return KeyStore.getInstance();
+ }
+
+ public IStorageManager getStorageManager() {
+ final IBinder service = ServiceManager.getService("mount");
+ if (service != null) {
+ return IStorageManager.Stub.asInterface(service);
+ }
+ return null;
+ }
+ }
+
public LockSettingsService(Context context) {
- mContext = context;
- mHandler = new Handler();
- mStrongAuth = new LockSettingsStrongAuth(context);
- // Open the database
+ this(new Injector(context));
+ }
- mLockPatternUtils = new LockPatternUtils(context);
+ @VisibleForTesting
+ protected LockSettingsService(Injector injector) {
+ mInjector = injector;
+ mContext = injector.getContext();
+ mKeyStore = injector.getKeyStore();
+ mHandler = injector.getHandler();
+ mStrongAuth = injector.getStrongAuth();
+ mActivityManager = injector.getActivityManager();
+
+ mLockPatternUtils = injector.getLockPatternUtils();
mFirstCallToVold = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
-
- mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
- @Override
- public void initialize(SQLiteDatabase db) {
- // Get the lockscreen default from a system property, if available
- boolean lockScreenDisable = SystemProperties.getBoolean(
- "ro.lockscreen.disable.default", false);
- if (lockScreenDisable) {
- mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
- }
- }
- });
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mStrongAuthTracker = new SynchronizedStrongAuthTracker(mContext);
- mStrongAuthTracker.register();
+ injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
+ null, null);
+ mStorage = injector.getStorage();
+ mNotificationManager = injector.getNotificationManager();
+ mUserManager = injector.getUserManager();
+ mStrongAuthTracker = injector.getStrongAuthTracker();
+ mStrongAuthTracker.register(mStrongAuth);
}
/**
@@ -748,7 +820,8 @@ public class LockSettingsService extends ILockSettings.Stub {
ks.unlock(userHandle, password);
}
- private String getDecryptedPasswordForTiedProfile(int userId)
+ @VisibleForTesting
+ protected String getDecryptedPasswordForTiedProfile(int userId)
throws KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
@@ -814,7 +887,7 @@ public class LockSettingsService extends ILockSettings.Stub {
};
try {
- ActivityManager.getService().unlockUser(userId, token, secret, listener);
+ mActivityManager.unlockUser(userId, token, secret, listener);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -961,7 +1034,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private void tieProfileLockToParent(int userId, String password) {
+ @VisibleForTesting
+ protected void tieProfileLockToParent(int userId, String password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
byte[] encryptionResult;
@@ -1085,8 +1159,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
throws RemoteException {
- final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
- final IStorageManager storageManager = getStorageManager();
+ final UserInfo userInfo = mUserManager.getUserInfo(userId);
+ final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
@@ -1097,7 +1171,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private void fixateNewestUserKeyAuth(int userId)
throws RemoteException {
- final IStorageManager storageManager = getStorageManager();
+ final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
storageManager.fixateNewestUserKeyAuth(userId);
@@ -1396,7 +1470,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// we should, within the first minute of decrypting the phone if this
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
- final IStorageManager service = getStorageManager();
+ final IStorageManager service = mInjector.getStorageManager();
String password;
long identity = Binder.clearCallingIdentity();
try {
@@ -1561,14 +1635,6 @@ public class LockSettingsService extends ILockSettings.Stub {
Secure.LOCK_SCREEN_OWNER_INFO
};
- private IStorageManager getStorageManager() {
- final IBinder service = ServiceManager.getService("mount");
- if (service != null) {
- return IStorageManager.Stub.asInterface(service);
- }
- return null;
- }
-
private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
diff --git a/services/core/java/com/android/server/LockSettingsShellCommand.java b/services/core/java/com/android/server/LockSettingsShellCommand.java
index f72663aed140..e1312519480f 100644
--- a/services/core/java/com/android/server/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/LockSettingsShellCommand.java
@@ -77,7 +77,8 @@ class LockSettingsShellCommand extends ShellCommand {
}
return 0;
} catch (Exception e) {
- getErrPrintWriter().println("Error while executing command: " + e);
+ getErrPrintWriter().println("Error while executing command: " + cmd);
+ e.printStackTrace(getErrPrintWriter());
return -1;
}
}
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index 3d973a04c212..c858036eb024 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -119,9 +119,13 @@ class LockSettingsStorage {
boolean isBaseZeroPattern;
}
- public LockSettingsStorage(Context context, Callback callback) {
+ public LockSettingsStorage(Context context) {
mContext = context;
- mOpenHelper = new DatabaseHelper(context, callback);
+ mOpenHelper = new DatabaseHelper(context);
+ }
+
+ public void setDatabaseOnCreateCallback(Callback callback) {
+ mOpenHelper.setCallback(callback);
}
public void writeKeyValue(String key, String value, int userId) {
@@ -472,11 +476,14 @@ class LockSettingsStorage {
private static final int DATABASE_VERSION = 2;
- private final Callback mCallback;
+ private Callback mCallback;
- public DatabaseHelper(Context context, Callback callback) {
+ public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
setWriteAheadLoggingEnabled(true);
+ }
+
+ public void setCallback(Callback callback) {
mCallback = callback;
}
@@ -492,7 +499,9 @@ class LockSettingsStorage {
@Override
public void onCreate(SQLiteDatabase db) {
createTable(db);
- mCallback.initialize(db);
+ if (mCallback != null) {
+ mCallback.initialize(db);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index 131411060625..f5fe3db5216c 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -51,6 +51,7 @@ public class LockSettingsStrongAuth {
private static final int MSG_REGISTER_TRACKER = 2;
private static final int MSG_UNREGISTER_TRACKER = 3;
private static final int MSG_REMOVE_USER = 4;
+ private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
@@ -128,6 +129,23 @@ public class LockSettingsStrongAuth {
}
}
+ private void handleScheduleStrongAuthTimeout(int userId) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
+ // cancel current alarm listener for the user (if there was one)
+ StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
+ if (alarm != null) {
+ mAlarmManager.cancel(alarm);
+ } else {
+ alarm = new StrongAuthTimeoutAlarmListener(userId);
+ mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
+ }
+ // schedule a new alarm listener for the user
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
+ alarm, mHandler);
+ }
+
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
try {
@@ -151,7 +169,8 @@ public class LockSettingsStrongAuth {
}
public void removeUser(int userId) {
- mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
+ final int argNotUsed = 0;
+ mHandler.obtainMessage(MSG_REMOVE_USER, userId, argNotUsed).sendToTarget();
}
public void requireStrongAuth(int strongAuthReason, int userId) {
@@ -169,29 +188,8 @@ public class LockSettingsStrongAuth {
}
public void reportSuccessfulStrongAuthUnlock(int userId) {
- scheduleStrongAuthTimeout(userId);
- }
-
- private void scheduleStrongAuthTimeout(int userId) {
- final DevicePolicyManager dpm =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
- // cancel current alarm listener for the user (if there was one)
- StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
- if (alarm != null) {
- mAlarmManager.cancel(alarm);
- } else {
- alarm = new StrongAuthTimeoutAlarmListener(userId);
- mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
- }
- // schedule a new alarm listener for the user
- final long ident = Binder.clearCallingIdentity();
- try {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
- alarm, mHandler);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ final int argNotUsed = 0;
+ mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
}
private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
@@ -224,6 +222,9 @@ public class LockSettingsStrongAuth {
case MSG_REMOVE_USER:
handleRemoveUser(msg.arg1);
break;
+ case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
+ handleScheduleStrongAuthTimeout(msg.arg1);
+ break;
}
}
};
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index e8ecc3e5f44a..5fe8b1a8ae9d 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -41,6 +41,10 @@ import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
import android.net.Uri;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -56,6 +60,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.TimedRemoteCaller;
@@ -73,10 +78,13 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
/**
* Backing service for {@link android.net.NetworkScoreManager}.
@@ -85,6 +93,7 @@ import java.util.function.Consumer;
public class NetworkScoreService extends INetworkScoreService.Stub {
private static final String TAG = "NetworkScoreService";
private static final boolean DBG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
private final Context mContext;
private final NetworkScorerAppManager mNetworkScorerAppManager;
@@ -174,11 +183,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
// connection.
if (DBG) Log.d(TAG, "No active scorers available.");
unbindFromScoringServiceIfNeeded();
- } else if (activeScorer.packageName.equals(scorerPackageName)) {
+ } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
+ {
// The active scoring service changed in some way.
if (DBG) {
Log.d(TAG, "Possible change to the active scorer: "
- + activeScorer.packageName);
+ + activeScorer.getRecommendationServicePackageName());
}
if (forceUnbind) {
unbindFromScoringServiceIfNeeded();
@@ -189,7 +199,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
// bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
// will sort that out to leave us bound to the most recent active scorer.
if (DBG) {
- Log.d(TAG, "Binding to " + activeScorer.packageName + " if needed.");
+ Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
+ + " if needed.");
}
bindToScoringServiceIfNeeded(activeScorer);
}
@@ -325,22 +336,19 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
bindToScoringServiceIfNeeded(scorerData);
}
- private void bindToScoringServiceIfNeeded(NetworkScorerAppData scorerData) {
- if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + scorerData + ")");
- if (scorerData != null && scorerData.recommendationServiceClassName != null) {
- ComponentName componentName = new ComponentName(scorerData.packageName,
- scorerData.recommendationServiceClassName);
+ private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
+ if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
+ if (appData != null) {
synchronized (mServiceConnectionLock) {
// If we're connected to a different component then drop it.
if (mServiceConnection != null
- && !mServiceConnection.mComponentName.equals(componentName)) {
+ && !mServiceConnection.mAppData.equals(appData)) {
unbindFromScoringServiceIfNeeded();
}
// If we're not connected at all then create a new connection.
if (mServiceConnection == null) {
- mServiceConnection = new ScoringServiceConnection(componentName,
- scorerData.packageUid);
+ mServiceConnection = new ScoringServiceConnection(appData);
}
// Make sure the connection is connected (idempotent)
@@ -391,6 +399,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
isEmpty = callbackList == null
|| callbackList.getRegisteredCallbackCount() == 0;
}
+
if (isEmpty) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No scorer registered for type " + entry.getKey()
@@ -399,18 +408,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
continue;
}
- sendCallback(new Consumer<INetworkScoreCache>() {
- @Override
- public void accept(INetworkScoreCache networkScoreCache) {
- try {
- networkScoreCache.updateScores(entry.getValue());
- } catch (RemoteException e) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
- }
- }
- }
- }, Collections.singleton(callbackList));
+ final BiConsumer<INetworkScoreCache, Object> consumer =
+ FilteringCacheUpdatingConsumer.create(mContext, entry.getValue(),
+ entry.getKey());
+ sendCacheUpdateCallback(consumer, Collections.singleton(callbackList));
}
return true;
@@ -419,7 +420,211 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
}
- private boolean isCallerSystemUid() {
+ /**
+ * A {@link BiConsumer} implementation that filters the given {@link ScoredNetwork}
+ * list (if needed) before invoking {@link INetworkScoreCache#updateScores(List)} on the
+ * accepted {@link INetworkScoreCache} implementation.
+ */
+ @VisibleForTesting
+ static class FilteringCacheUpdatingConsumer
+ implements BiConsumer<INetworkScoreCache, Object> {
+ private final Context mContext;
+ private final List<ScoredNetwork> mScoredNetworkList;
+ private final int mNetworkType;
+ // TODO: 1/23/17 - Consider a Map if we implement more filters.
+ // These are created on-demand to defer the construction cost until
+ // an instance is actually needed.
+ private UnaryOperator<List<ScoredNetwork>> mCurrentNetworkFilter;
+ private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
+
+ static FilteringCacheUpdatingConsumer create(Context context,
+ List<ScoredNetwork> scoredNetworkList, int networkType) {
+ return new FilteringCacheUpdatingConsumer(context, scoredNetworkList, networkType,
+ null, null);
+ }
+
+ @VisibleForTesting
+ FilteringCacheUpdatingConsumer(Context context,
+ List<ScoredNetwork> scoredNetworkList, int networkType,
+ UnaryOperator<List<ScoredNetwork>> currentNetworkFilter,
+ UnaryOperator<List<ScoredNetwork>> scanResultsFilter) {
+ mContext = context;
+ mScoredNetworkList = scoredNetworkList;
+ mNetworkType = networkType;
+ mCurrentNetworkFilter = currentNetworkFilter;
+ mScanResultsFilter = scanResultsFilter;
+ }
+
+ @Override
+ public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
+ int filterType = NetworkScoreManager.CACHE_FILTER_NONE;
+ if (cookie instanceof Integer) {
+ filterType = (Integer) cookie;
+ }
+
+ try {
+ final List<ScoredNetwork> filteredNetworkList =
+ filterScores(mScoredNetworkList, filterType);
+ if (!filteredNetworkList.isEmpty()) {
+ networkScoreCache.updateScores(filteredNetworkList);
+ }
+ } catch (RemoteException e) {
+ if (VERBOSE) {
+ Log.v(TAG, "Unable to update scores of type " + mNetworkType, e);
+ }
+ }
+ }
+
+ /**
+ * Applies the appropriate filter and returns the filtered results.
+ */
+ private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList,
+ int filterType) {
+ switch (filterType) {
+ case NetworkScoreManager.CACHE_FILTER_NONE:
+ return scoredNetworkList;
+
+ case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK:
+ if (mCurrentNetworkFilter == null) {
+ mCurrentNetworkFilter =
+ new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext));
+ }
+ return mCurrentNetworkFilter.apply(scoredNetworkList);
+
+ case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS:
+ if (mScanResultsFilter == null) {
+ mScanResultsFilter = new ScanResultsScoreCacheFilter(
+ new ScanResultsSupplier(mContext));
+ }
+ return mScanResultsFilter.apply(scoredNetworkList);
+
+ default:
+ Log.w(TAG, "Unknown filter type: " + filterType);
+ return scoredNetworkList;
+ }
+ }
+ }
+
+ /**
+ * Helper class that improves the testability of the cache filter Functions.
+ */
+ private static class WifiInfoSupplier implements Supplier<WifiInfo> {
+ private final Context mContext;
+
+ WifiInfoSupplier(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public WifiInfo get() {
+ WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
+ if (wifiManager != null) {
+ return wifiManager.getConnectionInfo();
+ }
+ Log.w(TAG, "WifiManager is null, failed to return the WifiInfo.");
+ return null;
+ }
+ }
+
+ /**
+ * Helper class that improves the testability of the cache filter Functions.
+ */
+ private static class ScanResultsSupplier implements Supplier<List<ScanResult>> {
+ private final Context mContext;
+
+ ScanResultsSupplier(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public List<ScanResult> get() {
+ WifiScanner wifiScanner = mContext.getSystemService(WifiScanner.class);
+ if (wifiScanner != null) {
+ return wifiScanner.getSingleScanResults();
+ }
+ Log.w(TAG, "WifiScanner is null, failed to return scan results.");
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Filters the given set of {@link ScoredNetwork}s and returns a new List containing only the
+ * {@link ScoredNetwork} associated with the current network. If no network is connected the
+ * returned list will be empty.
+ * <p>
+ * Note: this filter performs some internal caching for consistency and performance. The
+ * current network is determined at construction time and never changed. Also, the
+ * last filtered list is saved so if the same input is provided multiple times in a row
+ * the computation is only done once.
+ */
+ @VisibleForTesting
+ static class CurrentNetworkScoreCacheFilter implements UnaryOperator<List<ScoredNetwork>> {
+ private final NetworkKey mCurrentNetwork;
+
+ CurrentNetworkScoreCacheFilter(Supplier<WifiInfo> wifiInfoSupplier) {
+ mCurrentNetwork = NetworkKey.createFromWifiInfo(wifiInfoSupplier.get());
+ }
+
+ @Override
+ public List<ScoredNetwork> apply(List<ScoredNetwork> scoredNetworks) {
+ if (mCurrentNetwork == null || scoredNetworks.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ for (int i = 0; i < scoredNetworks.size(); i++) {
+ final ScoredNetwork scoredNetwork = scoredNetworks.get(i);
+ if (scoredNetwork.networkKey.equals(mCurrentNetwork)) {
+ return Collections.singletonList(scoredNetwork);
+ }
+ }
+
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Filters the given set of {@link ScoredNetwork}s and returns a new List containing only the
+ * {@link ScoredNetwork} associated with the current set of {@link ScanResult}s.
+ * If there are no {@link ScanResult}s the returned list will be empty.
+ * <p>
+ * Note: this filter performs some internal caching for consistency and performance. The
+ * current set of ScanResults is determined at construction time and never changed.
+ * Also, the last filtered list is saved so if the same input is provided multiple
+ * times in a row the computation is only done once.
+ */
+ @VisibleForTesting
+ static class ScanResultsScoreCacheFilter implements UnaryOperator<List<ScoredNetwork>> {
+ private final Set<NetworkKey> mScanResultKeys;
+
+ ScanResultsScoreCacheFilter(Supplier<List<ScanResult>> resultsSupplier) {
+ List<ScanResult> scanResults = resultsSupplier.get();
+ final int size = scanResults.size();
+ mScanResultKeys = new ArraySet<>(size);
+ for (int i = 0; i < size; i++) {
+ ScanResult scanResult = scanResults.get(i);
+ mScanResultKeys.add(NetworkKey.createFromScanResult(scanResult));
+ }
+ }
+
+ @Override
+ public List<ScoredNetwork> apply(List<ScoredNetwork> scoredNetworks) {
+ if (mScanResultKeys.isEmpty() || scoredNetworks.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<ScoredNetwork> filteredScores = new ArrayList<>();
+ for (int i = 0; i < scoredNetworks.size(); i++) {
+ final ScoredNetwork scoredNetwork = scoredNetworks.get(i);
+ if (mScanResultKeys.contains(scoredNetwork.networkKey)) {
+ filteredScores.add(scoredNetwork);
+ }
+ }
+
+ return filteredScores;
+ }
+ }
+
+ private boolean callerCanRequestScores() {
// REQUEST_NETWORK_SCORES is a signature only permission.
return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
PackageManager.PERMISSION_GRANTED;
@@ -428,7 +633,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public boolean clearScores() {
// Only the active scorer or the system should be allowed to flush all scores.
- if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+ if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
final long token = Binder.clearCallingIdentity();
try {
clearInternal();
@@ -466,7 +671,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public boolean isCallerActiveScorer(int callingUid) {
synchronized (mServiceConnectionLock) {
- return mServiceConnection != null && mServiceConnection.mScoringAppUid == callingUid;
+ return mServiceConnection != null
+ && mServiceConnection.mAppData.packageUid == callingUid;
}
}
@@ -480,7 +686,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
public String getActiveScorerPackage() {
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
- return mServiceConnection.mComponentName.getPackageName();
+ return mServiceConnection.getPackageName();
}
}
return null;
@@ -489,7 +695,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public void disableScoring() {
// Only the active scorer or the system should be allowed to disable scoring.
- if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+ if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
// no-op for now but we could write to the setting if needed.
} else {
throw new SecurityException(
@@ -499,9 +705,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
private void clearInternal() {
- sendCallback(new Consumer<INetworkScoreCache>() {
+ sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
@Override
- public void accept(INetworkScoreCache networkScoreCache) {
+ public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
try {
networkScoreCache.clearScores();
} catch (RemoteException e) {
@@ -574,7 +780,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
return caller.getRecommendationResult(provider, request);
} catch (RemoteException | TimeoutException e) {
Log.w(TAG, "Failed to request a recommendation.", e);
- // TODO(jjoslin): 12/15/16 - Keep track of failures.
+ // TODO: 12/15/16 - Keep track of failures.
}
}
@@ -628,7 +834,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
return;
} catch (RemoteException e) {
Log.w(TAG, "Failed to request a recommendation.", e);
- // TODO(jjoslin): 12/15/16 - Keep track of failures.
+ // TODO: 12/15/16 - Keep track of failures.
// Remove the timeout message
mHandler.removeMessages(timeoutMsg.what, pair);
// Will fall through and send back the default recommendation.
@@ -651,12 +857,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
if (provider != null) {
try {
provider.requestScores(networks);
- // TODO(jjoslin): 12/15/16 - Consider pushing null scores into the cache to
+ // TODO: 12/15/16 - Consider pushing null scores into the cache to
// prevent repeated requests for the same scores.
return true;
} catch (RemoteException e) {
Log.w(TAG, "Failed to request scores.", e);
- // TODO(jjoslin): 12/15/16 - Keep track of failures.
+ // TODO: 12/15/16 - Keep track of failures.
}
}
return false;
@@ -668,32 +874,37 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
- NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
- if (currentScorer == null) {
- writer.println("Scoring is disabled.");
- return;
- }
- writer.println("Current scorer: " + currentScorer.packageName);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
+ if (currentScorer == null) {
+ writer.println("Scoring is disabled.");
+ return;
+ }
+ writer.println("Current scorer: " + currentScorer);
- sendCallback(new Consumer<INetworkScoreCache>() {
- @Override
- public void accept(INetworkScoreCache networkScoreCache) {
- try {
- TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- writer.println("Failed to dump score cache: " + e);
+ sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
+ @Override
+ public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
+ try {
+ TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ writer.println("Failed to dump score cache: " + e);
+ }
}
- }
- }, getScoreCacheLists());
+ }, getScoreCacheLists());
- synchronized (mServiceConnectionLock) {
- if (mServiceConnection != null) {
- mServiceConnection.dump(fd, writer, args);
- } else {
- writer.println("ScoringServiceConnection: null");
+ synchronized (mServiceConnectionLock) {
+ if (mServiceConnection != null) {
+ mServiceConnection.dump(fd, writer, args);
+ } else {
+ writer.println("ScoringServiceConnection: null");
+ }
}
+ writer.flush();
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- writer.flush();
}
/**
@@ -708,14 +919,15 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
}
- private void sendCallback(Consumer<INetworkScoreCache> consumer,
+ private void sendCacheUpdateCallback(BiConsumer<INetworkScoreCache, Object> consumer,
Collection<RemoteCallbackList<INetworkScoreCache>> remoteCallbackLists) {
for (RemoteCallbackList<INetworkScoreCache> callbackList : remoteCallbackLists) {
synchronized (callbackList) { // Ensure only one active broadcast per RemoteCallbackList
final int count = callbackList.beginBroadcast();
try {
for (int i = 0; i < count; i++) {
- consumer.accept(callbackList.getBroadcastItem(i));
+ consumer.accept(callbackList.getBroadcastItem(i),
+ callbackList.getBroadcastCookie(i));
}
} finally {
callbackList.finishBroadcast();
@@ -754,21 +966,19 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
private static class ScoringServiceConnection implements ServiceConnection {
- private final ComponentName mComponentName;
- private final int mScoringAppUid;
+ private final NetworkScorerAppData mAppData;
private volatile boolean mBound = false;
private volatile boolean mConnected = false;
private volatile INetworkRecommendationProvider mRecommendationProvider;
- ScoringServiceConnection(ComponentName componentName, int scoringAppUid) {
- mComponentName = componentName;
- mScoringAppUid = scoringAppUid;
+ ScoringServiceConnection(NetworkScorerAppData appData) {
+ mAppData = appData;
}
void connect(Context context) {
if (!mBound) {
Intent service = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
- service.setComponent(mComponentName);
+ service.setComponent(mAppData.getRecommendationServiceComponent());
mBound = context.bindServiceAsUser(service, this,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
UserHandle.SYSTEM);
@@ -798,6 +1008,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
return mRecommendationProvider;
}
+ String getPackageName() {
+ return mAppData.getRecommendationServiceComponent().getPackageName();
+ }
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString());
@@ -815,7 +1029,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound
+ writer.println("ScoringServiceConnection: "
+ + mAppData.getRecommendationServiceComponent()
+ + ", bound: " + mBound
+ ", connected: " + mConnected);
}
}
diff --git a/services/core/java/com/android/server/PruneInstantAppsJobService.java b/services/core/java/com/android/server/PruneInstantAppsJobService.java
new file mode 100644
index 000000000000..a6c36850dd81
--- /dev/null
+++ b/services/core/java/com/android/server/PruneInstantAppsJobService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+
+import java.util.concurrent.TimeUnit;
+
+public class PruneInstantAppsJobService extends JobService {
+ private static final boolean DEBUG = false;
+
+ private static final int JOB_ID = 765123;
+
+ private static final long PRUNE_INSTANT_APPS_PERIOD_MILLIS = DEBUG
+ ? TimeUnit.MINUTES.toMillis(1) : TimeUnit.DAYS.toMillis(1);
+
+ public static void schedule(Context context) {
+ JobInfo pruneJob = new JobInfo.Builder(JOB_ID, new ComponentName(
+ context.getPackageName(), PruneInstantAppsJobService.class.getName()))
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(PRUNE_INSTANT_APPS_PERIOD_MILLIS)
+ .build();
+
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ jobScheduler.schedule(pruneJob);
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ packageManagerInternal.pruneInstantApps();
+ jobFinished(params, false);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index bb8401ff371a..c77a407f1fab 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -19,6 +19,9 @@ package com.android.server;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
+import android.os.Build;
import android.os.RecoverySystem;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -45,6 +48,7 @@ import com.android.internal.util.ArrayUtils;
public class RescueParty {
private static final String TAG = "RescueParty";
+ private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
private static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
@@ -60,11 +64,34 @@ public class RescueParty {
/** Threshold for app crash loops */
private static SparseArray<Threshold> sApps = new SparseArray<>();
+ private static boolean isDisabled() {
+ // We're disabled on all engineering devices
+ if (Build.IS_ENG) return true;
+
+ // We're disabled on userdebug devices connected over USB, since that's
+ // a decent signal that someone is actively trying to debug the device,
+ // or that it's in a lab environment.
+ if (Build.IS_USERDEBUG) {
+ try {
+ if (LocalServices.getService(BatteryManagerInternal.class)
+ .getPlugType() == BatteryManager.BATTERY_PLUGGED_USB) {
+ return true;
+ } else {
+ }
+ } catch (Throwable ignored) {
+ }
+ }
+
+ // One last-ditch check
+ return SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false);
+ }
+
/**
* Take note of a boot event. If we notice too many of these events
* happening in rapid succession, we'll send out a rescue party.
*/
public static void noteBoot(Context context) {
+ if (isDisabled()) return;
if (sBoot.incrementAndTest()) {
sBoot.reset();
incrementRescueLevel(sBoot.uid);
@@ -77,6 +104,7 @@ public class RescueParty {
* events happening in rapid succession, we'll send out a rescue party.
*/
public static void notePersistentAppCrash(Context context, int uid) {
+ if (isDisabled()) return;
Threshold t = sApps.get(uid);
if (t == null) {
t = new AppThreshold(uid);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e11dd1aae400..c07add0267cb 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2080,9 +2080,6 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public String getPrimaryStorageUuid() {
- enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- waitForReady();
-
synchronized (mLock) {
return mPrimaryStorageUuid;
}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index d1968507508a..5cc9bfd52b13 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -44,7 +44,7 @@ public class SystemServerInitThreadPool {
private static SystemServerInitThreadPool sInstance;
- private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(2,
+ private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
"system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
public static synchronized SystemServerInitThreadPool get() {
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index cbd7be7343bb..2b5166e0d52c 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -198,7 +198,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
}
- private class TextServicesMonitor extends PackageMonitor {
+ private final class TextServicesMonitor extends PackageMonitor {
private boolean isChangingPackagesOfCurrentUser() {
final int userId = getChangingUserId();
final boolean retval = userId == mSettings.getCurrentUserId();
@@ -236,7 +236,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- class TextServicesBroadcastReceiver extends BroadcastReceiver {
+ private final class TextServicesBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -618,8 +618,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
Slog.w(TAG, "Start spell checker session inner locked.");
}
final String sciId = info.getId();
- final InternalServiceConnection connection = new InternalServiceConnection(
- sciId, locale, bundle);
+ final InternalServiceConnection connection = new InternalServiceConnection(sciId);
final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
serviceIntent.setComponent(info.getComponent());
if (DBG) {
@@ -836,7 +835,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
// SpellCheckerBindGroup contains active text service session listeners.
// If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
// mSpellCheckerBindGroups
- private class SpellCheckerBindGroup {
+ private final class SpellCheckerBindGroup {
private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
private final InternalServiceConnection mInternalConnection;
private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners =
@@ -972,15 +971,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- private class InternalServiceConnection implements ServiceConnection {
+ private final class InternalServiceConnection implements ServiceConnection {
private final String mSciId;
- private final String mLocale;
- private final Bundle mBundle;
- public InternalServiceConnection(
- String id, String locale, Bundle bundle) {
+ public InternalServiceConnection(String id) {
mSciId = id;
- mLocale = locale;
- mBundle = bundle;
}
@Override
@@ -1013,7 +1007,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- private class InternalDeathRecipient implements IBinder.DeathRecipient {
+ private static final class InternalDeathRecipient implements IBinder.DeathRecipient {
public final ITextServicesSessionListener mTsListener;
public final ISpellCheckerSessionListener mScListener;
public final String mScLocale;
@@ -1041,7 +1035,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- private static class TextServicesSettings {
+ private static final class TextServicesSettings {
private final ContentResolver mResolver;
@UserIdInt
private int mCurrentUserId;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 440ac90a99d8..6f2f2c402f43 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -35,22 +35,26 @@ import android.content.res.Resources;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
-import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
+import android.text.TextUtils;
import android.util.Slog;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerPolicy;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
@@ -58,7 +62,6 @@ import com.android.server.power.ShutdownThread;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
-import com.android.server.wm.WindowManagerService;
final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
@@ -234,7 +237,7 @@ final class UiModeManagerService extends SystemService {
publishBinderService(Context.UI_MODE_SERVICE, mService);
}
- private final IBinder mService = new IUiModeManager.Stub() {
+ private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
@Override
public void enableCarMode(int flags) {
if (isUiModeLocked()) {
@@ -343,6 +346,28 @@ final class UiModeManagerService extends SystemService {
}
@Override
+ public String[] getAvailableThemes() {
+ if (getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_THEME_OVERLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "getAvailableThemes requires MODIFY_THEME_OVERLAY permission");
+ return null;
+ }
+ String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
+ if (TextUtils.isEmpty(def)) {
+ def = null;
+ }
+ String[] fileList = new File("/vendor/overlay").list();
+ if (fileList == null) return new String[0];
+ ArrayList<String> options = new ArrayList(fileList.length + 1);
+ Collections.addAll(options, fileList);
+ if (!options.contains(def)) {
+ options.add(0, def);
+ }
+ return options.toArray(new String[options.size()]);
+ }
+
+ @Override
public int getNightMode() {
synchronized (mLock) {
return mNightMode;
@@ -364,6 +389,12 @@ final class UiModeManagerService extends SystemService {
}
@Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ new Shell(mService).exec(mService, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -751,4 +782,101 @@ final class UiModeManagerService extends SystemService {
}
}
+ /**
+ * Handles "adb shell" commands.
+ */
+ private static class Shell extends ShellCommand {
+ public static final String NIGHT_MODE_STR_YES = "yes";
+ public static final String NIGHT_MODE_STR_NO = "no";
+ public static final String NIGHT_MODE_STR_AUTO = "auto";
+ public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
+ private final IUiModeManager mInterface;
+
+ Shell(IUiModeManager iface) {
+ mInterface = iface;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("UiModeManager service (uimode) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" night [yes|no|auto]");
+ pw.println(" Set or read night mode.");
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ try {
+ switch (cmd) {
+ case "night":
+ return handleNightMode();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ final PrintWriter err = getErrPrintWriter();
+ err.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ private int handleNightMode() throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ final String modeStr = getNextArg();
+ if (modeStr == null) {
+ printCurrentNightMode();
+ return 0;
+ }
+
+ final int mode = strToNightMode(modeStr);
+ if (mode >= 0) {
+ mInterface.setNightMode(mode);
+ printCurrentNightMode();
+ return 0;
+ } else {
+ err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
+ + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO + "'");
+ return -1;
+ }
+ }
+
+ private void printCurrentNightMode() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final int currMode = mInterface.getNightMode();
+ final String currModeStr = nightModeToStr(currMode);
+ pw.println("Night mode: " + currModeStr);
+ }
+
+ private static String nightModeToStr(int mode) {
+ switch (mode) {
+ case UiModeManager.MODE_NIGHT_YES:
+ return NIGHT_MODE_STR_YES;
+ case UiModeManager.MODE_NIGHT_NO:
+ return NIGHT_MODE_STR_NO;
+ case UiModeManager.MODE_NIGHT_AUTO:
+ return NIGHT_MODE_STR_AUTO;
+ default:
+ return NIGHT_MODE_STR_UNKNOWN;
+ }
+ }
+
+ private static int strToNightMode(String modeStr) {
+ switch (modeStr) {
+ case NIGHT_MODE_STR_YES:
+ return UiModeManager.MODE_NIGHT_YES;
+ case NIGHT_MODE_STR_NO:
+ return UiModeManager.MODE_NIGHT_NO;
+ case NIGHT_MODE_STR_AUTO:
+ return UiModeManager.MODE_NIGHT_AUTO;
+ default:
+ return -1;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 0a6c62f54564..fbc444026539 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -63,8 +63,8 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -76,6 +76,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -111,15 +112,16 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -174,17 +176,18 @@ public class AccountManagerService
private static final String PRE_N_DATABASE_NAME = "accounts.db";
private static final Intent ACCOUNTS_CHANGED_INTENT;
+ private static final int SIGNATURE_CHECK_MISMATCH = 0;
+ private static final int SIGNATURE_CHECK_MATCH = 1;
+ private static final int SIGNATURE_CHECK_UID_MATCH = 2;
+
static {
ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
}
-
private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
private final AtomicInteger mNotificationIds = new AtomicInteger(1);
- private static final String NEW_ACCOUNT_VISIBLE = "android.accounts.NEW_ACCOUNT_VISIBLE";
-
static class UserAccounts {
private final int userId;
final AccountsDb accountsDb;
@@ -204,6 +207,11 @@ public class AccountManagerService
/** protected by the {@link #cacheLock} */
private final TokenCache accountTokenCaches = new TokenCache();
+ /** protected by the {@link #cacheLock} */
+ // TODO use callback to set up the map.
+ private final Map<String, LinkedHashSet<String>> mApplicationAccountRequestMappings =
+ new HashMap<>();
+
/**
* protected by the {@link #cacheLock}
*
@@ -261,8 +269,6 @@ public class AccountManagerService
sThis.set(this);
- addRequestsForPreInstalledApplications();
-
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
@@ -281,42 +287,20 @@ public class AccountManagerService
* and then rebuild the cache. All under the cache lock. But that change is too
* large at this point.
*/
+ final String removedPackageName = intent.getData().toString();
Runnable purgingRunnable = new Runnable() {
@Override
public void run() {
purgeOldGrantsAll();
- // TODO remove visibility entries.
+ // Notify authenticator about removed app?
+ removeVisibilityValuesForPackage(removedPackageName);
}
};
mHandler.post(purgingRunnable);
}
-
}
}, intentFilter);
- IntentFilter packageAddedOrChangedFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageAddedOrChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageAddedOrChangedFilter.addDataScheme("package");
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context1, Intent intent) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- int uidOfInstalledApplication =
- intent.getIntExtra(Intent.EXTRA_UID, -1);
- if(uidOfInstalledApplication != -1) {
- registerAccountTypesSupported(
- uidOfInstalledApplication,
- getUserAccounts(
- UserHandle.getUserId(uidOfInstalledApplication)));
- }
- }
- });
- }
- }, UserHandle.ALL, packageAddedOrChangedFilter, null, null);
-
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@@ -380,11 +364,13 @@ public class AccountManagerService
final long identity = Binder.clearCallingIdentity();
try {
for (String packageName : packageNames) {
- if (mPackageManager.checkPermission(
- Manifest.permission.GET_ACCOUNTS, packageName)
- != PackageManager.PERMISSION_GRANTED) {
- continue;
- }
+ // if app asked for permission we need to cancel notification even
+ // for O+ applications.
+ if (mPackageManager.checkPermission(
+ Manifest.permission.GET_ACCOUNTS,
+ packageName) != PackageManager.PERMISSION_GRANTED) {
+ continue;
+ }
if (accounts == null) {
accounts = getAccountsAsUser(null, userId, "android");
@@ -443,112 +429,412 @@ public class AccountManagerService
}
@Override
- public boolean addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras,
- Map uidToVisibility) {
- // TODO implementation
- return false;
+ public boolean addAccountExplicitlyWithVisibility(Account account, String password,
+ Bundle extras, Map packageToVisibility) {
+ Bundle.setDefusable(extras, true);
+
+ final int callingUid = Binder.getCallingUid();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
+ + ", pid " + Binder.getCallingPid());
+ }
+ Preconditions.checkNotNull(account, "account cannot be null");
+ int userId = UserHandle.getCallingUserId();
+ if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
+ String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
+ callingUid, account.type);
+ throw new SecurityException(msg);
+ }
+ /*
+ * Child users are not allowed to add accounts. Only the accounts that are shared by the
+ * parent profile can be added to child profile.
+ *
+ * TODO: Only allow accounts that were shared to be added by a limited user.
+ */
+ // fails if the account already exists
+ long identityToken = clearCallingIdentity();
+ try {
+ UserAccounts accounts = getUserAccounts(userId);
+ return addAccountInternal(accounts, account, password, extras, callingUid,
+ (Map<String, Integer>) packageToVisibility);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
}
@Override
public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
String accountType) {
- // TODO Implement.
- return new HashMap<Account, Integer>();
+ int callingUid = Binder.getCallingUid();
+ boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
+ List<String> managedTypes =
+ getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
+
+ if ((accountType != null && !managedTypes.contains(accountType))
+ || (accountType == null && !isSystemUid)) {
+ throw new SecurityException(
+ "getAccountsAndVisibilityForPackage() called from unauthorized uid "
+ + callingUid + " with packageName=" + packageName);
+ }
+ if (accountType != null) {
+ managedTypes = new ArrayList<String>();
+ managedTypes.add(accountType);
+ }
+
+ return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
+ getUserAccounts(UserHandle.getUserId(callingUid)));
+ }
+
+ /*
+ * accountTypes may not be null
+ */
+ private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
+ List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
+ int uid = 0;
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName,
+ UserHandle.getUserId(callingUid));
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
+ return new HashMap<>();
+ }
+
+ Map<Account, Integer> result = new HashMap<>();
+ for (String accountType : accountTypes) {
+ synchronized (accounts.cacheLock) {
+ final Account[] accountsOfType = accounts.accountCache.get(accountType);
+ if (accountsOfType != null) {
+ for (Account account : accountsOfType) {
+ result.put(account,
+ resolveAccountVisibility(account, packageName, accounts));
+ }
+ }
+ }
+ }
+ return filterSharedAccounts(accounts, result, callingUid, packageName);
}
@Override
- public int[] getRequestingUidsForType(String accountType) {
+ public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
+ if (account == null) throw new IllegalArgumentException("account is null");
int callingUid = Binder.getCallingUid();
- if (!isAccountManagedByCaller(accountType, callingUid, UserHandle.getUserId(callingUid))) {
+ int userId = UserHandle.getUserId(callingUid);
+ UserAccounts accounts = getUserAccounts(userId);
+ if (!isAccountManagedByCaller(account.type, callingUid, userId)
+ && !isSystemUid(callingUid)) {
+ String msg =
+ String.format("uid %s cannot get secrets for account %s", callingUid, account);
+ throw new SecurityException(msg);
+ }
+ return getPackagesAndVisibilityForAccount(account, accounts);
+ }
+
+ /**
+ * Returns all package names and visibility values, which were set for given account.
+ *
+ * @param account Account to get visibility values.
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return Map from package names to visibility.
+ */
+ private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
+ UserAccounts accounts) {
+ final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ return accounts.accountsDb.findAllVisibilityValuesForAccount(account);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ }
+
+ @Override
+ public int getAccountVisibility(Account a, String packageName) {
+ if (a == null) throw new IllegalArgumentException("account is null");
+ int callingUid = Binder.getCallingUid();
+ if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+ && !isSystemUid(callingUid)) {
String msg = String.format(
"uid %s cannot get secrets for accounts of type: %s",
callingUid,
- accountType);
+ a.type);
throw new SecurityException(msg);
}
- // TODO Implement.
- return new int[]{};
+ return getAccountVisibility(a, packageName,
+ getUserAccounts(UserHandle.getUserId(callingUid)));
}
- @Override
- public int getAccountVisibility(Account a, int uid) {
- // TODO Implement.
- return 0;
+ /**
+ * Method returns visibility for given account and package name.
+ *
+ * @param account The account to check visibility.
+ * @param packageName Package name to check visibility.
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
+ *
+ */
+ private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
+ final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
+ return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
}
- @Override
- public boolean setAccountVisibility(Account a, int uid, int visibility) {
- // TODO Implement.
- return false;
+ /**
+ * Method which handles default values for Account visibility.
+ *
+ * @param account The account to check visibility.
+ * @param packageName Package name to check visibility
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
+ *
+ */
+ private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
+ UserAccounts accounts) {
+ Preconditions.checkNotNull(packageName, "packageName cannot be null");
+
+ int uid = -1;
+ try {
+ long identityToken = clearCallingIdentity();
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
+ return AccountManager.VISIBILITY_NOT_VISIBLE;
+ }
+
+ // System visibility can not be restricted.
+ if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
+ return AccountManager.VISIBILITY_VISIBLE;
+ }
+
+ int signatureCheckResult =
+ checkPackageSignature(account.type, uid, accounts.userId);
+
+ // Authenticator can not restrict visibility to itself.
+ if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
+ return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
+ }
+
+ if (isSpecialPackageKey(packageName)) {
+ Log.d(TAG, "Package name is forbidden: " + packageName);
+ return AccountManager.VISIBILITY_NOT_VISIBLE;
+ }
+
+ // Return stored value if it was set.
+ int visibility = getAccountVisibility(account, packageName, accounts);
+
+ if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
+ return visibility;
+ }
+
+ boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
+ Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+
+ // Device/Profile owner gets visibility by default.
+ if (isProfileOwner(uid)) {
+ return AccountManager.VISIBILITY_VISIBLE;
+ }
+ // Apps with READ_CONTACTS permission get visibility by default even post O.
+ boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
+
+ boolean preO = isPreOApplication(packageName);
+ if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
+ || (preO && checkGetAccountsPermission(packageName, accounts.userId))
+ || canReadContacts || isPrivileged) {
+ // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
+ // match.
+ visibility = getAccountVisibility(account,
+ AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+ visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
+ }
+ } else {
+ visibility = getAccountVisibility(account,
+ AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+ visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
+ }
+ }
+ return visibility;
}
/**
- * Registers the requested login account types requested by all the applications already
- * installed on the device.
+ * Checks targetSdk for a package;
+ *
+ * @param packageName Package name
+ *
+ * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
+ * undefined
*/
- private void addRequestsForPreInstalledApplications() {
- List<PackageInfo> allInstalledPackages = mPackageManager.getInstalledPackages(0);
- for(PackageInfo pi : allInstalledPackages) {
- int currentUid = pi.applicationInfo.uid;
- if(currentUid != -1) {
- registerAccountTypesSupported(currentUid,
- getUserAccounts(UserHandle.getUserId(currentUid)));
+ private boolean isPreOApplication(String packageName) {
+ try {
+ long identityToken = clearCallingIdentity();
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+
+ if (applicationInfo != null) {
+ int version = applicationInfo.targetSdkVersion;
+ return version < android.os.Build.VERSION_CODES.O;
}
+ return true;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
+ return true;
}
}
+ @Override
+ public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
+ if (a == null) throw new IllegalArgumentException("account is null");
+ int callingUid = Binder.getCallingUid();
+ if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+ && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get secrets for accounts of type: %s",
+ callingUid,
+ a.type);
+ throw new SecurityException(msg);
+ }
+ return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
+ getUserAccounts(UserHandle.getUserId(callingUid)));
+ }
+
/**
- * Registers an application, represented by a UID, to support account types detailed in the
- * applications manifest as well as allowing it to opt for notifications.
+ * Updates visibility for given account name and package.
+ *
+ * @param account Account to update visibility.
+ * @param packageName Package name for which visibility is updated.
+ * @param newVisibility New visibility calue
+ * @param notify if the flag is set applications will get notification about visibility change
+ * @param accounts UserAccount that currently hosts the account and application
*
- * @param uid UID of application
- * @param ua UserAccount that currently hosts the account and application
+ * @return True if account visibility was changed.
*/
- private void registerAccountTypesSupported(int uid, UserAccounts ua) {
- return;
- // TODO clean up the code, manifest entry is deprecated
- /*
- String interestedPackages = null;
- try {
- String[] allPackages = mPackageManager.getPackagesForUid(uid);
- if (allPackages != null) {
- for (String aPackage : allPackages) {
- ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
- PackageManager.GET_META_DATA);
- Bundle b = ai.metaData;
- if (b == null) {
- return;
+ private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
+ boolean notify, UserAccounts accounts) {
+ synchronized (accounts.cacheLock) {
+ LinkedHashSet<String> interestedPackages;
+ if (notify) {
+ if (isSpecialPackageKey(packageName)) {
+ interestedPackages = getRequestingPackageNames(account.type, accounts);
+ } else {
+ if (!packageExistsForUser(packageName, accounts.userId)) {
+ return false; // package is not installed.
}
- interestedPackages = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
+ interestedPackages = new LinkedHashSet<>();
+ interestedPackages.add(packageName);
}
+ } else {
+ // Notifications will not be send.
+ if (!isSpecialPackageKey(packageName) &&
+ !packageExistsForUser(packageName, accounts.userId)) {
+ // package is not installed and not meta value.
+ return false;
+ }
+ interestedPackages = new LinkedHashSet<>();
}
- } catch (PackageManager.NameNotFoundException e) {
- Log.d("NameNotFoundException", e.getMessage());
- }
- if (interestedPackages != null) {
- // TODO request visibility
- // requestAccountVisibility(interestedPackages.split(";"), uid, ua);
+ Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
+
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
+ if (accountId < 0) {
+ return false;
+ }
+ int index = 0;
+ for (String interestedPackage : interestedPackages) {
+ interestedPackagesVisibility[index++] =
+ resolveAccountVisibility(account, interestedPackage, accounts);
+ }
+
+ final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+ try {
+ if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
+ newVisibility)) {
+ return false;
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ index = 0;
+ for (String interestedPackage : interestedPackages) {
+ int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
+ if (visibility != interestedPackagesVisibility[index++]) {
+ sendNotification(interestedPackage, account, accounts.userId);
+ }
+ }
+ if (notify) {
+ sendAccountsChangedBroadcast(accounts.userId);
+ }
+ return true;
}
- */
}
/**
* Sends a direct intent to a package, notifying it of a visible account change.
*
- * @param desiredPackage to send Account to
- * @param visibleAccount to send to package
+ * @param packageName to send Account to
+ * @param account to send to package
+ * @param userId User
*/
- private void sendNotification(String desiredPackage, Account visibleAccount) {
- // TODO replace with callback
- /*
- Intent intent = new Intent();
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- intent.setAction(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
- intent.setPackage(desiredPackage);
- // TODO update documentation, add account extra if new account became visible
- // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
- mContext.sendBroadcast(intent);
- */
+ private void sendNotification(String packageName, Account account, int userId) {
+ // TODO send notification so apps subscribed in runtime.
+ }
+
+ private void sendNotification(Account account, UserAccounts accounts) {
+ LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
+ accounts);
+ for (String packageName : interestedPackages) {
+ int visibility = resolveAccountVisibility(account, packageName, accounts);
+ if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ sendNotification(packageName, account, accounts.userId);
+ }
+ }
+ }
+
+ LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
+ // TODO return packages registered to get notifications.
+ return new LinkedHashSet<String>();
+ }
+
+ private boolean packageExistsForUser(String packageName, int userId) {
+ try {
+ long identityToken = clearCallingIdentity();
+ try {
+ mPackageManager.getPackageUidAsUser(packageName, userId);
+ return true; // package exist
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if packageName is one of special values.
+ */
+ private boolean isSpecialPackageKey(String packageName) {
+ return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
+ || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
+ }
+
+ private void sendAccountsChangedBroadcast(int userId) {
+ Log.i(TAG, "the accounts changed, sending broadcast of "
+ + ACCOUNTS_CHANGED_INTENT.getAction());
+ mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
}
@Override
@@ -688,6 +974,12 @@ public class AccountManagerService
accounts.userDataCache.remove(account);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
+ LinkedHashSet<String> interestedPackages =
+ getRequestingPackageNames(account.type, accounts);
+ for (String packageName : interestedPackages) {
+ sendNotification(packageName, null, accounts.userId);
+ }
+
} else {
ArrayList<String> accountNames = accountNamesByType.get(account.type);
if (accountNames == null) {
@@ -792,7 +1084,7 @@ public class AccountManagerService
AccountsDb.TABLE_ACCOUNTS);
for (Account account : accountsToRemove) {
- removeAccountInternal(accounts, account, Process.myUid());
+ removeAccountInternal(accounts, account, Process.SYSTEM_UID);
}
}
}
@@ -820,6 +1112,20 @@ public class AccountManagerService
}
}
+ private void removeVisibilityValuesForPackage(String packageName) {
+ synchronized (mUsers) {
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserAccounts accounts = mUsers.valueAt(i);
+ try {
+ int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
+ } catch (NameNotFoundException e) {
+ // package does not exist - remove visibility values
+ accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
+ }
+ }
+ }
+ }
+
private void onUserRemoved(Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId < 1) return;
@@ -1049,7 +1355,7 @@ public class AccountManagerService
private boolean isCrossUser(int callingUid, int userId) {
return (userId != UserHandle.getCallingUserId()
- && callingUid != Process.myUid()
+ && callingUid != Process.SYSTEM_UID
&& mContext.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED);
@@ -1057,42 +1363,7 @@ public class AccountManagerService
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
- Bundle.setDefusable(extras, true);
- // clears the visible list functionality for this account because this method allows
- // default account access to all applications for account.
-
- final int callingUid = Binder.getCallingUid();
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "addAccountExplicitly: " + account
- + ", caller's uid " + callingUid
- + ", pid " + Binder.getCallingPid());
- }
- if (account == null) throw new IllegalArgumentException("account is null");
- int userId = UserHandle.getCallingUserId();
- if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
- String msg = String.format(
- "uid %s cannot explicitly add accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
-
- /*
- * Child users are not allowed to add accounts. Only the accounts that are
- * shared by the parent profile can be added to child profile.
- *
- * TODO: Only allow accounts that were shared to be added by
- * a limited user.
- */
-
- // fails if the account already exists
- long identityToken = clearCallingIdentity();
- try {
- UserAccounts accounts = getUserAccounts(userId);
- return addAccountInternal(accounts, account, password, extras, callingUid);
- } finally {
- restoreCallingIdentity(identityToken);
- }
+ return addAccountExplicitlyWithVisibility(account, password, extras, null);
}
@Override
@@ -1233,6 +1504,8 @@ public class AccountManagerService
// TODO: Anything to do if if succedded?
// TODO: If it failed: Show error notification? Should we remove the shadow
// account to avoid retries?
+ // TODO: what we do with the visibility?
+
super.onResult(result);
}
@@ -1250,7 +1523,7 @@ public class AccountManagerService
}
private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
- Bundle extras, int callingUid) {
+ Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Bundle.setDefusable(extras, true);
if (account == null) {
return false;
@@ -1290,10 +1563,17 @@ public class AccountManagerService
}
}
}
+
+ if (packageToVisibility != null) {
+ for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
+ setAccountVisibility(account, entry.getKey() /* package */,
+ entry.getValue() /* visibility */, false /* notify */, accounts);
+ }
+ }
accounts.accountsDb.setTransactionSuccessful();
- logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
- accountId, accounts, callingUid);
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
+ accounts, callingUid);
insertAccountIntoCacheLocked(accounts, account);
} finally {
@@ -1304,8 +1584,10 @@ public class AccountManagerService
addAccountToLinkedRestrictedUsers(account, accounts.userId);
}
+ sendNotification(account, accounts);
// Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
sendAccountsChangedBroadcast(accounts.userId);
+
return true;
}
@@ -1338,6 +1620,7 @@ public class AccountManagerService
public void hasFeatures(IAccountManagerResponse response,
Account account, String[] features, String opPackageName) {
int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "hasFeatures: " + account
+ ", response " + response
@@ -1482,6 +1765,10 @@ public class AccountManagerService
synchronized (accounts.cacheLock) {
accounts.accountsDb.beginTransaction();
Account renamedAccount = new Account(newName, accountToRename.type);
+ if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
+ Log.e(TAG, "renameAccount failed - account with new name already exists");
+ return null;
+ }
try {
final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
if (accountId >= 0) {
@@ -1493,6 +1780,9 @@ public class AccountManagerService
Log.e(TAG, "renameAccount failed");
return null;
}
+ } else {
+ Log.e(TAG, "renameAccount failed - old account does not exist");
+ return null;
}
} finally {
accounts.accountsDb.endTransaction();
@@ -1535,6 +1825,9 @@ public class AccountManagerService
}
}
}
+
+ // Notify authenticator.
+ sendNotification(resultAccount, accounts);
sendAccountsChangedBroadcast(accounts.userId);
}
return resultAccount;
@@ -1733,6 +2026,17 @@ public class AccountManagerService
+ " is still locked. CE data will be removed later");
}
synchronized (accounts.cacheLock) {
+ LinkedHashSet<String> interestedPackages =
+ accounts.mApplicationAccountRequestMappings.get(account.type);
+ if (interestedPackages == null) {
+ interestedPackages = new LinkedHashSet<>();
+ }
+ int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
+ int index = 0;
+ for (String packageName : interestedPackages) {
+ int visibility = resolveAccountVisibility(account, packageName, accounts);
+ visibilityForInterestedPackages[index++] = visibility;
+ }
accounts.accountsDb.beginTransaction();
// Set to a dummy value, this will only be used if the database
// transaction succeeds.
@@ -1756,6 +2060,17 @@ public class AccountManagerService
}
if (isChanged) {
removeAccountFromCacheLocked(accounts, account);
+ index = 0;
+ for (String packageName : interestedPackages) {
+ if ((visibilityForInterestedPackages[index]
+ != AccountManager.VISIBILITY_NOT_VISIBLE)
+ && (visibilityForInterestedPackages[index]
+ != AccountManager.VISIBILITY_UNDEFINED)) {
+ sendNotification(packageName, account, accounts.userId);
+ }
+ ++index;
+ }
+
// Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
sendAccountsChangedBroadcast(accounts.userId);
String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
@@ -2022,18 +2337,13 @@ public class AccountManagerService
accounts.accountsDb.endTransaction();
if (isChanged) {
// Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
+ sendNotification(account, accounts);
sendAccountsChangedBroadcast(accounts.userId);
}
}
}
}
- private void sendAccountsChangedBroadcast(int userId) {
- Log.i(TAG, "the accounts changed, sending broadcast of "
- + ACCOUNTS_CHANGED_INTENT.getAction());
- mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
- }
-
@Override
public void clearPassword(Account account) {
final int callingUid = Binder.getCallingUid();
@@ -2412,8 +2722,10 @@ public class AccountManagerService
checkKeyIntent(
Binder.getCallingUid(),
intent);
- doNotification(mAccounts,
- account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
+ doNotification(
+ mAccounts,
+ account,
+ result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
intent, "android", accounts.userId);
}
}
@@ -3298,7 +3610,8 @@ public class AccountManagerService
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
int userId = UserHandle.getCallingUserId();
- if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
+ if (!isAccountManagedByCaller(accountType, callingUid, userId)
+ && !isSystemUid(callingUid)) {
String msg = String.format(
"uid %s cannot edit authenticator properites for account type: %s",
callingUid,
@@ -3341,23 +3654,50 @@ public class AccountManagerService
Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
try {
- final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
return hasAccountAccess(account, packageName, uid);
} catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
}
+ // Returns package with oldest target SDK for given UID.
+ private String getPackageNameForUid(int uid) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return null;
+ }
+ // For app op checks related to permissions all packages in the UID
+ // have the same app op state, so doesn't matter which one we pick.
+ // Update: due to visibility changes we want to use package with oldest target SDK,
+
+ String packageName = packageNames[0];
+ int oldestVersion = Integer.MAX_VALUE;
+ for (String name : packageNames) {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
+ if (applicationInfo != null) {
+ int version = applicationInfo.targetSdkVersion;
+ if (version < oldestVersion) {
+ oldestVersion = version;
+ packageName = name;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ // skip
+ }
+ }
+ return packageName;
+ }
+
private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
int uid) {
if (packageName == null) {
- String[] packageNames = mPackageManager.getPackagesForUid(uid);
- if (ArrayUtils.isEmpty(packageNames)) {
+ packageName = getPackageNameForUid(uid);
+ if (packageName == null) {
return false;
}
- // For app op checks related to permissions all packages in the UID
- // have the same app op state, so doesn't matter which one we pick.
- packageName = packageNames[0];
}
// Use null token which means any token. Having a token means the package
@@ -3366,27 +3706,12 @@ public class AccountManagerService
return true;
}
// In addition to the permissions required to get an auth token we also allow
- // the account to be accessed by holders of the get accounts permissions.
- return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
- || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
- }
+ // the account to be accessed by apps for which user or authenticator granted visibility.
- private boolean checkUidPermission(String permission, int uid, String opPackageName) {
- final long identity = Binder.clearCallingIdentity();
- try {
- IPackageManager pm = ActivityThread.getPackageManager();
- if (pm.checkUidPermission(permission, uid) != PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- final int opCode = AppOpsManager.permissionToOpCode(permission);
- return (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
- opCode, uid, opPackageName) == AppOpsManager.MODE_ALLOWED);
- } catch (RemoteException e) {
- /* ignore - local call */
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return false;
+ int visibility = resolveAccountVisibility(account, packageName,
+ getUserAccounts(UserHandle.getUserId(uid)));
+ return (visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
}
@Override
@@ -3482,21 +3807,28 @@ public class AccountManagerService
private volatile ArrayList<Account> mAccountsWithFeatures = null;
private volatile int mCurrentAccount = 0;
private final int mCallingUid;
+ private final String mPackageName;
- public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
- IAccountManagerResponse response, String type, String[] features, int callingUid) {
+ public GetAccountsByTypeAndFeatureSession(
+ UserAccounts accounts,
+ IAccountManagerResponse response,
+ String type,
+ String[] features,
+ int callingUid,
+ String packageName) {
super(accounts, response, type, false /* expectActivityLaunch */,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */);
mCallingUid = callingUid;
mFeatures = features;
+ mPackageName = packageName;
}
@Override
public void run() throws RemoteException {
synchronized (mAccounts.cacheLock) {
mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
- null);
+ mPackageName, false /* include managed not visible*/);
}
// check whether each account matches the requested features
mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
@@ -3569,7 +3901,6 @@ public class AccountManagerService
}
}
-
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
@@ -3584,6 +3915,7 @@ public class AccountManagerService
@NonNull
public Account[] getAccounts(int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
opPackageName);
if (visibleAccountTypes.isEmpty()) {
@@ -3595,15 +3927,16 @@ public class AccountManagerService
return getAccountsInternal(
accounts,
callingUid,
- null, // packageName
- visibleAccountTypes);
+ opPackageName,
+ visibleAccountTypes,
+ false /* includeUserManagedNotVisible */);
} finally {
restoreCallingIdentity(identityToken);
}
}
/**
- * Returns accounts for all running users.
+ * Returns accounts for all running users, ignores visibility values.
*
* @hide
*/
@@ -3619,7 +3952,11 @@ public class AccountManagerService
return getAccounts(runningUserIds);
}
- /** {@hide} */
+ /**
+ * Returns accounts for all users, ignores visibility values.
+ *
+ * @hide
+ */
@NonNull
public AccountAndUser[] getAllAccounts() {
final List<UserInfo> users = getUserManager().getUsers(true);
@@ -3637,8 +3974,12 @@ public class AccountManagerService
UserAccounts userAccounts = getUserAccounts(userId);
if (userAccounts == null) continue;
synchronized (userAccounts.cacheLock) {
- Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
- Binder.getCallingUid(), null);
+ Account[] accounts = getAccountsFromCacheLocked(
+ userAccounts,
+ null /* type */,
+ Binder.getCallingUid(),
+ null /* packageName */,
+ false /* include managed not visible*/);
for (int a = 0; a < accounts.length; a++) {
runningAccounts.add(new AccountAndUser(accounts[a], userId));
}
@@ -3652,7 +3993,10 @@ public class AccountManagerService
@Override
@NonNull
public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
- return getAccountsAsUser(type, userId, null, -1, opPackageName);
+ int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
+ return getAccountsAsUser(type, userId, opPackageName /* callingPackage */, -1,
+ opPackageName, false /* includeUserManagedNotVisible */);
}
@NonNull
@@ -3661,11 +4005,12 @@ public class AccountManagerService
int userId,
String callingPackage,
int packageUid,
- String opPackageName) {
+ String opPackageName,
+ boolean includeUserManagedNotVisible) {
int callingUid = Binder.getCallingUid();
// Only allow the system process to read accounts of other users
if (userId != UserHandle.getCallingUserId()
- && callingUid != Process.myUid()
+ && callingUid != Process.SYSTEM_UID
&& mContext.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3678,9 +4023,15 @@ public class AccountManagerService
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- // If the original calling app was using the framework account chooser activity, we'll
- // be passed in the original caller's uid here, which is what should be used for filtering.
- if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
+
+ // If the original calling app was using account choosing activity
+ // provided by the framework or authenticator we'll passing in
+ // the original caller's uid here, which is what should be used for filtering.
+ List<String> managedTypes =
+ getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
+ if (packageUid != -1 &&
+ ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || (type != null && managedTypes.contains(type))))) {
callingUid = packageUid;
opPackageName = callingPackage;
}
@@ -3688,7 +4039,7 @@ public class AccountManagerService
opPackageName);
if (visibleAccountTypes.isEmpty()
|| (type != null && !visibleAccountTypes.contains(type))) {
- return new Account[0];
+ return new Account[]{};
} else if (visibleAccountTypes.contains(type)) {
// Prune the list down to just the requested type.
visibleAccountTypes = new ArrayList<>();
@@ -3703,7 +4054,8 @@ public class AccountManagerService
accounts,
callingUid,
callingPackage,
- visibleAccountTypes);
+ visibleAccountTypes,
+ includeUserManagedNotVisible);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -3714,12 +4066,14 @@ public class AccountManagerService
UserAccounts userAccounts,
int callingUid,
String callingPackage,
- List<String> visibleAccountTypes) {
+ List<String> visibleAccountTypes,
+ boolean includeUserManagedNotVisible) {
synchronized (userAccounts.cacheLock) {
ArrayList<Account> visibleAccounts = new ArrayList<>();
for (String visibleType : visibleAccountTypes) {
Account[] accountsForType = getAccountsFromCacheLocked(
- userAccounts, visibleType, callingUid, callingPackage);
+ userAccounts, visibleType, callingUid, callingPackage,
+ includeUserManagedNotVisible);
if (accountsForType != null) {
visibleAccounts.addAll(Arrays.asList(accountsForType));
}
@@ -3810,29 +4164,36 @@ public class AccountManagerService
@NonNull
public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
int callingUid = Binder.getCallingUid();
- if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
+ if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
+ // Don't do opPackageName check - caller is system.
throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
+ callingUid + " with uid=" + uid);
}
return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
- opPackageName);
+ opPackageName, true /* includeUserManagedNotVisible */);
}
@Override
@NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName,
String opPackageName) {
+ int callingUid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
int packageUid = -1;
try {
- packageUid = AppGlobals.getPackageManager().getPackageUid(
- packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
- UserHandle.getCallingUserId());
- } catch (RemoteException re) {
+ packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (NameNotFoundException re) {
Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
return new Account[0];
}
- return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
- packageUid, opPackageName);
+ if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ && !isAccountManagedByCaller(type, callingUid, userId)) {
+ return new Account[0];
+ }
+
+ return getAccountsAsUser(type, userId,
+ packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
}
@Override
@@ -3842,6 +4203,7 @@ public class AccountManagerService
String[] features,
String opPackageName) {
int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAccounts: accountType " + type
+ ", response " + response
@@ -3872,7 +4234,8 @@ public class AccountManagerService
if (features == null || features.length == 0) {
Account[] accounts;
synchronized (userAccounts.cacheLock) {
- accounts = getAccountsFromCacheLocked(userAccounts, type, callingUid, null);
+ accounts = getAccountsFromCacheLocked(
+ userAccounts, type, callingUid, opPackageName, false);
}
Bundle result = new Bundle();
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
@@ -3884,7 +4247,8 @@ public class AccountManagerService
response,
type,
features,
- callingUid).bind();
+ callingUid,
+ opPackageName).bind();
} finally {
restoreCallingIdentity(identityToken);
}
@@ -3903,6 +4267,7 @@ public class AccountManagerService
if (Objects.equals(account.getAccessId(), token)) {
// An app just accessed the account. At this point it knows about
// it and there is not need to hide this account from the app.
+ // Do we need to update account visibility here?
if (!hasAccountAccess(account, null, uid)) {
updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
uid, true);
@@ -4429,7 +4794,7 @@ public class AccountManagerService
userAccounts.accountsDb.dumpDeAccountsTable(fout);
} else {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
- Process.myUid(), null);
+ Process.SYSTEM_UID, null /* packageName */, false);
fout.println("Accounts: " + accounts.length);
for (Account account : accounts) {
fout.println(" " + account);
@@ -4522,6 +4887,24 @@ public class AccountManagerService
}
}
+ private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ for (String perm : permissions) {
+ if (pm.checkPermission(perm, packageName, userId)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return false;
+ }
+
private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
for (String perm : permissions) {
if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
@@ -4556,6 +4939,7 @@ public class AccountManagerService
userPackageManager = mContext.createPackageContextAsUser(
"android", 0, new UserHandle(callingUserId)).getPackageManager();
} catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
@@ -4569,6 +4953,7 @@ public class AccountManagerService
return true;
}
} catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
}
@@ -4623,6 +5008,53 @@ public class AccountManagerService
}
}
+ // Method checks visibility for applications targeing API level below {@link
+ // android.os.Build.VERSION_CODES#O},
+ // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
+ private boolean checkGetAccountsPermission(String packageName, int userId) {
+ return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+ }
+
+ private boolean checkReadContactsPermission(String packageName, int userId) {
+ return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
+ }
+
+ /**
+ * Method checks package uid and signature with Authenticator which manages accountType.
+ *
+ * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
+ * SIGNATURE_CHECK_MISMATCH otherwise.
+ */
+ private int checkPackageSignature(String accountType, int callingUid, int userId) {
+ if (accountType == null) {
+ return SIGNATURE_CHECK_MISMATCH;
+ }
+
+ long identityToken = Binder.clearCallingIdentity();
+ Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
+ try {
+ serviceInfos = mAuthenticatorCache.getAllServices(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ // Check for signature match with Authenticator.
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
+ : serviceInfos) {
+ if (accountType.equals(serviceInfo.type.type)) {
+ if (serviceInfo.uid == callingUid) {
+ return SIGNATURE_CHECK_UID_MATCH;
+ }
+ final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+ if (sigChk == PackageManager.SIGNATURE_MATCH) {
+ return SIGNATURE_CHECK_MATCH;
+ }
+ }
+ }
+ return SIGNATURE_CHECK_MISMATCH;
+ }
+
+ // returns true for applications with the same signature as authenticator.
private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
if (accountType == null) {
return false;
@@ -4633,10 +5065,7 @@ public class AccountManagerService
private List<String> getTypesVisibleToCaller(int callingUid, int userId,
String opPackageName) {
- boolean isPermitted =
- isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
- return getTypesForCaller(callingUid, userId, isPermitted);
+ return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
}
private List<String> getTypesManagedByCaller(int callingUid, int userId) {
@@ -4655,8 +5084,8 @@ public class AccountManagerService
}
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
serviceInfos) {
- final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
- if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
+ if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
+ callingUid) == PackageManager.SIGNATURE_MATCH)) {
managedAccountTypes.add(serviceInfo.type.type);
}
}
@@ -4738,7 +5167,7 @@ public class AccountManagerService
!= 0) {
return true;
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
Log.w(TAG, String.format("Could not find package [%s]", name), e);
}
}
@@ -4929,15 +5358,40 @@ public class AccountManagerService
return newAccountsForType[oldLength];
}
- private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
- int callingUid, String callingPackage) {
+ private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
+ String callingPackage, boolean includeManagedNotVisible) {
+ // filter based on visibility.
+ Map<Account, Integer> firstPass = new HashMap<>();
+ for (Account account : unfiltered) {
+ int visibility = resolveAccountVisibility(account, callingPackage, accounts);
+ if ((visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
+ || (includeManagedNotVisible
+ && (visibility
+ == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
+ firstPass.put(account, visibility);
+ }
+ }
+ Map<Account, Integer> secondPass =
+ filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
+
+ Account[] filtered = new Account[secondPass.size()];
+ filtered = secondPass.keySet().toArray(filtered);
+ return filtered;
+ }
+
+ private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
+ Map<Account, Integer> unfiltered, int callingUid, String callingPackage) {
+ // first part is to filter shared accounts.
+ // unfiltered type check is not necessary.
if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
- || callingUid == Process.myUid()) {
+ || callingUid == Process.SYSTEM_UID) {
return unfiltered;
}
UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
if (user != null && user.isRestricted()) {
- String[] packages = mPackageManager.getPackagesForUid(callingUid);
+ String[] packages =
+ mPackageManager.getPackagesForUid(callingUid);
// If any of the packages is a visible listed package, return the full set,
// otherwise return non-shared accounts only.
// This might be a temporary way to specify a visible list
@@ -4948,9 +5402,10 @@ public class AccountManagerService
return unfiltered;
}
}
- ArrayList<Account> allowed = new ArrayList<>();
Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
- if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
+ if (ArrayUtils.isEmpty(sharedAccounts)) {
+ return unfiltered;
+ }
String requiredAccountType = "";
try {
// If there's an explicit callingPackage specified, check if that package
@@ -4970,11 +5425,14 @@ public class AccountManagerService
}
}
}
- } catch (NameNotFoundException nnfe) {
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
}
- for (Account account : unfiltered) {
+ Map<Account, Integer> filtered = new HashMap<>();
+ for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
+ Account account = entry.getKey();
if (account.type.equals(requiredAccountType)) {
- allowed.add(account);
+ filtered.put(account, entry.getValue());
} else {
boolean found = false;
for (Account shared : sharedAccounts) {
@@ -4984,12 +5442,10 @@ public class AccountManagerService
}
}
if (!found) {
- allowed.add(account);
+ filtered.put(account, entry.getValue());
}
}
}
- Account[] filtered = new Account[allowed.size()];
- allowed.toArray(filtered);
return filtered;
} else {
return unfiltered;
@@ -5001,14 +5457,17 @@ public class AccountManagerService
* that the package is not allowed to access.
*/
protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
- int callingUid, String callingPackage) {
+ int callingUid, String callingPackage, boolean includeManagedNotVisible) {
+ if (callingPackage == null) {
+ callingPackage = getPackageNameForUid(callingUid);
+ }
if (accountType != null) {
final Account[] accounts = userAccounts.accountCache.get(accountType);
if (accounts == null) {
return EMPTY_ACCOUNT_ARRAY;
} else {
- return filterSharedAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
- callingUid, callingPackage);
+ return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
+ callingUid, callingPackage, includeManagedNotVisible);
}
} else {
int totalLength = 0;
@@ -5025,7 +5484,8 @@ public class AccountManagerService
accountsOfType.length);
totalLength += accountsOfType.length;
}
- return filterSharedAccounts(userAccounts, accounts, callingUid, callingPackage);
+ return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
+ includeManagedNotVisible);
}
}
@@ -5253,19 +5713,21 @@ public class AccountManagerService
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
// Make sure the new file doesn't already exist. A dummy file could have been
- // accidentally created in the old location, causing the new one to become corrupted
- // as well.
+ // accidentally created in the old location,
+ // causing the new one to become corrupted as well.
File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
if (oldFile.exists() && !databaseFile.exists()) {
// Check for use directory; create if it doesn't exist, else renameTo will fail
File userDir = Environment.getUserSystemDirectory(userId);
if (!userDir.exists()) {
if (!userDir.mkdirs()) {
- throw new IllegalStateException("User dir cannot be created: " + userDir);
+ throw new IllegalStateException(
+ "User dir cannot be created: " + userDir);
}
}
if (!oldFile.renameTo(databaseFile)) {
- throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
+ throw new IllegalStateException(
+ "User dir cannot be migrated: " + databaseFile);
}
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 5ca74711ddbb..22543cb9e022 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -54,7 +54,7 @@ class AccountsDb implements AutoCloseable {
private static final String DATABASE_NAME = "accounts.db";
private static final int PRE_N_DATABASE_VERSION = 9;
private static final int CE_DATABASE_VERSION = 10;
- private static final int DE_DATABASE_VERSION = 2; // Added visibility support in O.
+ private static final int DE_DATABASE_VERSION = 3; // Added visibility support in O
static final String TABLE_ACCOUNTS = "accounts";
@@ -75,7 +75,7 @@ class AccountsDb implements AutoCloseable {
private static final String TABLE_VISIBILITY = "visibility";
private static final String VISIBILITY_ACCOUNTS_ID = "accounts_id";
- private static final String VISIBILITY_UID = "_uid";
+ private static final String VISIBILITY_PACKAGE = "_package";
private static final String VISIBILITY_VALUE = "value";
private static final String TABLE_GRANTS = "grants";
@@ -252,7 +252,7 @@ class AccountsDb implements AutoCloseable {
createAccountsDeletionTrigger(db);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_DEBUG);
- oldVersion ++;
+ oldVersion++;
}
if (oldVersion != newVersion) {
@@ -355,7 +355,7 @@ class AccountsDb implements AutoCloseable {
boolean deleteAuthtokensByAccountIdAndType(long accountId, String authtokenType) {
SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
return db.delete(CE_TABLE_AUTHTOKENS,
- AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ AUTHTOKENS_ACCOUNTS_ID + "=?" + " AND " + AUTHTOKENS_TYPE + "=?",
new String[]{String.valueOf(accountId), authtokenType}) > 0;
}
@@ -559,9 +559,9 @@ class AccountsDb implements AutoCloseable {
private void createAccountsVisibilityTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_VISIBILITY + " ( "
+ VISIBILITY_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + VISIBILITY_UID + " TEXT NOT NULL, "
+ + VISIBILITY_PACKAGE + " TEXT NOT NULL, "
+ VISIBILITY_VALUE + " INTEGER, "
- + "PRIMARY KEY(" + VISIBILITY_ACCOUNTS_ID + "," + VISIBILITY_UID + "))");
+ + "PRIMARY KEY(" + VISIBILITY_ACCOUNTS_ID + "," + VISIBILITY_PACKAGE + "))");
}
static void createDebugTable(SQLiteDatabase db) {
@@ -591,9 +591,18 @@ class AccountsDb implements AutoCloseable {
Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
if (oldVersion == 1) {
- createAccountsVisibilityTable(db);
- createAccountsDeletionVisibilityCleanupTrigger(db);
- ++oldVersion;
+ createAccountsVisibilityTable(db);
+ createAccountsDeletionVisibilityCleanupTrigger(db);
+ oldVersion = 3; // skip version 2 which had uid based table
+ }
+
+ if (oldVersion == 2) {
+ // Remove uid based table and replace it with packageName based
+ db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "DeleteVisibility");
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_VISIBILITY);
+ createAccountsVisibilityTable(db);
+ createAccountsDeletionVisibilityCleanupTrigger(db);
+ oldVersion++;
}
if (oldVersion != newVersion) {
@@ -890,20 +899,20 @@ class AccountsDb implements AutoCloseable {
new String[] {Integer.toString(uid)}) > 0;
}
- boolean setAccountVisibility(long accountId, int uid, int visibility) {
+ boolean setAccountVisibility(long accountId, String packageName, int visibility) {
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(VISIBILITY_ACCOUNTS_ID, String.valueOf(accountId));
- values.put(VISIBILITY_UID, String.valueOf(uid));
+ values.put(VISIBILITY_PACKAGE, packageName);
values.put(VISIBILITY_VALUE, String.valueOf(visibility));
return (db.replace(TABLE_VISIBILITY, VISIBILITY_VALUE, values) != -1);
}
- Integer findAccountVisibility(Account account, int uid) {
+ Integer findAccountVisibility(Account account, String packageName) {
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
final Cursor cursor = db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_VALUE},
- SELECTION_ACCOUNTS_ID_BY_ACCOUNT + " AND " + VISIBILITY_UID + "=? ",
- new String[] {account.name, account.type, String.valueOf(uid)}, null, null, null);
+ SELECTION_ACCOUNTS_ID_BY_ACCOUNT + " AND " + VISIBILITY_PACKAGE + "=? ",
+ new String[] {account.name, account.type, packageName}, null, null, null);
try {
while (cursor.moveToNext()) {
return cursor.getInt(0);
@@ -914,11 +923,11 @@ class AccountsDb implements AutoCloseable {
return null;
}
- Integer findAccountVisibility(long accountId, int uid) {
+ Integer findAccountVisibility(long accountId, String packageName) {
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
final Cursor cursor = db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_VALUE},
- VISIBILITY_ACCOUNTS_ID + "=? AND " + VISIBILITY_UID + "=? ",
- new String[] {String.valueOf(accountId), String.valueOf(uid)}, null, null, null);
+ VISIBILITY_ACCOUNTS_ID + "=? AND " + VISIBILITY_PACKAGE + "=? ",
+ new String[] {String.valueOf(accountId), packageName}, null, null, null);
try {
while (cursor.moveToNext()) {
return cursor.getInt(0);
@@ -944,17 +953,18 @@ class AccountsDb implements AutoCloseable {
}
/**
- * Returns a map from uid to visibility value.
+ * Returns a map from packageNames to visibility.
*/
- Map<Integer, Integer> findAccountVisibilityForAccountId(long accountId) {
+ Map<String, Integer> findAllVisibilityValuesForAccount(Account account) {
SQLiteDatabase db = mDeDatabase.getReadableDatabase();
- Map<Integer, Integer> result = new HashMap<>();
- final Cursor cursor = db.query(TABLE_VISIBILITY,
- new String[] {VISIBILITY_UID, VISIBILITY_VALUE}, VISIBILITY_ACCOUNTS_ID + "=? ",
- new String[] {String.valueOf(accountId)}, null, null, null);
+ Map<String, Integer> result = new HashMap<>();
+ final Cursor cursor =
+ db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_PACKAGE, VISIBILITY_VALUE},
+ SELECTION_ACCOUNTS_ID_BY_ACCOUNT, new String[] {account.name, account.type},
+ null, null, null);
try {
while (cursor.moveToNext()) {
- result.put(cursor.getInt(0), cursor.getInt(1));
+ result.put(cursor.getString(0), cursor.getInt(1));
}
} finally {
cursor.close();
@@ -962,10 +972,10 @@ class AccountsDb implements AutoCloseable {
return result;
}
- boolean deleteAccountVisibilityForUid(int uid) {
+ boolean deleteAccountVisibilityForPackage(String packageName) {
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
- return db.delete(TABLE_VISIBILITY, VISIBILITY_UID + "=? ",
- new String[] {Integer.toString(uid)}) > 0;
+ return db.delete(TABLE_VISIBILITY, VISIBILITY_PACKAGE + "=? ",
+ new String[] {packageName}) > 0;
}
long insertOrReplaceMetaAuthTypeAndUid(String authenticatorType, int uid) {
@@ -1306,4 +1316,4 @@ class AccountsDb implements AutoCloseable {
return new AccountsDb(deDatabaseHelper, context, preNDatabaseFile);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
new file mode 100644
index 000000000000..84e4ea9d0ee8
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.app.IInstrumentationWatcher;
+import android.app.IUiAutomationConnection;
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+import android.util.PrintWriterPrinter;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class ActiveInstrumentation {
+ final ActivityManagerService mService;
+
+ // Class installed to instrument app
+ ComponentName mClass;
+
+ // All process names that should be instrumented
+ String[] mTargetProcesses;
+
+ // The application being instrumented
+ ApplicationInfo mTargetInfo;
+
+ // Where to save profiling
+ String mProfileFile;
+
+ // Who is waiting
+ IInstrumentationWatcher mWatcher;
+
+ // Connection to use the UI introspection APIs.
+ IUiAutomationConnection mUiAutomationConnection;
+
+ // As given to us
+ Bundle mArguments;
+
+ // Any intermediate results that have been collected.
+ Bundle mCurResults;
+
+ // Copy of instrumentationClass.
+ ComponentName mResultClass;
+
+ // Contains all running processes that have active instrumentation.
+ final ArrayList<ProcessRecord> mRunningProcesses = new ArrayList<>();
+
+ // Set to true when we have told the watcher the instrumentation is finished.
+ boolean mFinished;
+
+ ActiveInstrumentation(ActivityManagerService service) {
+ mService = service;
+ }
+
+ void removeProcess(ProcessRecord proc) {
+ mFinished = true;
+ mRunningProcesses.remove(proc);
+ if (mRunningProcesses.size() == 0) {
+ mService.mActiveInstrumentation.remove(this);
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("ActiveInstrumentation{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(mClass.toShortString());
+ if (mFinished) {
+ sb.append(" FINISHED");
+ }
+ sb.append(" ");
+ sb.append(mRunningProcesses.size());
+ sb.append(" procs");
+ sb.append('}');
+ return sb.toString();
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mClass="); pw.print(mClass);
+ pw.print(" mFinished="); pw.println(mFinished);
+ pw.print(prefix); pw.println("mRunningProcesses:");
+ for (int i=0; i<mRunningProcesses.size(); i++) {
+ pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.println(mRunningProcesses.get(i));
+ }
+ pw.print(prefix); pw.print("mTargetProcesses=");
+ pw.println(Arrays.toString(mTargetProcesses));
+ pw.print(prefix); pw.print("mTargetInfo=");
+ pw.println(mTargetInfo);
+ if (mTargetInfo != null) {
+ mTargetInfo.dump(new PrintWriterPrinter(pw), prefix + " ", 0);
+ }
+ if (mProfileFile != null) {
+ pw.print(prefix); pw.print("mProfileFile="); pw.println(mProfileFile);
+ }
+ if (mWatcher != null) {
+ pw.print(prefix); pw.print("mWatcher="); pw.println(mWatcher);
+ }
+ if (mUiAutomationConnection != null) {
+ pw.print(prefix); pw.print("mUiAutomationConnection=");
+ pw.println(mUiAutomationConnection);
+ }
+ pw.print(prefix); pw.print("mArguments=");
+ pw.println(mArguments);
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5655dc54ded7..041fee2352e3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import java.io.FileDescriptor;
@@ -1391,8 +1393,7 @@ public final class ActiveServices {
}
if (r != null) {
if (mAm.checkComponentPermission(r.permission,
- callingPid, callingUid, r.appInfo.uid, r.exported)
- != PackageManager.PERMISSION_GRANTED) {
+ callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
@@ -2775,16 +2776,15 @@ public final class ActiveServices {
return info;
}
- List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags) {
+ List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags,
+ int callingUid, boolean allowed) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
- final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- if (ActivityManager.checkUidPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- uid) == PackageManager.PERMISSION_GRANTED) {
+ if (ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
+ == PERMISSION_GRANTED) {
int[] users = mAm.mUserController.getUsers();
for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
@@ -2802,16 +2802,20 @@ public final class ActiveServices {
res.add(info);
}
} else {
- int userId = UserHandle.getUserId(uid);
+ int userId = UserHandle.getUserId(callingUid);
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(userId);
for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
ServiceRecord sr = alls.valueAt(i);
- res.add(makeRunningServiceInfoLocked(sr));
+
+ if (allowed || (sr.app != null && sr.app.uid == callingUid)) {
+ res.add(makeRunningServiceInfoLocked(sr));
+ }
}
for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
ServiceRecord r = mRestartingServices.get(i);
- if (r.userId == userId) {
+ if (r.userId == userId
+ && (allowed || (r.app != null && r.app.uid == callingUid))) {
ActivityManager.RunningServiceInfo info =
makeRunningServiceInfoLocked(r);
info.restarting = r.nextRestartTime;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
new file mode 100644
index 000000000000..3c90f93bd18e
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+
+/**
+ * Settings constants that can modify the activity manager's behavior.
+ */
+final class ActivityManagerConstants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_ENFORCE_BG_CHECK = "enforce_bg_check";
+ private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+
+ private static final boolean DEFAULT_ENFORCE_BG_CHECK = SystemProperties.getBoolean(
+ "debug.bgcheck", false);
+ private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+
+ // Enforce background check on apps targeting O?
+ public boolean ENFORCE_BG_CHECK = DEFAULT_ENFORCE_BG_CHECK;
+
+ // Maximum number of cached processes we will allow.
+ public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
+
+ private final ActivityManagerService mService;
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ private int mOverrideMaxCachedProcesses = -1;
+
+ // The maximum number of cached processes we will keep around before killing them.
+ // NOTE: this constant is *only* a control to not let us go too crazy with
+ // keeping around processes on devices with large amounts of RAM. For devices that
+ // are tighter on RAM, the out of memory killer is responsible for killing background
+ // processes as RAM is needed, and we should *never* be relying on this limit to
+ // kill them. Also note that this limit only applies to cached background processes;
+ // we have no limit on the number of service, visible, foreground, or other such
+ // processes and the number of those processes does not count against the cached
+ // process limit.
+ public int CUR_MAX_CACHED_PROCESSES;
+
+ // The maximum number of empty app processes we will let sit around.
+ public int CUR_MAX_EMPTY_PROCESSES;
+
+ // The number of empty apps at which we don't consider it necessary to do
+ // memory trimming.
+ public int CUR_TRIM_EMPTY_PROCESSES;
+
+ // The number of cached at which we don't consider it necessary to do
+ // memory trimming.
+ public int CUR_TRIM_CACHED_PROCESSES;
+
+ public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
+ super(handler);
+ mService = service;
+ updateMaxCachedProcesses();
+ }
+
+ public void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ public void setOverrideMaxCachedProcesses(int value) {
+ mOverrideMaxCachedProcesses = value;
+ updateMaxCachedProcesses();
+ }
+
+ public int getOverrideMaxCachedProcesses() {
+ return mOverrideMaxCachedProcesses;
+ }
+
+ public static int computeEmptyProcessLimit(int totalProcessLimit) {
+ return totalProcessLimit/2;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (mService) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e);
+ }
+
+ ENFORCE_BG_CHECK = mParser.getBoolean(KEY_ENFORCE_BG_CHECK, DEFAULT_ENFORCE_BG_CHECK);
+ MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES,
+ DEFAULT_MAX_CACHED_PROCESSES);
+ updateMaxCachedProcesses();
+ }
+ }
+
+ private void updateMaxCachedProcesses() {
+ CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
+ ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;
+ CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES);
+
+ // Note the trim levels do NOT depend on the override process limit, we want
+ // to consider the same level the point where we do trimming regardless of any
+ // additional enforced limit.
+ final int rawMaxEmptyProcesses = computeEmptyProcessLimit(MAX_CACHED_PROCESSES);
+ CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses/2;
+ CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ + Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
+
+ pw.print(" "); pw.print(KEY_ENFORCE_BG_CHECK); pw.print("=");
+ pw.println(ENFORCE_BG_CHECK);
+
+ pw.print(" "); pw.print(KEY_MAX_CACHED_PROCESSES); pw.print("=");
+ pw.println(MAX_CACHED_PROCESSES);
+
+ pw.println();
+ if (mOverrideMaxCachedProcesses >= 0) {
+ pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
+ }
+ pw.print(" CUR_MAX_CACHED_PROCESSES="); pw.println(CUR_MAX_CACHED_PROCESSES);
+ pw.print(" CUR_MAX_EMPTY_PROCESSES="); pw.println(CUR_MAX_EMPTY_PROCESSES);
+ pw.print(" CUR_TRIM_EMPTY_PROCESSES="); pw.println(CUR_TRIM_EMPTY_PROCESSES);
+ pw.print(" CUR_TRIM_CACHED_PROCESSES="); pw.println(CUR_TRIM_CACHED_PROCESSES);
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e7e07fe8594b..93fb9114beba 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -235,6 +235,7 @@ import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.location.LocationManager;
+import android.metrics.LogMaker;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -312,6 +313,7 @@ import android.view.WindowManager;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.AssistUtils;
@@ -322,6 +324,8 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.IResultReceiver;
@@ -569,7 +573,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
- public IntentFirewall mIntentFirewall;
+ final ArrayList<ActiveInstrumentation> mActiveInstrumentation = new ArrayList<>();
+
+ public final IntentFirewall mIntentFirewall;
// Whether we should show our dialogs (ANR, crash, etc) or just perform their
// default action automatically. Important for devices without direct input
@@ -695,21 +701,16 @@ public class ActivityManagerService extends IActivityManager.Stub
public AssistStructure structure = null;
public AssistContent content = null;
public Bundle receiverExtras;
- public int resultCode;
- public int flags;
public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
- String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _resultCode,
- int _userHandle, int _flags) {
+ String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
activity = _activity;
extras = _extras;
intent = _intent;
hint = _hint;
receiver = _receiver;
receiverExtras = _receiverExtras;
- resultCode = _resultCode;
userHandle = _userHandle;
- flags = _flags;
}
@Override
public void run() {
@@ -761,11 +762,6 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessRecord mHeavyWeightProcess = null;
/**
- * Are we enforcing background restrictions?
- */
- final boolean mEnforceBackgroundCheck;
-
- /**
* Non-persistent app uid whitelist for background restrictions
*/
int[] mBackgroundUidWhitelist = new int[] {
@@ -775,7 +771,7 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Broadcast actions that will always be deliverable to unlaunched/background apps
*/
- final ArraySet<String> mBackgroundLaunchBroadcasts;
+ ArraySet<String> mBackgroundLaunchBroadcasts;
/**
* All of the processes we currently have running organized by pid.
@@ -1427,6 +1423,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ParcelFileDescriptor mProfileFd;
int mSamplingInterval = 0;
boolean mAutoStopProfiler = false;
+ boolean mStreamingOutput = false;
int mProfileType = 0;
final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName;
@@ -1442,7 +1439,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
- static final int CHANGE_PROCESS_STATE = 1<<1;
int changes;
int uid;
int pid;
@@ -1515,9 +1511,6 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
boolean mBooted = false;
- int mProcessLimit = ProcessList.MAX_CACHED_APPS;
- int mProcessLimitOverride = -1;
-
WindowManagerService mWindowManager;
final ActivityThread mSystemThread;
@@ -1631,14 +1624,12 @@ public class ActivityManagerService extends IActivityManager.Stub
int mThumbnailHeight;
float mFullscreenThumbnailScale;
- /** The aspect ratio bounds of the PIP. */
- float mMinPipAspectRatio;
- float mMaxPipAspectRatio;
-
final ServiceThread mHandlerThread;
final MainHandler mHandler;
final UiHandler mUiHandler;
+ final ActivityManagerConstants mConstants;
+
PackageManagerInternal mPackageManagerInt;
// VoiceInteraction session ID that changes for each new request except when
@@ -2620,13 +2611,11 @@ public class ActivityManagerService extends IActivityManager.Stub
mPermissionReviewRequired = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_permissionReviewRequired);
- mEnforceBackgroundCheck = SystemProperties.getBoolean("debug.bgcheck", false);
- mBackgroundLaunchBroadcasts = SystemConfig.getInstance().getAllowImplicitBroadcasts();
if (DEBUG_BACKGROUND_CHECK) {
- Slog.d(TAG, "Enforcing O+ bg restrictions: " + mEnforceBackgroundCheck);
+ Slog.d(TAG, "Enforcing O+ bg restrictions: " + mConstants.ENFORCE_BG_CHECK);
StringBuilder sb = new StringBuilder(200);
sb.append(" ");
- for (String a : mBackgroundLaunchBroadcasts) {
+ for (String a : getBackgroundLaunchBroadcasts()) {
sb.append(' '); sb.append(a);
}
Slog.d(TAG, "Background implicit broadcasts:");
@@ -2639,6 +2628,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mHandler = new MainHandler(mHandlerThread.getLooper());
mUiHandler = new UiHandler();
+ mConstants = new ActivityManagerConstants(this, mHandler);
+
/* static; one-time init here */
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
@@ -2788,6 +2779,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mVoiceWakeLock.setReferenceCounted(false);
}
+ private ArraySet<String> getBackgroundLaunchBroadcasts() {
+ if (mBackgroundLaunchBroadcasts == null) {
+ mBackgroundLaunchBroadcasts = SystemConfig.getInstance().getAllowImplicitBroadcasts();
+ }
+ return mBackgroundLaunchBroadcasts;
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -3712,7 +3710,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
@@ -3922,7 +3921,7 @@ public class ActivityManagerService extends IActivityManager.Stub
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
- if (app == null || app.instrumentationClass == null) {
+ if (app == null || app.instr == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
}
@@ -4162,12 +4161,6 @@ public class ActivityManagerService extends IActivityManager.Stub
observer.onForegroundActivitiesChanged(item.pid, item.uid,
item.foregroundActivities);
}
- if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "PROCSTATE CHANGED pid=" + item.pid + " uid=" + item.uid
- + ": " + item.processState);
- observer.onProcessStateChanged(item.pid, item.uid, item.processState);
- }
}
} catch (RemoteException e) {
}
@@ -5094,9 +5087,9 @@ public class ActivityManagerService extends IActivityManager.Stub
app.activities.clear();
- if (app.instrumentationClass != null) {
+ if (app.instr != null) {
Slog.w(TAG, "Crash of app " + app.processName
- + " running instrumentation " + app.instrumentationClass);
+ + " running instrumentation " + app.instr.mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
@@ -5229,7 +5222,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- boolean doLowMem = app.instrumentationClass == null;
+ boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
@@ -6385,7 +6378,7 @@ public class ActivityManagerService extends IActivityManager.Stub
handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
- addAppLocked(app.info, false, null /* ABI override */);
+ addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
@@ -6561,16 +6554,18 @@ public class ActivityManagerService extends IActivityManager.Stub
mWaitForDebugger = mOrigWaitForDebugger;
}
}
- String profileFile = app.instrumentationProfileFile;
+ String profileFile = app.instr != null ? app.instr.mProfileFile : null;
ParcelFileDescriptor profileFd = null;
int samplingInterval = 0;
boolean profileAutoStop = false;
+ boolean profileStreamingOutput = false;
if (mProfileApp != null && mProfileApp.equals(processName)) {
mProfileProc = app;
profileFile = mProfileFile;
profileFd = mProfileFd;
samplingInterval = mSamplingInterval;
profileAutoStop = mAutoStopProfiler;
+ profileStreamingOutput = mStreamingOutput;
}
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
@@ -6587,20 +6582,20 @@ public class ActivityManagerService extends IActivityManager.Stub
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
- if (app.instrumentationClass != null) {
- notifyPackageUse(app.instrumentationClass.getPackageName(),
+ if (app.instr != null) {
+ notifyPackageUse(app.instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config " + getGlobalConfiguration());
- ApplicationInfo appInfo = app.instrumentationInfo != null
- ? app.instrumentationInfo : app.info;
+ ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) {
profileFd = profileFd.dup();
}
ProfilerInfo profilerInfo = profileFile == null ? null
- : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+ : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop,
+ profileStreamingOutput);
// We deprecated Build.SERIAL and only apps that target pre NMR1
// SDK can see it. Since access to the serial is now behind a
@@ -6613,16 +6608,57 @@ public class ActivityManagerService extends IActivityManager.Stub
.getSerial();
// }
+ // Check if this is a secondary process that should be incorporated into some
+ // currently active instrumentation. (Note we do this AFTER all of the profiling
+ // stuff above because profiling can currently happen only in the primary
+ // instrumentation process.)
+ if (mActiveInstrumentation.size() > 0 && app.instr == null) {
+ for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
+ ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
+ if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
+ if (aInstr.mTargetProcesses.length == 0) {
+ // This is the wildcard mode, where every process brought up for
+ // the target instrumentation should be included.
+ if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
+ app.instr = aInstr;
+ aInstr.mRunningProcesses.add(app);
+ }
+ } else {
+ for (String proc : aInstr.mTargetProcesses) {
+ if (proc.equals(app.processName)) {
+ app.instr = aInstr;
+ aInstr.mRunningProcesses.add(app);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
- thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
- profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
- app.instrumentationUiAutomationConnection, testMode,
- mBinderTransactionTrackingEnabled, enableTrackAllocation,
- isRestrictedBackupMode || !normalMode, app.persistent,
- new Configuration(getGlobalConfiguration()), app.compat,
- getCommonServicesLocked(app.isolated),
- mCoreSettingsObserver.getCoreSettingsLocked(),
- buildSerial);
+ if (app.instr != null) {
+ thread.bindApplication(processName, appInfo, providers,
+ app.instr.mClass,
+ profilerInfo, app.instr.mArguments,
+ app.instr.mWatcher,
+ app.instr.mUiAutomationConnection, testMode,
+ mBinderTransactionTrackingEnabled, enableTrackAllocation,
+ isRestrictedBackupMode || !normalMode, app.persistent,
+ new Configuration(getGlobalConfiguration()), app.compat,
+ getCommonServicesLocked(app.isolated),
+ mCoreSettingsObserver.getCoreSettingsLocked(),
+ buildSerial);
+ } else {
+ thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
+ null, null, null, testMode,
+ mBinderTransactionTrackingEnabled, enableTrackAllocation,
+ isRestrictedBackupMode || !normalMode, app.persistent,
+ new Configuration(getGlobalConfiguration()), app.compat,
+ getCommonServicesLocked(app.isolated),
+ mCoreSettingsObserver.getCoreSettingsLocked(),
+ buildSerial);
+ }
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
@@ -6731,7 +6767,8 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
ActivityRecord r =
- mStackSupervisor.activityIdleInternalLocked(token, false, config);
+ mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
+ false /* processPausingActivities */, config);
if (stopProfiling) {
if ((mProfileProc == r.app) && (mProfileFd != null)) {
try {
@@ -7276,9 +7313,6 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Whitelists {@code targetUid} to temporarily bypass Power Save mode.
- *
- * <p>{@code callerUid} must be allowed to request such whitelist by calling
- * {@link #addTempPowerSaveWhitelistGrantorUid(int)}.
*/
void tempWhitelistAppForPowerSave(int callerPid, int callerUid, int targetUid, long duration) {
if (DEBUG_WHITELISTS) {
@@ -7470,8 +7504,7 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
synchronized (this) {
- mProcessLimit = max < 0 ? ProcessList.MAX_CACHED_APPS : max;
- mProcessLimitOverride = max;
+ mConstants.setOverrideMaxCachedProcesses(max);
}
trimApplications();
}
@@ -7479,7 +7512,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int getProcessLimit() {
synchronized (this) {
- return mProcessLimitOverride;
+ return mConstants.getOverrideMaxCachedProcesses();
}
}
@@ -7615,7 +7648,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// Activity supports picture-in-picture, now check that we can enter PiP at this
// point, if it is
- if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode")) {
+ if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
+ false /* noThrow */)) {
return false;
}
@@ -7624,13 +7658,17 @@ public class ActivityManagerService extends IActivityManager.Stub
r.pictureInPictureArgs.copyOnlySet(args);
final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
- final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
- ? mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
- aspectRatio)
- : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY);
+ final Rect bounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
+ aspectRatio);
mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
bounds, true /* moveHomeStackToFront */);
- mWindowManager.setPictureInPictureActions(actions);
+ final ActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
+ stack.setPictureInPictureAspectRatio(aspectRatio);
+ stack.setPictureInPictureActions(actions);
+
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED,
+ r.supportsPictureInPictureWhilePausing);
+ logPictureInPictureArgs(args);
};
if (isKeyguardLocked()) {
@@ -7678,21 +7716,29 @@ public class ActivityManagerService extends IActivityManager.Stub
// Only update the saved args from the args that are set
r.pictureInPictureArgs.copyOnlySet(args);
- if (r.getStack().getStackId() == PINNED_STACK_ID) {
+ final ActivityStack stack = r.getStack();
+ if (stack.getStackId() == PINNED_STACK_ID) {
// If the activity is already in picture-in-picture, update the pinned stack now
- mWindowManager.setPictureInPictureAspectRatio(
- r.pictureInPictureArgs.getAspectRatio());
- mWindowManager.setPictureInPictureActions(
- r.pictureInPictureArgs.getActions());
+ stack.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio());
+ stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
+ logPictureInPictureArgs(args);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
- return mMinPipAspectRatio <= aspectRatio && aspectRatio <= mMaxPipAspectRatio;
+ private void logPictureInPictureArgs(PictureInPictureArgs args) {
+ if (args.hasSetActions()) {
+ MetricsLogger.histogram(mContext, "tron_varz_picture_in_picture_actions_count",
+ args.getActions().size());
+ }
+ if (args.hasSetAspectRatio()) {
+ LogMaker lm = new LogMaker(MetricsEvent.ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED);
+ lm.addTaggedData(MetricsEvent.PICTURE_IN_PICTURE_ASPECT_RATIO, args.getAspectRatio());
+ MetricsLogger.action(lm);
+ }
}
/**
@@ -7725,10 +7771,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (args.hasSetAspectRatio()
- && !isValidPictureInPictureAspectRatio(args.getAspectRatio())) {
+ && !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
+ args.getAspectRatio())) {
+ final float minAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+ final float maxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
throw new IllegalArgumentException(String.format(caller
+ ": Aspect ratio is too extreme (must be between %f and %f).",
- mMinPipAspectRatio, mMaxPipAspectRatio));
+ minAspectRatio, maxAspectRatio));
}
if (args.hasSetActions()
@@ -8036,7 +8087,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Unified app-op and target sdk check
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
- if (mEnforceBackgroundCheck && packageTargetSdk >= Build.VERSION_CODES.O) {
+ if (mConstants.ENFORCE_BG_CHECK && packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
@@ -9341,7 +9392,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (tr.mBounds != null) {
rti.bounds = new Rect(tr.mBounds);
}
- rti.isDockable = tr.canGoInDockedStack();
+ rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreen();
rti.resizeMode = tr.mResizeMode;
ActivityRecord base = null;
@@ -10221,7 +10272,9 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
if (animate) {
if (stackId == PINNED_STACK_ID) {
- mWindowManager.animateResizePinnedStack(bounds, animationDuration);
+ final ActivityStack pinnedStack =
+ mStackSupervisor.getStack(PINNED_STACK_ID);
+ pinnedStack.animateResizePinnedStack(bounds, animationDuration);
} else {
throw new IllegalArgumentException("Stack: " + stackId
+ " doesn't support animated resize.");
@@ -11559,6 +11612,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mSystemThread.installSystemProviders(providers);
}
+ mConstants.start(mContext.getContentResolver());
mCoreSettingsObserver = new CoreSettingsObserver(this);
mFontScaleSettingObserver = new FontScaleSettingObserver();
@@ -11578,7 +11632,7 @@ public class ActivityManagerService extends IActivityManager.Stub
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
- addAppLocked(app, false, null /* ABI override */);
+ addAppLocked(app, null, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
@@ -11766,17 +11820,18 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
ProcessRecord app;
if (!isolated) {
- app = getProcessRecordLocked(info.processName, info.uid, true);
+ app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
+ info.uid, true);
} else {
app = null;
}
if (app == null) {
- app = newProcessRecordLocked(info, null, isolated, 0);
+ app = newProcessRecordLocked(info, customProcess, isolated, 0);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
@@ -11797,7 +11852,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
- startProcessLocked(app, "added application", app.processName, abiOverride,
+ startProcessLocked(app, "added application",
+ customProcess != null ? customProcess : app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}
@@ -12044,14 +12100,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final long ident = Binder.clearCallingIdentity();
try {
if (mUserController.shouldConfirmCredentials(userId)) {
- final int currentUserId = mUserController.getCurrentUserIdLocked();
- if (!mKeyguardController.isKeyguardLocked()) {
- // If the device is not locked, we will prompt for credentials immediately.
- mStackSupervisor.lockAllProfileTasks(userId);
- } else {
+ if (mKeyguardController.isKeyguardLocked()) {
// Showing launcher to avoid user entering credential twice.
+ final int currentUserId = mUserController.getCurrentUserIdLocked();
startHomeActivityLocked(currentUserId, "notifyLockedProfile");
}
+ mStackSupervisor.lockAllProfileTasks(userId);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12060,12 +12114,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void startConfirmDeviceCredentialIntent(Intent intent) {
+ public void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- mActivityStarter.startConfirmCredentialIntent(intent);
+ mActivityStarter.startConfirmCredentialIntent(intent, options);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -12204,6 +12258,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProfileFd = profilerInfo.profileFd;
mSamplingInterval = profilerInfo.samplingInterval;
mAutoStopProfiler = profilerInfo.autoStopProfiler;
+ mStreamingOutput = profilerInfo.streamingOutput;
mProfileType = 0;
}
}
@@ -12253,11 +12308,11 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
synchronized (mPidsSelfLocked) {
final int callingPid = Binder.getCallingPid();
- ProcessRecord precessRecord = mPidsSelfLocked.get(callingPid);
- if (precessRecord == null) {
+ ProcessRecord proc = mPidsSelfLocked.get(callingPid);
+ if (proc == null) {
throw new SecurityException("Unknown process: " + callingPid);
}
- if (precessRecord.instrumentationUiAutomationConnection == null) {
+ if (proc.instr == null || proc.instr.mUiAutomationConnection == null) {
throw new SecurityException("Only an instrumentation process "
+ "with a UiAutomation can call setUserIsMonkey");
}
@@ -12314,7 +12369,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
- if (r != null && (r.instrumentationClass != null || r.usingWrapper)) {
+ if (r != null && (r.instr != null || r.usingWrapper)) {
return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
}
return KEY_DISPATCHING_TIMEOUT;
@@ -12375,7 +12430,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- if (proc.instrumentationClass != null) {
+ if (proc.instr != null) {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
@@ -12397,8 +12452,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public Bundle getAssistContextExtras(int requestType) {
PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
- null, 0, null, true /* focused */, true /* newSessionId */,
- UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
+ null, null, true /* focused */, true /* newSessionId */,
+ UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
if (pae == null) {
return null;
}
@@ -12462,44 +12517,31 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
- Bundle receiverExtras,
- IBinder activityToken, boolean focused, boolean newSessionId) {
+ Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
- 0, activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
- PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
+ activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
+ PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
}
@Override
public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
- int resultCode, IBinder activityToken, int flags) {
- final boolean forFill = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
- final boolean forSave = (flags & View.AUTO_FILL_FLAG_TYPE_SAVE) != 0;
- if ((forFill && forSave) || (!forFill) && !(forSave)) {
- // There can be only one!
- Slog.w(TAG, "requestAutoFillData(): invalid flags (" + flags + ")");
- return false;
- }
-
+ IBinder activityToken) {
// NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
// rely on the flags to decide whether the handleRequestAssistContextExtras() is for
// auto-fill, but it's safer to explicitly use new AutoFill types, in case the Assist
// requests use flags in the future as well (since their flags value might collide with the
// auto-fill flag values).
- final int type = forFill?
- ActivityManager.ASSIST_CONTEXT_AUTO_FILL :
- ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
-
- return enqueueAssistContext(type, null, null, receiver, receiverExtras, resultCode,
- activityToken, true, true, UserHandle.getCallingUserId(), null,
- PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
+ return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTO_FILL, null, null,
+ receiver, receiverExtras, activityToken, true, true, UserHandle.getCallingUserId(),
+ null, PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT) != null;
}
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
- IResultReceiver receiver, Bundle receiverExtras, int resultCode, IBinder activityToken,
- boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
- int flags) {
+ IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
+ boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
+
synchronized (this) {
ActivityRecord activity = getFocusedStack().topActivity();
if (activity == null) {
@@ -12535,15 +12577,17 @@ public class ActivityManagerService extends IActivityManager.Stub
}
extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+
pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
- resultCode, userHandle, flags);
+ userHandle);
+
// Increment the sessionId if necessary
if (newSessionId) {
mViSessionId++;
}
try {
- activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
- requestType, mViSessionId, flags);
+ activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
+ mViSessionId);
mPendingAssistExtras.add(pae);
mUiHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
@@ -12619,18 +12663,11 @@ public class ActivityManagerService extends IActivityManager.Stub
sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
pae.receiverExtras);
- if (pae.flags > 0) {
- sendBundle.putInt(VoiceInteractionSession.KEY_FLAGS, pae.flags);
- }
- IBinder cb = extras.getBinder(AutoFillService.KEY_CALLBACK);
- if (cb != null) {
- sendBundle.putBinder(AutoFillService.KEY_CALLBACK, cb);
- }
}
}
if (sendReceiver != null) {
try {
- sendReceiver.send(pae.resultCode, sendBundle);
+ sendReceiver.send(0, sendBundle);
} catch (RemoteException e) {
}
return;
@@ -12655,9 +12692,9 @@ public class ActivityManagerService extends IActivityManager.Stub
public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
Bundle args) {
- return enqueueAssistContext(requestType, intent, hint, null, null, 0, null,
+ return enqueueAssistContext(requestType, intent, hint, null, null, null,
true /* focused */, true /* newSessionId */, userHandle, args,
- PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
+ PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
}
public void registerProcessObserver(IProcessObserver observer) {
@@ -13404,13 +13441,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (supportsMultiWindow || forceResizable) {
mSupportsMultiWindow = true;
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
- mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
} else {
mSupportsMultiWindow = false;
mSupportsFreeformWindowManagement = false;
- mSupportsPictureInPicture = false;
}
mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
+ mSupportsPictureInPicture = supportsPictureInPicture;
mWindowManager.setForceResizableTasks(mForceResizableActivities);
mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
// This happens before any activities are started, so we can change global configuration
@@ -13426,10 +13462,6 @@ public class ActivityManagerService extends IActivityManager.Stub
com.android.internal.R.dimen.thumbnail_width);
mThumbnailHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.thumbnail_height);
- mMinPipAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
- mMaxPipAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
com.android.internal.R.string.config_appsNotReportingCrashes));
mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -14496,6 +14528,10 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
dumpAssociationsLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
}
+ } else if ("settings".equals(cmd)) {
+ synchronized (this) {
+ mConstants.dump(pw);
+ }
} else if ("services".equals(cmd) || "s".equals(cmd)) {
if (dumpClient) {
ActiveServices.ServiceDumper dumper;
@@ -14536,6 +14572,11 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if (dumpClient) {
ActiveServices.ServiceDumper sdumper;
synchronized (this) {
+ mConstants.dump(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
@@ -14594,6 +14635,11 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
synchronized (this) {
+ mConstants.dump(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
@@ -14888,8 +14934,31 @@ public class ActivityManagerService extends IActivityManager.Stub
printed = true;
needSep = true;
}
- pw.println(String.format("%sIsolated #%2d: %s",
- " ", i, r.toString()));
+ pw.print(" Isolated #"); pw.print(i); pw.print(": ");
+ pw.println(r);
+ }
+ }
+
+ if (mActiveInstrumentation.size() > 0) {
+ boolean printed = false;
+ for (int i=0; i<mActiveInstrumentation.size(); i++) {
+ ActiveInstrumentation ai = mActiveInstrumentation.get(i);
+ if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
+ && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Active instrumentation:");
+ printedAnything = true;
+ printed = true;
+ needSep = true;
+ }
+ pw.print(" Instrumentation #"); pw.print(i); pw.print(": ");
+ pw.println(ai);
+ ai.dump(pw, " ");
}
}
@@ -15169,7 +15238,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
pw.println(" mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler="
- + mAutoStopProfiler);
+ + mAutoStopProfiler + " mStreamingOutput=" + mStreamingOutput);
pw.println(" mProfileType=" + mProfileType);
}
}
@@ -17387,7 +17456,11 @@ public class ActivityManagerService extends IActivityManager.Stub
int flags) {
enforceNotIsolatedCaller("getServices");
synchronized (this) {
- return mServices.getRunningServiceInfoLocked(maxNum, flags);
+ final int callingUid = Binder.getCallingUid();
+ final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+ callingUid);
+
+ return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid, allowed);
}
}
@@ -17756,6 +17829,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = mBackupTarget.app;
updateOomAdjLocked(proc);
+ proc.inFullBackup = false;
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
@@ -18295,7 +18369,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (action != null) {
- if (mBackgroundLaunchBroadcasts.contains(action)) {
+ if (getBackgroundLaunchBroadcasts().contains(action)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
}
@@ -18635,7 +18709,7 @@ public class ActivityManagerService extends IActivityManager.Stub
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false, false /*visibleToEphemeral*/,
- false /*isEphemeral*/, users[i]);
+ false /*isInstant*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
@@ -18645,7 +18719,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, false /*visibleToEphemeral*/,
- false /*isEphemeral*/, userId);
+ false /*isInstant*/, userId);
}
}
@@ -19032,18 +19106,35 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException(msg);
}
+ ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
+ activeInstr.mClass = className;
+ String defProcess = ai.processName;;
+ if (ii.targetProcess == null) {
+ activeInstr.mTargetProcesses = new String[]{ai.processName};
+ } else if (ii.targetProcess.equals("*")) {
+ activeInstr.mTargetProcesses = new String[0];
+ } else {
+ activeInstr.mTargetProcesses = ii.targetProcess.split(",");
+ defProcess = activeInstr.mTargetProcesses[0];
+ }
+ activeInstr.mTargetInfo = ai;
+ activeInstr.mProfileFile = profileFile;
+ activeInstr.mArguments = arguments;
+ activeInstr.mWatcher = watcher;
+ activeInstr.mUiAutomationConnection = uiAutomationConnection;
+ activeInstr.mResultClass = className;
+
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");
- ProcessRecord app = addAppLocked(ai, false, abiOverride);
- app.instrumentationClass = className;
- app.instrumentationInfo = ai;
- app.instrumentationProfileFile = profileFile;
- app.instrumentationArguments = arguments;
- app.instrumentationWatcher = watcher;
- app.instrumentationUiAutomationConnection = uiAutomationConnection;
- app.instrumentationResultClass = className;
+ ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+ app.instr = activeInstr;
+ activeInstr.mFinished = false;
+ activeInstr.mRunningProcesses.add(app);
+ if (!mActiveInstrumentation.contains(activeInstr)) {
+ mActiveInstrumentation.add(activeInstr);
+ }
Binder.restoreCallingIdentity(origId);
}
@@ -19070,24 +19161,70 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ void addInstrumentationResultsLocked(ProcessRecord app, Bundle results) {
+ if (app.instr == null) {
+ Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+ return;
+ }
+
+ if (!app.instr.mFinished && results != null) {
+ if (app.instr.mCurResults == null) {
+ app.instr.mCurResults = new Bundle(results);
+ } else {
+ app.instr.mCurResults.putAll(results);
+ }
+ }
+ }
+
+ public void addInstrumentationResults(IApplicationThread target, Bundle results) {
+ int userId = UserHandle.getCallingUserId();
+ // Refuse possible leaked file descriptors
+ if (results != null && results.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ synchronized(this) {
+ ProcessRecord app = getRecordForAppLocked(target);
+ if (app == null) {
+ Slog.w(TAG, "addInstrumentationResults: no app for " + target);
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ addInstrumentationResultsLocked(app, results);
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
- if (app.instrumentationWatcher != null) {
- mInstrumentationReporter.reportFinished(app.instrumentationWatcher,
- app.instrumentationClass, resultCode, results);
+ if (app.instr == null) {
+ Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+ return;
}
- // Can't call out of the system process with a lock held, so post a message.
- if (app.instrumentationUiAutomationConnection != null) {
- mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
- app.instrumentationUiAutomationConnection).sendToTarget();
+ if (!app.instr.mFinished) {
+ if (app.instr.mWatcher != null) {
+ Bundle finalResults = app.instr.mCurResults;
+ if (finalResults != null) {
+ if (app.instr.mCurResults != null && results != null) {
+ finalResults.putAll(results);
+ }
+ } else {
+ finalResults = results;
+ }
+ mInstrumentationReporter.reportFinished(app.instr.mWatcher,
+ app.instr.mClass, resultCode, finalResults);
+ }
+
+ // Can't call out of the system process with a lock held, so post a message.
+ if (app.instr.mUiAutomationConnection != null) {
+ mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+ app.instr.mUiAutomationConnection).sendToTarget();
+ }
+ app.instr.mFinished = true;
}
- app.instrumentationWatcher = null;
- app.instrumentationUiAutomationConnection = null;
- app.instrumentationClass = null;
- app.instrumentationInfo = null;
- app.instrumentationProfileFile = null;
- app.instrumentationArguments = null;
+ app.instr.removeProcess(app);
+ app.instr = null;
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
"finished inst");
@@ -19594,10 +19731,15 @@ public class ActivityManagerService extends IActivityManager.Stub
/** Helper method that requests bounds from WM and applies them to stack. */
private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
- final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+ final Rect newStackBounds = new Rect();
+ final Rect newTempTaskBounds = new Rect();
+ mStackSupervisor.getStack(stackId).getBoundsForNewConfiguration(newStackBounds,
+ newTempTaskBounds);
mStackSupervisor.resizeStackLocked(
- stackId, newBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+ stackId, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
+ !newTempTaskBounds.isEmpty() ? newTempTaskBounds : null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, false /* preserveWindows */,
+ false /* allowResizeInDockedMode */, deferResume);
}
/**
@@ -19865,7 +20007,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
- } else if (app.instrumentationClass != null) {
+ } else if (app.instr != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -20997,7 +21139,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.repProcState != app.curProcState) {
app.repProcState = app.curProcState;
- changes |= ProcessChangeItem.CHANGE_PROCESS_STATE;
if (app.thread != null) {
try {
if (false) {
@@ -21118,12 +21259,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mPendingProcessChanges.add(item);
}
item.changes |= changes;
- item.processState = app.repProcState;
item.foregroundActivities = app.repForegroundActivities;
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Item " + Integer.toHexString(System.identityHashCode(item))
+ " " + app.toShortString() + ": changes=" + item.changes
- + " procState=" + item.processState
+ " foreground=" + item.foregroundActivities
+ " type=" + app.adjType + " source=" + app.adjSource
+ " target=" + app.adjTarget);
@@ -21394,17 +21533,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
- final int emptyProcessLimit;
- final int cachedProcessLimit;
- if (mProcessLimit <= 0) {
- emptyProcessLimit = cachedProcessLimit = 0;
- } else if (mProcessLimit == 1) {
- emptyProcessLimit = 1;
- cachedProcessLimit = 0;
- } else {
- emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
- cachedProcessLimit = mProcessLimit - emptyProcessLimit;
- }
+ final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
+ final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;
// Let's determine how many processes we have running vs.
// how many slots we have for background processes; we may want
@@ -21512,7 +21642,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- if (numEmpty > ProcessList.TRIM_EMPTY_APPS
+ if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.lastActivityTime < oldTime) {
app.kill("empty for "
+ ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
@@ -21541,7 +21671,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Keeping this process, update its uid.
final UidRecord uidRec = app.uidRecord;
if (uidRec != null) {
- uidRec.ephemeral = app.info.isEphemeralApp();
+ uidRec.ephemeral = app.info.isInstantApp();
if (uidRec.curProcState > app.curProcState) {
uidRec.curProcState = app.curProcState;
}
@@ -21565,8 +21695,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// memory they want.
final int numCachedAndEmpty = numCached + numEmpty;
int memFactor;
- if (numCached <= ProcessList.TRIM_CACHED_APPS
- && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
+ if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
+ && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
@@ -21966,7 +22096,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mRemovedProcesses.remove(i);
if (app.persistent) {
- addAppLocked(app.info, false, null /* ABI override */);
+ addAppLocked(app.info, null, false, null /* ABI override */);
}
}
}
@@ -22026,6 +22156,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProfileFile = null;
mProfileType = 0;
mAutoStopProfiler = false;
+ mStreamingOutput = false;
mSamplingInterval = 0;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 1a2a31b5885c..a06fa1b8dcfe 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -115,6 +115,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
private String mProfileFile;
private int mSamplingInterval;
private boolean mAutoStop;
+ private boolean mStreaming; // Streaming the profiling output to a file.
private int mDisplayId;
private int mStackId;
@@ -256,6 +257,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
mProfileFile = null;
mSamplingInterval = 0;
mAutoStop = false;
+ mStreaming = false;
mUserId = defUser;
mDisplayId = INVALID_DISPLAY;
mStackId = INVALID_STACK_ID;
@@ -277,6 +279,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
mAutoStop = false;
} else if (opt.equals("--sampling")) {
mSamplingInterval = Integer.parseInt(getNextArgRequired());
+ } else if (opt.equals("--streaming")) {
+ mStreaming = true;
} else if (opt.equals("-R")) {
mRepeat = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("-S")) {
@@ -354,7 +358,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
if (fd == null) {
return 1;
}
- profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop);
+ profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
+ mStreaming);
}
pw.println("Starting: " + intent);
@@ -659,6 +664,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
int userId = UserHandle.USER_CURRENT;
int profileType = 0;
mSamplingInterval = 0;
+ mStreaming = false;
String process = null;
@@ -672,6 +678,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
userId = UserHandle.parseUserArg(getNextArgRequired());
} else if (opt.equals("--wall")) {
wall = true;
+ } else if (opt.equals("--streaming")) {
+ mStreaming = true;
} else if (opt.equals("--sampling")) {
mSamplingInterval = Integer.parseInt(getNextArgRequired());
} else {
@@ -716,7 +724,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
if (fd == null) {
return -1;
}
- profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming);
}
try {
@@ -2035,7 +2043,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
mInterface.stopLockTaskMode();
} else {
int taskId = Integer.parseInt(taskIdStr);
- mInterface.startLockTaskModeById(taskId);
+ mInterface.startSystemLockTaskMode(taskId);
}
pw.println("Activity manager is " + (mInterface.isInLockTaskMode() ? "" : "not ") +
"in lockTaskMode");
@@ -2406,6 +2414,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" provider [COMP_SPEC]: provider client-side state");
pw.println(" s[ervices] [COMP_SPEC ...]: service state");
pw.println(" as[sociations]: tracked app associations");
+ pw.println(" settings: currently applied config settings");
pw.println(" service [COMP_SPEC]: service client-side state");
pw.println(" package [PACKAGE_NAME]: all state related to given package");
pw.println(" all: dump all activities");
@@ -2424,7 +2433,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" help");
pw.println(" Print this help text.");
pw.println(" start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]");
- pw.println(" [--sampling INTERVAL] [-R COUNT] [-S]");
+ pw.println(" [--sampling INTERVAL] [--streaming] [-R COUNT] [-S]");
pw.println(" [--track-allocation] [--user <USER_ID> | current] <INTENT>");
pw.println(" Start an Activity. Options are:");
pw.println(" -D: enable debugging");
@@ -2433,6 +2442,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --start-profiler <FILE>: start profiler and send results to <FILE>");
pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
pw.println(" between samples (use with --start-profiler)");
+ pw.println(" --streaming: stream the profiling output to the specified file");
+ pw.println(" (use with --start-profiler)");
pw.println(" -P <FILE>: like above, but profiling stops when app goes idle");
pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,");
pw.println(" the top activity will be finished.");
@@ -2479,11 +2490,14 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" stop: stop tracing IPC transactions and dump the results to file.");
pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to.");
pw.println(" profile [start|stop] [--user <USER_ID> current] [--sampling INTERVAL]");
- pw.println(" <PROCESS> <FILE>");
+ pw.println(" [--streaming] <PROCESS> <FILE>");
pw.println(" Start and stop profiler on a process. The given <PROCESS> argument");
pw.println(" may be either a process name or pid. Options are:");
pw.println(" --user <USER_ID> | current: When supplying a process name,");
pw.println(" specify user of process to profile; uses current user if not specified.");
+ pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
+ pw.println(" between samples");
+ pw.println(" --streaming: stream the profiling output to the specified file");
pw.println(" dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>");
pw.println(" Dump the heap of a process. The given <PROCESS> argument may");
pw.println(" be either a process name or pid. Options are:");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3bd44f5cd3c9..58c17ebbeafe 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
@@ -29,6 +30,7 @@ import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
@@ -36,13 +38,17 @@ import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
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 android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
+import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -66,7 +72,6 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import android.annotation.NonNull;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
-import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.PictureInPictureArgs;
import android.app.ResultInfo;
@@ -78,7 +83,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
-import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -454,6 +459,7 @@ final class ActivityRecord implements AppWindowContainerListener {
}
if (info != null) {
pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+ pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());
}
pw.println(prefix + "supportsPictureInPictureWhilePausing: "
+ supportsPictureInPictureWhilePausing);
@@ -731,7 +737,6 @@ final class ActivityRecord implements AppWindowContainerListener {
if (mWindowContainerController != null) {
throw new IllegalArgumentException("Window container=" + mWindowContainerController
+ " already created for r=" + this);
-
}
inHistory = true;
@@ -752,10 +757,36 @@ final class ActivityRecord implements AppWindowContainerListener {
}
void removeWindowContainer() {
+ // Resume key dispatching if it is currently paused before we remove the container.
+ resumeKeyDispatchingLocked();
+
mWindowContainerController.removeContainer(getDisplayId());
mWindowContainerController = null;
}
+ /**
+ * Reparents this activity into {@param newTask} at the provided {@param position}. The caller
+ * should ensure that the {@param newTask} is not already the parent of this activity.
+ */
+ void reparent(TaskRecord newTask, int position, String reason) {
+ final TaskRecord prevTask = task;
+ if (prevTask == newTask) {
+ throw new IllegalArgumentException(reason + ": task=" + newTask
+ + " is already the parent of r=" + this);
+ }
+
+ // Must reparent first in window manager
+ mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
+
+ // Remove the activity from the old task and add it to the new task
+ prevTask.removeActivity(this);
+ // TODO(b/34179495): This should really be set to null in removeActivity() call above,
+ // but really bad things that I can't track down right now happen when I do that.
+ // So, setting it here now and will change later when there is time for investigation.
+ task = null;
+ newTask.addActivityAtIndex(position, this);
+ }
+
private boolean isHomeIntent(Intent intent) {
return Intent.ACTION_MAIN.equals(intent.getAction())
&& intent.hasCategory(Intent.CATEGORY_HOME)
@@ -800,19 +831,8 @@ final class ActivityRecord implements AppWindowContainerListener {
}
}
- void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
- if (task != null && task.removeActivity(this) && task != newTask
- && task.getStack() != null) {
- task.getStack().removeTask(task, "setTask");
- }
- task = newTask;
- setTaskToAffiliateWith(taskToAffiliateWith);
- }
-
void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
- if (taskToAffiliateWith != null &&
- launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE &&
- launchMode != ActivityInfo.LAUNCH_SINGLE_TASK) {
+ if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
task.setTaskToAffiliateWith(taskToAffiliateWith);
}
}
@@ -879,56 +899,91 @@ final class ActivityRecord implements AppWindowContainerListener {
}
boolean isResizeable() {
- return ActivityInfo.isResizeableMode(info.resizeMode);
- }
-
- boolean isResizeableOrForced() {
- return !isHomeActivity() && (isResizeable() || service.mForceResizableActivities);
+ return ActivityInfo.isResizeableMode(info.resizeMode) || info.supportsPictureInPicture();
}
- boolean isNonResizableOrForced() {
+ /**
+ * @return whether this activity is non-resizeable or forced to be resizeable
+ */
+ boolean isNonResizableOrForcedResizable() {
return info.resizeMode != RESIZE_MODE_RESIZEABLE
- && info.resizeMode != RESIZE_MODE_RESIZEABLE_AND_PIPABLE
&& info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
/**
- * @return whether this activity's resize mode supports PIP.
+ * @return whether this activity supports PiP multi-window and can be put in the pinned stack.
*/
boolean supportsPictureInPicture() {
- return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ return service.mSupportsPictureInPicture && !isHomeActivity()
+ && info.supportsPictureInPicture();
+ }
+
+ /**
+ * @return whether this activity supports split-screen multi-window and can be put in the docked
+ * stack.
+ */
+ boolean supportsSplitScreen() {
+ // An activity can not be docked even if it is considered resizeable because it only
+ // supports picture-in-picture mode but has a non-resizeable resizeMode
+ return service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
+ }
+
+ /**
+ * @return whether this activity supports freeform multi-window and can be put in the freeform
+ * stack.
+ */
+ boolean supportsFreeform() {
+ return service.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
+ }
+
+ /**
+ * @return whether this activity supports non-PiP multi-window.
+ */
+ private boolean supportsResizeableMultiWindow() {
+ return service.mSupportsMultiWindow && !isHomeActivity()
+ && (ActivityInfo.isResizeableMode(info.resizeMode)
+ || service.mForceResizableActivities);
}
/**
* @return whether this activity is currently allowed to enter PIP, throwing an exception if
- * the activity is not currently visible.
+ * the activity is not currently visible and {@param noThrow} is not set.
*/
- boolean checkEnterPictureInPictureState(String caller) {
+ boolean checkEnterPictureInPictureState(String caller, boolean noThrow) {
+ boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
boolean isKeyguardLocked = service.isKeyguardLocked();
boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
+ // Don't return early if !isNotLocked, since we want to throw an exception if the activity
+ // is in an incorrect state
+ boolean isNotLocked = !isKeyguardLocked && !isCurrentAppLocked;
switch (state) {
case RESUMED:
- // When visible, allow entering PiP if not on the lockscreen. If there is another
- // PiP activity, the logic to handle that comes later in enterPictureInPictureMode()
- return !isKeyguardLocked;
+ // When visible, allow entering PiP if not on the lockscreen and if the task is not
+ // locked
+ return isNotLocked;
case PAUSING:
case PAUSED:
- // When pausing, only allow enter PiP if not on the lockscreen and there is not
- // already an existing PiP activity
- return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing
+ // When pausing, then only allow enter PiP as in the resume state, and in addition,
+ // require that there is not an existing PiP activity and that the current system
+ // state supports entering PiP
+ return isNotLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing
&& checkEnterPictureInPictureOnHideAppOpsState();
case STOPPING:
// When stopping in a valid state, then only allow enter PiP as in the pause state.
// Otherwise, fall through to throw an exception if the caller is trying to enter
// PiP in an invalid stopping state.
if (supportsPictureInPictureWhilePausing) {
- return !isKeyguardLocked && !hasPinnedStack
+ return isNotLocked && !hasPinnedStack
&& checkEnterPictureInPictureOnHideAppOpsState();
}
default:
- throw new IllegalStateException(caller
- + ": Current activity is not visible (state=" + state.name() + ") "
- + "r=" + this);
+ if (noThrow) {
+ return false;
+ } else {
+ throw new IllegalStateException(caller
+ + ": Current activity is not visible (state=" + state.name() + ") "
+ + "r=" + this);
+ }
}
}
@@ -945,10 +1000,6 @@ final class ActivityRecord implements AppWindowContainerListener {
return false;
}
- boolean canGoInDockedStack() {
- return !isHomeActivity() && isResizeableOrForced();
- }
-
boolean isAlwaysFocusable() {
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
@@ -1630,7 +1681,8 @@ final class ActivityRecord implements AppWindowContainerListener {
if (!idle) {
// Instead of doing the full stop routine here, let's just hide any activities
// we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivitiesLocked(false);
+ mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
+ false /* remove */, true /* processPausingActivities */);
} else {
// If this activity was already idle, then we now need to make sure we perform
// the full stop of any activities that are waiting to do so. This is because
@@ -1790,7 +1842,8 @@ final class ActivityRecord implements AppWindowContainerListener {
if (_taskDescription.getIconFilename() == null &&
(icon = _taskDescription.getIcon()) != null) {
final String iconFilename = createImageFilename(createTime, task.taskId);
- final File iconFile = new File(TaskPersister.getUserImagesDir(userId), iconFilename);
+ final File iconFile = new File(TaskPersister.getUserImagesDir(task.userId),
+ iconFilename);
final String iconFilePath = iconFile.getAbsolutePath();
service.mRecentTasks.saveImage(icon, iconFilePath);
_taskDescription.setIconFilename(iconFilePath);
@@ -1859,11 +1912,22 @@ final class ActivityRecord implements AppWindowContainerListener {
task.taskId, requestedOrientation);
}
- // TODO: now used only in one place to address race-condition. Remove when that will be fixed.
- void setLastReportedConfiguration(@NonNull Configuration config) {
+ /**
+ * Set the last reported global configuration to the client. Should be called whenever a new
+ * global configuration is sent to the client for this activity.
+ */
+ void setLastReportedGlobalConfiguration(@NonNull Configuration config) {
mLastReportedConfiguration.setTo(config);
}
+ /**
+ * Set the last reported merged override configuration to the client. Should be called whenever
+ * a new merged configuration is sent to the client for this activity.
+ */
+ void setLastReportedMergedOverrideConfiguration(@NonNull Configuration config) {
+ mLastReportedOverrideConfiguration.setTo(config);
+ }
+
/** Call when override config was sent to the Window Manager to update internal records. */
void onOverrideConfigurationSent() {
mLastReportedOverrideConfiguration.setTo(task.getMergedOverrideConfiguration());
@@ -1948,7 +2012,8 @@ final class ActivityRecord implements AppWindowContainerListener {
+ ", newGlobalConfig=" + newGlobalConfig
+ ", newTaskMergedOverrideConfig=" + newTaskMergedOverrideConfig);
- if ((changes&(~info.getRealConfigChanged())) != 0 || forceNewConfig) {
+ if (shouldRelaunchLocked(changes, newGlobalConfig, newTaskMergedOverrideConfig)
+ || forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
configChangeFlags |= changes;
startFreezingScreenLocked(app, globalChanges);
@@ -1999,6 +2064,27 @@ final class ActivityRecord implements AppWindowContainerListener {
return true;
}
+ /**
+ * When assessing a configuration change, decide if the changes flags and the new configurations
+ * should cause the Activity to relaunch.
+ */
+ private boolean shouldRelaunchLocked(int changes, Configuration newGlobalConfig,
+ Configuration newTaskMergedOverrideConfig) {
+ int configChanged = info.getRealConfigChanged();
+
+ // Override for apps targeting pre-O sdks
+ // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
+ // to the config change.
+ // For O and later, apps will be required to add configChanges="uimode" to their manifest.
+ if (appInfo.targetSdkVersion < O
+ && requestedVrComponent != null
+ && (isInVrUiMode(newGlobalConfig) || isInVrUiMode(newTaskMergedOverrideConfig))) {
+ configChanged |= CONFIG_UI_MODE;
+ }
+
+ return (changes&(~configChanged)) != 0;
+ }
+
private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
Configuration oldTaskOverride) {
// If we went from full-screen to non-full-screen, make sure to use the correct
@@ -2099,7 +2185,7 @@ final class ActivityRecord implements AppWindowContainerListener {
// if the app is relaunched when it's stopped, and we're not resuming,
// put it back into stopped state.
if (stopped) {
- getStack().addToStopping(this, true /* immediate */);
+ getStack().addToStopping(this, true /* scheduleIdle */, false /* idleDelayed */);
}
}
@@ -2235,6 +2321,10 @@ final class ActivityRecord implements AppWindowContainerListener {
}
}
+ private static boolean isInVrUiMode(Configuration config) {
+ return (config.uiMode & Configuration.UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
+ }
+
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 963a9dcb1b01..104fc6a6e565 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -26,6 +26,8 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
@@ -62,7 +64,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
@@ -73,7 +74,6 @@ import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN_BEHIND;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
import static java.lang.Integer.MAX_VALUE;
-import static java.lang.Integer.MIN_VALUE;
import android.app.Activity;
import android.app.ActivityManager;
@@ -82,6 +82,7 @@ import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
+import android.app.RemoteAction;
import android.app.ResultInfo;
import android.content.ComponentName;
import android.content.Intent;
@@ -116,6 +117,8 @@ import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.wm.StackWindowController;
+import com.android.server.wm.StackWindowListener;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -130,7 +133,7 @@ import java.util.Set;
/**
* State and management of a single stack of activities.
*/
-final class ActivityStack extends ConfigurationContainer {
+final class ActivityStack extends ConfigurationContainer implements StackWindowListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
@@ -242,6 +245,7 @@ final class ActivityStack extends ConfigurationContainer {
final ActivityManagerService mService;
private final WindowManagerService mWindowManager;
+ private StackWindowController mWindowContainerController;
private final RecentTasks mRecentTasks;
/**
@@ -330,7 +334,7 @@ final class ActivityStack extends ConfigurationContainer {
private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
- private final Rect tempRect2 = new Rect();
+ private final Rect mTmpRect2 = new Rect();
/** Run all ActivityStacks through this */
private final ActivityStackSupervisor mStackSupervisor;
@@ -443,7 +447,7 @@ final class ActivityStack extends ConfigurationContainer {
}
ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
- RecentTasks recentTasks) {
+ RecentTasks recentTasks, boolean onTop) {
mActivityContainer = activityContainer;
mStackSupervisor = activityContainer.getOuter();
mService = mStackSupervisor.mService;
@@ -454,13 +458,25 @@ final class ActivityStack extends ConfigurationContainer {
mRecentTasks = recentTasks;
mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
? new LaunchingTaskPositioner() : null;
+ final ActivityStackSupervisor.ActivityDisplay display = mActivityContainer.mActivityDisplay;
+ mTmpRect2.setEmpty();
+ mWindowContainerController = new StackWindowController(mStackId, this,
+ display.mDisplayId, onTop, mTmpRect2);
+ activityContainer.mStack = this;
+ mStackSupervisor.mActivityContainers.put(mStackId, activityContainer);
+ postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
+ }
+
+ StackWindowController getWindowContainerController() {
+ return mWindowContainerController;
}
/** Adds the stack to specified display and calls WindowManager to do the same. */
- void addToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
- final Rect bounds = mWindowManager.addStackToDisplay(mStackId, activityDisplay.mDisplayId,
- onTop);
- postAddToDisplay(activityDisplay, bounds);
+ void reparent(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+ removeFromDisplay();
+ mTmpRect2.setEmpty();
+ mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
+ postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
}
/**
@@ -469,10 +485,10 @@ final class ActivityStack extends ConfigurationContainer {
* @param bounds Updated bounds.
*/
private void postAddToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay,
- Rect bounds) {
+ Rect bounds, boolean onTop) {
mDisplayId = activityDisplay.mDisplayId;
mStacks = activityDisplay.mStacks;
- mBounds = bounds;
+ mBounds = bounds != null ? new Rect(bounds) : null;
mFullscreen = mBounds == null;
if (mTaskPositioner != null) {
mTaskPositioner.setDisplay(activityDisplay.mDisplay);
@@ -480,6 +496,7 @@ final class ActivityStack extends ConfigurationContainer {
}
onParentChanged();
+ activityDisplay.attachStack(this, onTop);
if (mStackId == DOCKED_STACK_ID) {
// If we created a docked stack we want to resize it so it resizes all other stacks
// in the system.
@@ -489,16 +506,6 @@ final class ActivityStack extends ConfigurationContainer {
}
/**
- * Moves the stack to specified display.
- * @param activityDisplay Target display to move the stack to.
- */
- void moveToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay) {
- removeFromDisplay();
- final Rect bounds = mWindowManager.moveStackToDisplay(mStackId, activityDisplay.mDisplayId);
- postAddToDisplay(activityDisplay, bounds);
- }
-
- /**
* Updates the inner state of the stack to remove it from its current parent, so it can be
* either destroyed completely or re-parented.
*/
@@ -520,7 +527,8 @@ final class ActivityStack extends ConfigurationContainer {
void remove() {
removeFromDisplay();
mStackSupervisor.deleteActivityContainerRecord(mStackId);
- mWindowManager.removeStack(mStackId);
+ mWindowContainerController.removeContainer();
+ mWindowContainerController = null;
onParentChanged();
}
@@ -528,6 +536,45 @@ final class ActivityStack extends ConfigurationContainer {
mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
}
+ void animateResizePinnedStack(Rect bounds, int animationDuration) {
+ mWindowContainerController.animateResizePinnedStack(bounds, animationDuration);
+ }
+
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ mWindowContainerController.setPictureInPictureAspectRatio(aspectRatio);
+ }
+
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ mWindowContainerController.setPictureInPictureActions(actions);
+ }
+
+ void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds, Rect outTempInsetBounds,
+ boolean ignoreVisibility) {
+ mWindowContainerController.getStackDockedModeBounds(outBounds, outTempBounds,
+ outTempInsetBounds, ignoreVisibility);
+ }
+
+ void prepareFreezingTaskBounds() {
+ mWindowContainerController.prepareFreezingTaskBounds();
+ }
+
+ void getWindowContainerBounds(Rect outBounds) {
+ if (mWindowContainerController != null) {
+ mWindowContainerController.getBounds(outBounds);
+ return;
+ }
+ outBounds.setEmpty();
+ }
+
+ void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
+ mWindowContainerController.getBoundsForNewConfiguration(outBounds, outTempBounds);
+ }
+
+ void positionChildWindowContainerAtTop(TaskRecord child) {
+ mWindowContainerController.positionChildAtTop(child.getWindowContainerController(),
+ true /* includingParents */);
+ }
+
/**
* Defers updating the bounds of the stack. If the stack was resized/repositioned while
* deferring, the bounds will update in {@link #continueUpdateBounds()}.
@@ -548,8 +595,7 @@ final class ActivityStack extends ConfigurationContainer {
final boolean wasDeferred = mUpdateBoundsDeferred;
mUpdateBoundsDeferred = false;
if (wasDeferred && mUpdateBoundsDeferredCalled) {
- mStackSupervisor.resizeStackUncheckedLocked(this,
- mDeferredBounds.isEmpty() ? null : mDeferredBounds,
+ resize(mDeferredBounds.isEmpty() ? null : mDeferredBounds,
mDeferredTaskBounds.isEmpty() ? null : mDeferredTaskBounds,
mDeferredTaskInsetBounds.isEmpty() ? null : mDeferredTaskInsetBounds);
}
@@ -767,7 +813,8 @@ final class ActivityStack extends ConfigurationContainer {
task = topTask();
if (task != null) {
- task.moveWindowContainerToTop(true /* includingParents */);
+ mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
+ true /* includingParents */);
}
}
@@ -786,7 +833,7 @@ final class ActivityStack extends ConfigurationContainer {
mTaskHistory.remove(task);
mTaskHistory.add(0, task);
updateTaskMovement(task, false);
- task.moveWindowContainerToBottom();
+ mWindowContainerController.positionChildAtBottom(task.getWindowContainerController());
}
}
@@ -1092,6 +1139,18 @@ final class ActivityStack extends ConfigurationContainer {
}
/**
+ * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
+ * this directly impacts the responsiveness seen by the user.
+ */
+ private void schedulePauseTimeout(ActivityRecord r) {
+ final Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
+ msg.obj = r;
+ r.pauseTime = SystemClock.uptimeMillis();
+ mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
+ }
+
+ /**
* Start pausing the currently resumed activity. It is an error to call this if there
* is already an activity being paused or there is no resumed activity.
*
@@ -1197,14 +1256,7 @@ final class ActivityStack extends ConfigurationContainer {
return false;
} else {
- // Schedule a pause timeout in case the app doesn't respond.
- // We don't give it much time because this directly impacts the
- // responsiveness seen by the user.
- Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
- msg.obj = prev;
- prev.pauseTime = SystemClock.uptimeMillis();
- mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
+ schedulePauseTimeout(prev);
return true;
}
@@ -1285,7 +1337,7 @@ final class ActivityStack extends ConfigurationContainer {
|| mService.isSleepingOrShuttingDownLocked()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
- addToStopping(prev, true /* immediate */);
+ addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */);
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
@@ -1351,7 +1403,7 @@ final class ActivityStack extends ConfigurationContainer {
mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
}
- void addToStopping(ActivityRecord r, boolean immediate) {
+ void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
}
@@ -1362,11 +1414,14 @@ final class ActivityStack extends ConfigurationContainer {
// be cleared immediately.
boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
|| (r.frontOfTask && mTaskHistory.size() <= 1);
-
- if (immediate || forceIdle) {
+ if (scheduleIdle || forceIdle) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
- + forceIdle + "immediate=" + immediate);
- mStackSupervisor.scheduleIdleLocked();
+ + forceIdle + "immediate=" + !idleDelayed);
+ if (!idleDelayed) {
+ mStackSupervisor.scheduleIdleLocked();
+ } else {
+ mStackSupervisor.scheduleIdleTimeoutLocked(r);
+ }
} else {
mStackSupervisor.checkReadyForSleepLocked();
}
@@ -1499,38 +1554,6 @@ final class ActivityStack extends ConfigurationContainer {
final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
final int focusedStackId = focusedStack.mStackId;
- final TaskRecord topFocusedTask = focusedStack.topTask();
- final boolean isOnTopLauncherFocused = topFocusedTask != null &&
- topFocusedTask.isOnTopLauncher();
- if (isOnTopLauncherFocused) {
- // When an on-top launcher is focused, we should find out whether the freeform stack or
- // the fullscreen stack appears first underneath and has activities to show, and then
- // make it visible.
- boolean behindFullscreenOrFreeForm = false;
- for (int stackBehindFocusedIndex = mStacks.indexOf(focusedStack) - 1;
- stackBehindFocusedIndex >= 0; stackBehindFocusedIndex--) {
- ActivityStack stack = mStacks.get(stackBehindFocusedIndex);
- if ((stack.mStackId == FREEFORM_WORKSPACE_STACK_ID
- || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID)
- && stack.topRunningActivityLocked() != null) {
- if (stackIndex == stackBehindFocusedIndex) {
- return !behindFullscreenOrFreeForm ? STACK_VISIBLE : STACK_INVISIBLE;
- }
- behindFullscreenOrFreeForm = true;
- }
- }
- }
- // If an on-top launcher is on the top of the home stack but the home stack is not focused,
- // then the whole stack should be invisible.
- TaskRecord topTask = topTask();
- if (mStackId != focusedStackId && topTask != null && topTask.isOnTopLauncher()) {
- // We're here mostly because the on-top launcher didn't have a chance to move itself to
- // back. We should move it to back as soon as possible to avoid other activities
- // returning to it or other visibility issues.
- moveTaskToBackLocked(topTask.taskId);
- return STACK_INVISIBLE;
- }
-
if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
&& hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(focusedStackId)
&& !focusedStack.topActivity().fullscreen) {
@@ -1545,7 +1568,7 @@ final class ActivityStack extends ConfigurationContainer {
// home task even though it's not resizable.
final ActivityRecord r = focusedStack.topRunningActivityLocked();
final TaskRecord task = r != null ? r.task : null;
- return task == null || task.canGoInDockedStack() || task.isHomeTask() ? STACK_VISIBLE
+ return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE
: STACK_INVISIBLE;
}
@@ -1735,28 +1758,7 @@ final class ActivityStack extends ConfigurationContainer {
// status of an activity in a previous task affects other.
behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
} else if (mStackId == HOME_STACK_ID) {
- if (task.isOnTopLauncher()) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "On-top launcher: at " + task
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // When an on-top launcher is visible, (e.g. it's on the top of the home stack),
- // other tasks in the home stack could be visible if and only if:
- // - some app is running in the docked stack;
- // - no app is running in either the fullscreen stack or the freefrom stack.
- final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
- final ActivityStack fullscreenStack = mStackSupervisor.getStack(
- FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityStack freeformStack = mStackSupervisor.getStack(
- FREEFORM_WORKSPACE_STACK_ID);
- final boolean dockedStackEmpty = dockedStack == null ||
- dockedStack.topRunningActivityLocked() == null;
- final boolean fullscreenStackEmpty = fullscreenStack == null ||
- fullscreenStack.topRunningActivityLocked() == null;
- final boolean freeformStackEmpty = freeformStack == null ||
- freeformStack.topRunningActivityLocked() == null;
- behindFullscreenActivity = dockedStackEmpty || !fullscreenStackEmpty ||
- !freeformStackEmpty;
- } else if (task.isHomeTask()) {
+ if (task.isHomeTask()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+ " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
@@ -1839,6 +1841,12 @@ final class ActivityStack extends ConfigurationContainer {
if (isTop) {
mTopActivityOccludesKeyguard |= showWhenLocked;
}
+
+ final boolean canShowWithKeyguard = canShowWithInsecureKeyguard()
+ && mStackSupervisor.mKeyguardController.canDismissKeyguard();
+ if (canShowWithKeyguard) {
+ return true;
+ }
}
if (keyguardShowing) {
@@ -1854,6 +1862,22 @@ final class ActivityStack extends ConfigurationContainer {
}
}
+ /**
+ * Check if the display to which this stack is attached has
+ * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
+ */
+ private boolean canShowWithInsecureKeyguard() {
+ final ActivityStackSupervisor.ActivityDisplay activityDisplay
+ = mActivityContainer.mActivityDisplay;
+ if (activityDisplay == null) {
+ throw new IllegalStateException("Stack is not attached to any display, stackId="
+ + mStackId);
+ }
+
+ final int flags = activityDisplay.mDisplay.getFlags();
+ return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0;
+ }
+
private void checkTranslucentActivityWaiting(ActivityRecord top) {
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -1924,7 +1948,14 @@ final class ActivityStack extends ConfigurationContainer {
if (visibleBehind == r) {
releaseBackgroundResources(r);
} else {
- addToStopping(r, true /* immediate */);
+ // If this activity is in a state where it can currently enter
+ // picture-in-picture, then don't immediately schedule the idle now in case
+ // the activity tries to enterPictureInPictureMode() later. Otherwise,
+ // we will try and stop the activity next time idle is processed.
+ final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
+ "makeInvisible", true /* noThrow */);
+ addToStopping(r, true /* scheduleIdle */,
+ canEnterPictureInPicture /* idleDelayed */);
}
break;
@@ -2580,7 +2611,8 @@ final class ActivityStack extends ConfigurationContainer {
position = getAdjustedPositionForTask(task, position, null /* starting */);
mTaskHistory.remove(task);
mTaskHistory.add(position, task);
- task.positionWindowContainerAt(position);
+ mWindowContainerController.positionChildAt(task.getWindowContainerController(), position,
+ task.mBounds, task.getOverrideConfiguration());
updateTaskMovement(task, true);
}
@@ -2592,7 +2624,8 @@ final class ActivityStack extends ConfigurationContainer {
final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting);
mTaskHistory.add(position, task);
updateTaskMovement(task, true);
- task.moveWindowContainerToTop(true /* includingParents */);
+ mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
+ true /* includingParents */);
}
private void updateTaskReturnToForTopInsertion(TaskRecord task) {
@@ -2613,14 +2646,7 @@ final class ActivityStack extends ConfigurationContainer {
ActivityStack lastStack = mStackSupervisor.getLastStack();
final boolean fromHomeOrRecents = lastStack.isHomeOrRecentsStack();
final TaskRecord topTask = lastStack.topTask();
- final boolean fromOnTopLauncher = topTask != null && topTask.isOnTopLauncher();
- if (fromOnTopLauncher) {
- // Since an on-top launcher will is moved to back when tasks are launched from it,
- // those tasks should first try to return to a non-home activity.
- // This also makes sure that non-home activities are visible under a transparent
- // non-home activity.
- task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
- } else if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask != task)) {
+ if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask() != task)) {
// If it's a last task over home - we default to keep its return to type not to
// make underlying task focused when this one will be finished.
int returnToType = isLastTaskOverHome
@@ -2689,7 +2715,12 @@ final class ActivityStack extends ConfigurationContainer {
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
- r.createWindowContainer();
+ // TODO: Need to investigate if it is okay for the controller to already be created by the
+ // time we get to this point. I think it is, but need to double check.
+ // Use test in b/34179495 to trace the call path.
+ if (r.getWindowContainerController() == null) {
+ r.createWindowContainer();
+ }
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
@@ -2866,11 +2897,11 @@ final class ActivityStack extends ConfigurationContainer {
+ targetTask + " Callers=" + Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Pushing next activity " + p + " out to target's task " + target.task);
- p.setTask(targetTask, null);
- targetTask.addActivityAtBottom(p);
+ p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded");
}
- targetTask.moveWindowContainerToBottom();
+ mWindowContainerController.positionChildAtBottom(
+ targetTask.getWindowContainerController());
replyChainEnd = -1;
} else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
// If the activity should just be removed -- either
@@ -2997,8 +3028,7 @@ final class ActivityStack extends ConfigurationContainer {
+ " to task=" + task + ":" + taskInsertionPoint);
for (int srcPos = start; srcPos >= i; --srcPos) {
final ActivityRecord p = activities.get(srcPos);
- p.setTask(task, null);
- task.addActivityAtIndex(taskInsertionPoint, p);
+ p.reparent(task, taskInsertionPoint, "resetAffinityTaskIfNeededLocked");
if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
"Removing and adding activity " + p + " to stack at " + task
@@ -3006,7 +3036,8 @@ final class ActivityStack extends ConfigurationContainer {
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
+ " from " + srcPos + " in to resetting task " + task);
}
- task.moveWindowContainerToTop(true /* includingParents */);
+ mWindowContainerController.positionChildAtTop(
+ task.getWindowContainerController(), true /* includingParents */);
// Now we've moved it in to place... but what if this is
// a singleTop activity and we have put it on top of another
@@ -3483,7 +3514,7 @@ final class ActivityStack extends ConfigurationContainer {
if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
&& next != null && !next.nowVisible) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- addToStopping(r, false /* immediate */);
+ addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */);
}
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: "+ r + " (finish requested)");
@@ -3512,6 +3543,7 @@ final class ActivityStack extends ConfigurationContainer {
|| (prevState == ActivityState.PAUSED
&& (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID))
|| finishingActivityInNonFocusedStack
+ || prevState == ActivityState.STOPPING
|| prevState == ActivityState.STOPPED
|| prevState == ActivityState.INITIALIZING) {
r.makeFinishingLocked();
@@ -3736,7 +3768,7 @@ final class ActivityStack extends ConfigurationContainer {
mWindowManager.notifyAppRelaunchesCleared(r.appToken);
}
- private void removeTimeoutsForActivityLocked(ActivityRecord r) {
+ void removeTimeoutsForActivityLocked(ActivityRecord r) {
mStackSupervisor.removeTimeoutsForActivityLocked(r);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
@@ -4312,23 +4344,6 @@ final class ActivityStack extends ConfigurationContainer {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
if (mStackId == HOME_STACK_ID && topTask().isHomeTask()) {
- if (topTask().isOnTopLauncher()) {
- // An on-top launcher doesn't affect the visibility of activities on other stacks
- // behind it. So if we're moving an on-top launcher to the back, we want to move the
- // focus to the next focusable stack and resume an activity there.
- // Besides, when the docked stack is visible, we should also move the home stack to
- // the back to avoid the recents pops up on top of a fullscreen or freeform
- // activity.
-
- // Move the home stack to back.
- moveToBack(topTask());
-
- // Resume an activity in the next focusable stack.
- adjustFocusToNextFocusableStackLocked("moveTaskToBack");
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- return true;
- }
-
// For the case where we are moving the home task back and there is an activity visible
// behind it on the fullscreen stack, we want to move the focus to the visible behind
// activity to maintain order with what the user is seeing.
@@ -4375,7 +4390,7 @@ final class ActivityStack extends ConfigurationContainer {
}
mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
- tr.moveWindowContainerToBottom();
+ mWindowContainerController.positionChildAtBottom(tr.getWindowContainerController());
final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
@@ -4438,11 +4453,24 @@ final class ActivityStack extends ConfigurationContainer {
}
}
- /** Update override configurations of all tasks in the stack. */
- void updateOverrideConfiguration(Rect stackBounds, Rect tempTaskBounds,
- Rect tempTaskInsetBounds) {
+ // TODO: Figure-out a way to consolidate with resize() method below.
+ @Override
+ public void requestResize(Rect bounds) {
+ mService.resizeStack(mStackId, bounds, true /* allowResizeInDockedMode */,
+ false /* preserveWindows */, false /* animate */, -1 /* animationDuration */);
+ }
+
+ // TODO: Can only be called from special methods in ActivityStackSupervisor.
+ // Need to consolidate those calls points into this resize method so anyone can call directly.
+ void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds) {
+ bounds = TaskRecord.validateBounds(bounds);
+
+ if (!updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) {
+ return;
+ }
- final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : stackBounds;
+ // Update override configurations of all tasks in the stack.
+ final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
mTmpBounds.clear();
@@ -4456,9 +4484,9 @@ final class ActivityStack extends ConfigurationContainer {
// For freeform stack we don't adjust the size of the tasks to match that
// of the stack, but we do try to make sure the tasks are still contained
// with the bounds of the stack.
- tempRect2.set(task.mBounds);
- fitWithinBounds(tempRect2, stackBounds);
- task.updateOverrideConfiguration(tempRect2);
+ mTmpRect2.set(task.mBounds);
+ fitWithinBounds(mTmpRect2, bounds);
+ task.updateOverrideConfiguration(mTmpRect2);
} else {
task.updateOverrideConfiguration(taskBounds, insetBounds);
}
@@ -4471,11 +4499,9 @@ final class ActivityStack extends ConfigurationContainer {
}
}
- // We might trigger a configuration change. Save the current task bounds for freezing.
- mWindowManager.prepareFreezingTaskBounds(mStackId);
- mFullscreen = mWindowManager.resizeStack(mStackId, stackBounds, mTmpConfigs, mTmpBounds,
+ mFullscreen = mWindowContainerController.resize(bounds, mTmpConfigs, mTmpBounds,
mTmpInsetBounds);
- setBounds(stackBounds);
+ setBounds(bounds);
}
@@ -4665,7 +4691,7 @@ final class ActivityStack extends ConfigurationContainer {
}
ci.numActivities = numActivities;
ci.numRunning = numRunning;
- ci.isDockable = task.canGoInDockedStack();
+ ci.supportsSplitScreenMultiWindow = task.supportsSplitScreen();
ci.resizeMode = task.mResizeMode;
list.add(ci);
}
@@ -4899,7 +4925,8 @@ final class ActivityStack extends ConfigurationContainer {
addTask(task, toTop ? MAX_VALUE : 0, reason);
if (toTop) {
// TODO: figure-out a way to remove this call.
- task.moveWindowContainerToTop(true /* includingParents */);
+ mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
+ true /* includingParents */);
}
}
@@ -4989,6 +5016,7 @@ final class ActivityStack extends ConfigurationContainer {
// If the activity was previously pausing, then ensure we transfer that as well
if (setPause) {
mPausingActivity = r;
+ schedulePauseTimeout(r);
}
// Move the stack in which we are placing the activity to the front. The call will also
// make sure the activity focus is set.
@@ -5012,12 +5040,17 @@ final class ActivityStack extends ConfigurationContainer {
final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
final boolean wasPaused = prevStack.mPausingActivity == r;
+ // Create a new task for the activity to be parented in
final TaskRecord task = createTaskRecord(
mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
r.info, r.intent, null, null, true, r.mActivityType);
- r.setTask(task, null);
- task.addActivityToTop(r);
+ // This is a new task, so reparenting it to position 0 will move it to the top
+ r.reparent(task, 0 /* position */, "moveActivityToStack");
+
+ // Notify the task actiivties if it was moved to/from a pinned stack
mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
+
+ // Resume the activity if necessary after it has moved
moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, wasPaused,
"moveActivityToStack");
if (wasResumed) {
@@ -5025,6 +5058,7 @@ final class ActivityStack extends ConfigurationContainer {
}
if (wasPaused) {
prevStack.mPausingActivity = null;
+ prevStack.removeTimeoutsForActivityLocked(r);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2c1c3a191d11..e954363a936b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -90,7 +90,6 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static java.lang.Integer.MAX_VALUE;
-import static java.lang.Integer.MIN_VALUE;
import android.Manifest;
import android.annotation.NonNull;
@@ -164,6 +163,8 @@ import android.view.InputEvent;
import android.view.Surface;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.TransferPipe;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
@@ -377,7 +378,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();
+ SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();
/** Mapping from displayId to display current state */
private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
@@ -419,8 +420,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityMetricsLogger mActivityMetricsLogger;
- private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
-
@Override
protected int getChildCount() {
return mActivityDisplays.size();
@@ -530,7 +529,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService = service;
mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
- mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
mKeyguardController = new KeyguardController(service, this);
}
@@ -1323,7 +1321,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
profilerInfo = new ProfilerInfo(profileFile, profileFd,
- mService.mSamplingInterval, mService.mAutoStopProfiler);
+ mService.mSamplingInterval, mService.mAutoStopProfiler,
+ mService.mStreamingOutput);
}
}
}
@@ -1336,10 +1335,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Because we could be starting an Activity in the system process this may not go across
// a Binder interface which would create a new Configuration. Consequently we have to
// always create a new Configuration here.
+
+ final Configuration globalConfiguration =
+ new Configuration(mService.getGlobalConfiguration());
+ r.setLastReportedGlobalConfiguration(globalConfiguration);
+ final Configuration mergedOverrideConfiguration =
+ new Configuration(task.getMergedOverrideConfiguration());
+ r.setLastReportedMergedOverrideConfiguration(mergedOverrideConfiguration);
+
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
- new Configuration(mService.getGlobalConfiguration()),
- new Configuration(task.getMergedOverrideConfiguration()), r.compat,
+ globalConfiguration,
+ mergedOverrideConfiguration, r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
@@ -1708,7 +1715,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Checked.
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
- Configuration config) {
+ boolean processPausingActivities, Configuration config) {
if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
ArrayList<ActivityRecord> finishes = null;
@@ -1734,7 +1741,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// We'll update with whatever configuration it now says
// it used to launch.
if (config != null) {
- r.setLastReportedConfiguration(config);
+ r.setLastReportedGlobalConfiguration(config);
}
// We are now idle. If someone is waiting for a thumbnail from
@@ -1764,7 +1771,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Atomically retrieve all of the other things to do.
- final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(true);
+ final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
+ true /* remove */, processPausingActivities);
NS = stops != null ? stops.size() : 0;
if ((NF = mFinishingActivities.size()) > 0) {
finishes = new ArrayList<>(mFinishingActivities);
@@ -2199,7 +2207,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
mWindowManager.deferSurfaceLayout();
try {
- resizeStackUncheckedLocked(stack, bounds, tempTaskBounds, tempTaskInsetBounds);
+ stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds);
if (!deferResume) {
stack.ensureVisibleActivitiesConfigurationLocked(
stack.topRunningActivityLocked(), preserveWindows);
@@ -2237,17 +2245,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mResizingTasksDuringAnimation.clear();
}
- void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
- Rect tempTaskInsetBounds) {
- bounds = TaskRecord.validateBounds(bounds);
-
- if (!stack.updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) {
- return;
- }
-
- stack.updateOverrideConfiguration(bounds, tempTaskBounds, tempTaskInsetBounds);
- }
-
void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) {
final ActivityStack stack = getStack(fromStackId);
if (stack == null) {
@@ -2291,6 +2288,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// pinned stack is recreated. See moveActivityToPinnedStackLocked().
task.setTaskToReturnTo(isFullscreenStackVisible && onTop ?
APPLICATION_ACTIVITY_TYPE : HOME_ACTIVITY_TYPE);
+ MetricsLogger.action(mService.mContext,
+ MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
}
moveTaskToStackLocked(tasks.get(i).taskId,
FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
@@ -2341,8 +2340,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Don't allow re-entry while resizing. E.g. due to docked stack detaching.
mAllowDockedStackResize = false;
ActivityRecord r = stack.topRunningActivityLocked();
- resizeStackUncheckedLocked(stack, dockedBounds, tempDockedTaskBounds,
- tempDockedTaskInsetBounds);
+ stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds);
// TODO: Checking for isAttached might not be needed as if the user passes in null
// dockedBounds then they want the docked stack to be dismissed.
@@ -2359,13 +2357,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
- mWindowManager.getStackDockedModeBounds(
- HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+ final Rect tempOtherTaskRect = new Rect();
+ final Rect tempOtherTaskInsetRect = new Rect();
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
- resizeStackLocked(i, tempRect, tempOtherTaskBounds,
- tempOtherTaskInsetBounds, preserveWindows,
- true /* allowResizeInDockedMode */, deferResume);
+ final ActivityStack current = getStack(i);
+ if (current != null && StackId.isResizeableByDockedStack(i)) {
+ current.getStackDockedModeBounds(tempRect, tempOtherTaskRect,
+ tempOtherTaskInsetRect, true /* ignoreVisibility */);
+ resizeStackLocked(i, tempRect,
+ !tempOtherTaskRect.isEmpty() ? tempOtherTaskRect :
+ tempOtherTaskBounds,
+ !tempOtherTaskInsetRect.isEmpty() ? tempOtherTaskInsetRect :
+ tempOtherTaskInsetBounds,
+ preserveWindows, true /* allowResizeInDockedMode */, deferResume);
}
}
}
@@ -2377,12 +2381,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
-
- mResizeDockedStackTimeout.notifyResizing(dockedBounds,
- tempDockedTaskBounds != null
- || tempDockedTaskInsetBounds != null
- || tempOtherTaskBounds != null
- || tempOtherTaskInsetBounds != null);
}
void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
@@ -2395,8 +2393,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mWindowManager.deferSurfaceLayout();
try {
ActivityRecord r = stack.topRunningActivityLocked();
- resizeStackUncheckedLocked(stack, pinnedBounds, tempPinnedTaskBounds,
- null);
+ stack.resize(pinnedBounds, tempPinnedTaskBounds, null);
stack.ensureVisibleActivitiesConfigurationLocked(r, false);
} finally {
mWindowManager.continueSurfaceLayout();
@@ -2405,14 +2402,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
- ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+ final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
return null;
}
- ActivityContainer activityContainer = new ActivityContainer(stackId);
- mActivityContainers.put(stackId, activityContainer);
- activityContainer.addToDisplayLocked(activityDisplay, onTop);
+ final ActivityContainer activityContainer =
+ new ActivityContainer(stackId, activityDisplay, onTop);
return activityContainer.mStack;
}
@@ -2576,7 +2572,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// This means that tasks that were on external displays will be restored on the
// primary display.
stackId = task.getLaunchStackId();
- } else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) {
+ } else if (stackId == DOCKED_STACK_ID && !task.supportsSplitScreen()) {
// Preferred stack is the docked stack, but the task can't go in the docked stack.
// Put it in the fullscreen stack.
stackId = FULLSCREEN_WORKSPACE_STACK_ID;
@@ -2706,6 +2702,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Reset the paused activity on the previous stack
if (wasPaused) {
prevStack.mPausingActivity = null;
+ prevStack.removeTimeoutsForActivityLocked(r);
}
// If the task had focus before (or we're requested to move focus),
@@ -2771,7 +2768,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// We might trigger a configuration change. Save the current task bounds for freezing.
- mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+ // TODO: Should this call be moved inside the resize method in WM?
+ stack.prepareFreezingTaskBounds();
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
@@ -2840,7 +2838,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds,
boolean moveHomeStackToFront) {
+
mWindowManager.deferSurfaceLayout();
+ // Need to make sure the pinned stack exist so we can resize it below...
+ final ActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+
try {
final TaskRecord task = r.task;
@@ -2850,9 +2852,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
requestVisibleBehindLocked(r, false);
}
- // Need to make sure the pinned stack exist so we can resize it below...
- final ActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
-
// Resize the pinned stack to match the current size of the task the activity we are
// going to be moving is currently contained in. We do this to have the right starting
// animation bounds for the pinned stack to the desired bounds the caller wants.
@@ -2892,7 +2891,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- mWindowManager.animateResizePinnedStack(bounds, -1);
+ stack.animateResizePinnedStack(bounds, -1);
mService.mTaskChangeNotificationController.notifyActivityPinned();
}
@@ -3357,7 +3356,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
stack.switchUserLocked(userId);
TaskRecord task = stack.topTask();
if (task != null) {
- task.moveWindowContainerToTop(true /* includingParents */);
+ stack.positionChildWindowContainerAtTop(task);
}
}
}
@@ -3382,7 +3381,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return mService.mUserController.isCurrentProfileLocked(userId);
}
- final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
+ final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
+ boolean remove, boolean processPausingActivities) {
ArrayList<ActivityRecord> stops = null;
final boolean nowVisible = allResumedActivitiesVisible();
@@ -3407,6 +3407,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
+ if (!processPausingActivities && s.state == PAUSING) {
+ // Defer processing pausing activities in this iteration and reschedule
+ // a delayed idle to reprocess it again
+ removeTimeoutsForActivityLocked(idleActivity);
+ scheduleIdleTimeoutLocked(idleActivity);
+ continue;
+ }
+
if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
if (stops == null) {
stops = new ArrayList<>();
@@ -3795,7 +3803,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
private StackInfo getStackInfoLocked(ActivityStack stack) {
final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY);
StackInfo info = new StackInfo();
- mWindowManager.getStackBounds(stack.mStackId, info.bounds);
+ stack.getWindowContainerBounds(info.bounds);
info.displayId = DEFAULT_DISPLAY;
info.stackId = stack.mStackId;
info.userId = stack.mCurrentUser;
@@ -3895,14 +3903,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
final ActivityRecord topActivity = task.getTopActivity();
- if (!task.canGoInDockedStack() || forceNonResizable) {
+ if (!task.supportsSplitScreen() || forceNonResizable) {
// Display a warning toast that we tried to put a non-dockable task in the docked stack.
mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
moveTasksToFullscreenStackLocked(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
- } else if (topActivity != null && topActivity.isNonResizableOrForced()
+ } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
&& !topActivity.noDisplay) {
String packageName = topActivity.appInfo.packageName;
mService.mTaskChangeNotificationController.notifyActivityForcedResizable(
@@ -4108,18 +4116,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
void setDockedStackMinimized(boolean minimized) {
mIsDockMinimized = minimized;
- if (minimized) {
- // Docked stack is not visible, no need to confirm credentials for its top activity.
- return;
- }
- final ActivityStack dockedStack = getStack(StackId.DOCKED_STACK_ID);
- if (dockedStack == null) {
- return;
- }
- final ActivityRecord top = dockedStack.topRunningActivityLocked();
- if (top != null && mService.mUserController.shouldConfirmCredentials(top.userId)) {
- mService.mActivityStarter.showConfirmDeviceCredential(top.userId);
- }
}
private final class ActivityStackSupervisorHandler extends Handler {
@@ -4128,9 +4124,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
super(looper);
}
- void activityIdleInternal(ActivityRecord r) {
+ void activityIdleInternal(ActivityRecord r, boolean processPausingActivities) {
synchronized (mService) {
- activityIdleInternalLocked(r != null ? r.appToken : null, true, null);
+ activityIdleInternalLocked(r != null ? r.appToken : null, true /* fromTimeout */,
+ processPausingActivities, null);
}
}
@@ -4165,11 +4162,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- activityIdleInternal((ActivityRecord)msg.obj);
+ activityIdleInternal((ActivityRecord) msg.obj,
+ true /* processPausingActivities */);
} break;
case IDLE_NOW_MSG: {
if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
- activityIdleInternal((ActivityRecord)msg.obj);
+ activityIdleInternal((ActivityRecord) msg.obj,
+ false /* processPausingActivities */);
} break;
case RESUME_TOP_ACTIVITY_MSG: {
synchronized (mService) {
@@ -4321,7 +4320,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
final int mStackId;
IActivityContainerCallback mCallback = null;
- final ActivityStack mStack;
+ ActivityStack mStack;
ActivityRecord mParentActivity = null;
String mIdString;
@@ -4335,10 +4334,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final static int CONTAINER_STATE_FINISHING = 2;
int mContainerState = CONTAINER_STATE_HAS_SURFACE;
- ActivityContainer(int stackId) {
+ ActivityContainer(int stackId, ActivityDisplay activityDisplay, boolean onTop) {
synchronized (mService) {
mStackId = stackId;
- mStack = new ActivityStack(this, mRecentTasks);
+ mActivityDisplay = activityDisplay;
+ new ActivityStack(this, mRecentTasks, onTop);
mIdString = "ActivtyContainer{" + mStackId + "}";
if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
}
@@ -4346,21 +4346,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
/**
* Adds the stack to specified display. Also calls WindowManager to do the same from
- * {@link ActivityStack#addToDisplay(ActivityDisplay, boolean)}.
+ * {@link ActivityStack#reparent(ActivityDisplay, boolean)}.
* @param activityDisplay The display to add the stack to.
- * @param onTop If true the stack will be place at the top of the display, else at the
- * bottom.
*/
- void addToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
+ void addToDisplayLocked(ActivityDisplay activityDisplay) {
if (DEBUG_STACK) Slog.d(TAG_STACK, "addToDisplayLocked: " + this
- + " to display=" + activityDisplay + " onTop=" + onTop);
+ + " to display=" + activityDisplay);
if (mActivityDisplay != null) {
throw new IllegalStateException("ActivityContainer is already attached, " +
"displayId=" + mActivityDisplay.mDisplayId);
}
mActivityDisplay = activityDisplay;
- mStack.addToDisplay(activityDisplay, onTop);
- activityDisplay.attachActivities(mStack, onTop);
+ mStack.reparent(activityDisplay, true /* onTop */);
}
@Override
@@ -4370,7 +4367,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (activityDisplay == null) {
return;
}
- addToDisplayLocked(activityDisplay, true /* onTop */);
+ addToDisplayLocked(activityDisplay);
}
}
@@ -4447,7 +4444,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (DEBUG_STACK) Slog.d(TAG_STACK, "removeFromDisplayLocked: " + this
+ " current displayId=" + mActivityDisplay.mDisplayId);
- mActivityDisplay.detachActivitiesLocked(mStack);
+ mActivityDisplay.detachStack(mStack);
mActivityDisplay = null;
}
@@ -4463,8 +4460,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
removeFromDisplayLocked();
mActivityDisplay = activityDisplay;
- mStack.moveToDisplay(activityDisplay);
- activityDisplay.attachActivities(mStack, ON_TOP);
+ mStack.reparent(activityDisplay, ON_TOP);
}
@Override
@@ -4554,7 +4550,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
boolean mDrawn = false;
VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) {
- super(getNextStackId());
+ super(getNextStackId(), parent.getStack().mActivityContainer.mActivityDisplay,
+ true /* onTop */);
mParentActivity = parent;
mCallback = callback;
mContainerState = CONTAINER_STATE_NO_SURFACE;
@@ -4586,7 +4583,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
new VirtualActivityDisplay(width, height, density);
mActivityDisplay = virtualActivityDisplay;
mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
- addToDisplayLocked(virtualActivityDisplay, true /* onTop */);
+ addToDisplayLocked(virtualActivityDisplay);
}
if (mSurface != null) {
@@ -4675,10 +4672,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mDisplayId = display.getDisplayId();
}
- void attachActivities(ActivityStack stack, boolean onTop) {
- if (DEBUG_STACK) Slog.v(TAG_STACK,
- "attachActivities: attaching " + stack + " to displayId=" + mDisplayId
- + " onTop=" + onTop);
+ void attachStack(ActivityStack stack, boolean onTop) {
+ if (DEBUG_STACK) Slog.v(TAG_STACK, "attachStack: attaching " + stack
+ + " to displayId=" + mDisplayId + " onTop=" + onTop);
if (onTop) {
mStacks.add(stack);
} else {
@@ -4686,8 +4682,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
- void detachActivitiesLocked(ActivityStack stack) {
- if (DEBUG_STACK) Slog.v(TAG_STACK, "detachActivitiesLocked: detaching " + stack
+ void detachStack(ActivityStack stack) {
+ if (DEBUG_STACK) Slog.v(TAG_STACK, "detachStack: detaching " + stack
+ " from displayId=" + mDisplayId);
mStacks.remove(stack);
}
@@ -4765,8 +4761,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
@Override
- void detachActivitiesLocked(ActivityStack stack) {
- super.detachActivitiesLocked(stack);
+ void detachStack(ActivityStack stack) {
+ super.detachStack(stack);
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
mVirtualDisplay = null;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 873f2b7a04b6..d1606b4dc13b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -608,58 +608,14 @@ class ActivityStarter {
}
}
- void showConfirmDeviceCredential(int userId) {
- // First, retrieve the stack that we want to resume after credential is confirmed.
- ActivityStack targetStack;
- ActivityStack fullscreenStack =
- mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
- if (fullscreenStack != null &&
- fullscreenStack.getStackVisibilityLocked(null) != ActivityStack.STACK_INVISIBLE) {
- // Single window case and the case that the docked stack is shown with fullscreen stack.
- targetStack = fullscreenStack;
- } else {
- // The case that the docked stack is shown with recent.
- targetStack = mSupervisor.getStack(HOME_STACK_ID);
- }
- if (targetStack == null) {
- return;
- }
- final KeyguardManager km = (KeyguardManager) mService.mContext
- .getSystemService(Context.KEYGUARD_SERVICE);
- final Intent credential =
- km.createConfirmDeviceCredentialIntent(null, null, userId);
- // For safety, check null here in case users changed the setting after the checking.
- if (credential == null) {
- return;
- }
- final ActivityRecord activityRecord = targetStack.topRunningActivityLocked();
- if (activityRecord != null) {
- final IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY,
- activityRecord.launchedFromPackage,
- activityRecord.launchedFromUid,
- activityRecord.userId,
- null, null, 0,
- new Intent[] { activityRecord.intent },
- new String[] { activityRecord.resolvedType },
- PendingIntent.FLAG_CANCEL_CURRENT |
- PendingIntent.FLAG_ONE_SHOT |
- PendingIntent.FLAG_IMMUTABLE,
- null);
- credential.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
- // Show confirm credentials activity.
- startConfirmCredentialIntent(credential);
- }
- }
-
- void startConfirmCredentialIntent(Intent intent) {
+ void startConfirmCredentialIntent(Intent intent, Bundle optionsBundle) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
FLAG_ACTIVITY_TASK_ON_HOME);
- final ActivityOptions options = ActivityOptions.makeBasic();
+ ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle)
+ : ActivityOptions.makeBasic());
options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
- mService.mContext.startActivityAsUser(intent, options.toBundle(),
- UserHandle.CURRENT);
+ mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
}
final int startActivityMayWait(IApplicationThread caller, int callingUid,
@@ -1542,15 +1498,7 @@ class ActivityStarter {
private void updateTaskReturnToType(
TaskRecord task, int launchFlags, ActivityStack focusedStack) {
- if (focusedStack != null && focusedStack.isHomeOrRecentsStack()
- && focusedStack.topTask() != null && focusedStack.topTask().isOnTopLauncher()) {
- // Since an on-top launcher will is moved to back when tasks are launched from it,
- // those tasks should first try to return to a non-home activity.
- // This also makes sure that non-home activities are visible under a transparent
- // non-home activity.
- task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
- return;
- } else if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity.
task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
@@ -1659,7 +1607,7 @@ class ActivityStarter {
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
- mStartActivity.setTask(task, taskToAffiliate);
+ addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
if (mLaunchBounds != null) {
final int stackId = mTargetStack.mStackId;
if (StackId.resizeStackWithLaunchBounds(stackId)) {
@@ -1669,11 +1617,14 @@ class ActivityStarter {
mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
}
}
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " +
- mStartActivity + " in new task " + mStartActivity.task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in new task " + mStartActivity.task);
} else {
- mStartActivity.setTask(mReuseTask, taskToAffiliate);
+ addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
+ }
+
+ if (taskToAffiliate != null) {
+ mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
@@ -1763,7 +1714,7 @@ class ActivityStarter {
// An existing activity is starting this new activity, so we want to keep the new one in
// the same task as the one that is starting it.
- mStartActivity.setTask(sourceTask, null);
+ addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord");
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
return START_SUCCESS;
@@ -1796,7 +1747,8 @@ class ActivityStarter {
// Check whether we should actually launch the new activity in to the task,
// or just reuse the current activity on top.
ActivityRecord top = mInTask.getTopActivity();
- if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+ if (top != null && top.realActivity.equals(mStartActivity.realActivity)
+ && top.userId == mStartActivity.userId) {
if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
@@ -1805,7 +1757,8 @@ class ActivityStarter {
// anything if that is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
- top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+ mStartActivity.launchedFromPackage);
return START_DELIVERED_TO_TOP;
}
}
@@ -1817,9 +1770,9 @@ class ActivityStarter {
return START_TASK_TO_FRONT;
}
- mStartActivity.setTask(mInTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+ addOrReparentStartingActivity(mInTask, "setTaskFromInTask");
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in explicit task " + mStartActivity.task);
return START_SUCCESS;
}
@@ -1834,10 +1787,18 @@ class ActivityStarter {
final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
mIntent, null, null, true, mStartActivity.mActivityType);
- mStartActivity.setTask(task, null);
- mStartActivity.task.moveWindowContainerToTop(true /* includingParents */);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
+ addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
+ mTargetStack.positionChildWindowContainerAtTop(task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in new guessed " + mStartActivity.task);
+ }
+
+ private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
+ if (mStartActivity.task == null || mStartActivity.task == parent) {
+ parent.addActivityToTop(mStartActivity);
+ } else {
+ mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason);
+ }
}
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
@@ -1967,10 +1928,10 @@ class ActivityStarter {
canUseFocusedStack = true;
break;
case DOCKED_STACK_ID:
- canUseFocusedStack = r.canGoInDockedStack();
+ canUseFocusedStack = r.supportsSplitScreen();
break;
case FREEFORM_WORKSPACE_STACK_ID:
- canUseFocusedStack = r.isResizeableOrForced();
+ canUseFocusedStack = r.supportsFreeform();
break;
default:
canUseFocusedStack = isDynamicStack(focusedStackId)
@@ -2057,29 +2018,27 @@ class ActivityStarter {
}
boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
- if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID) {
- return false;
- }
-
- if (stackId != FULLSCREEN_WORKSPACE_STACK_ID
- && (!mService.mSupportsMultiWindow || !r.isResizeableOrForced())) {
- return false;
- }
-
- if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
- return true;
- }
-
- if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
- return false;
- }
-
- final boolean supportsPip = mService.mSupportsPictureInPicture
- && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
- if (stackId == PINNED_STACK_ID && !supportsPip) {
- return false;
+ switch (stackId) {
+ case INVALID_STACK_ID:
+ case HOME_STACK_ID:
+ return false;
+ case FULLSCREEN_WORKSPACE_STACK_ID:
+ return true;
+ case FREEFORM_WORKSPACE_STACK_ID:
+ return r.supportsFreeform();
+ case DOCKED_STACK_ID:
+ return r.supportsSplitScreen();
+ case PINNED_STACK_ID:
+ return r.supportsPictureInPicture();
+ case RECENTS_STACK_ID:
+ return r.isRecentsActivity();
+ default:
+ if (StackId.isDynamicStack(stackId)) {
+ return true;
+ }
+ Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
+ return false;
}
- return true;
}
Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 384f2f8662b8..36a913fb9c53 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -357,7 +357,7 @@ class AppErrors {
* If this process was running instrumentation, finish now - it will be handled in
* {@link ActivityManagerService#handleAppDiedLocked}.
*/
- if (r != null && r.instrumentationClass != null) {
+ if (r != null && r.instr != null) {
return;
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f1f8bb20652d..35713025a2f5 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -51,8 +51,8 @@ import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.IntArray;
import android.util.Slog;
-
import android.util.TimeUtils;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
@@ -1127,6 +1127,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
pw.println(" full-history: include additional detailed events in battery history:");
pw.println(" wake_lock_in, alarms and proc events");
pw.println(" no-auto-reset: don't automatically reset stats when unplugged");
+ pw.println(" pretend-screen-off: pretend the screen is off, even if screen state changes");
}
private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
@@ -1144,6 +1145,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.setNoAutoReset(enable);
}
+ } else if ("pretend-screen-off".equals(args[i])) {
+ synchronized (mStats) {
+ mStats.setPretendScreenOff(enable);
+ }
} else {
pw.println("Unknown enable/disable option: " + args[i]);
dumpHelp(pw);
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index b0a4746b8ff1..2bd119ec177d 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -280,7 +280,7 @@ class KeyguardController {
/**
* @return true if Keyguard can be currently dismissed without entering credentials.
*/
- private boolean canDismissKeyguard() {
+ boolean canDismissKeyguard() {
return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1322ecf89baf..40effff77166 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -138,31 +138,9 @@ final class ProcessList {
// without empty apps being able to push them out of memory.
static final int MIN_CACHED_APPS = 2;
- // The maximum number of cached processes we will keep around before killing them.
- // NOTE: this constant is *only* a control to not let us go too crazy with
- // keeping around processes on devices with large amounts of RAM. For devices that
- // are tighter on RAM, the out of memory killer is responsible for killing background
- // processes as RAM is needed, and we should *never* be relying on this limit to
- // kill them. Also note that this limit only applies to cached background processes;
- // we have no limit on the number of service, visible, foreground, or other such
- // processes and the number of those processes does not count against the cached
- // process limit.
- static final int MAX_CACHED_APPS = 32;
-
// We allow empty processes to stick around for at most 30 minutes.
static final long MAX_EMPTY_TIME = 30*60*1000;
- // The maximum number of empty app processes we will let sit around.
- private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);
-
- // The number of empty apps at which we don't consider it necessary to do
- // memory trimming.
- static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
-
- // The number of cached at which we don't consider it necessary to do
- // memory trimming.
- static final int TRIM_CACHED_APPS = (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
-
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 49fe79c7d01e..356781fc7956 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -135,13 +135,7 @@ final class ProcessRecord {
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
- ComponentName instrumentationClass;// class installed to instrument app
- ApplicationInfo instrumentationInfo; // the application being instrumented
- String instrumentationProfileFile; // where to save profiling
- IInstrumentationWatcher instrumentationWatcher; // who is waiting
- IUiAutomationConnection instrumentationUiAutomationConnection; // Connection to use the UI introspection APIs.
- Bundle instrumentationArguments;// as given to us
- ComponentName instrumentationResultClass;// copy of instrumentationClass
+ ActiveInstrumentation instr;// Set to currently active instrumentation running in process
boolean usingWrapper; // Set to true when process was launched with a wrapper attached
final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
long lastWakeTime; // How long proc held wake lock at last check
@@ -248,19 +242,8 @@ final class ProcessRecord {
pw.println("}");
}
pw.print(prefix); pw.print("compat="); pw.println(compat);
- if (instrumentationClass != null || instrumentationProfileFile != null
- || instrumentationArguments != null) {
- pw.print(prefix); pw.print("instrumentationClass=");
- pw.print(instrumentationClass);
- pw.print(" instrumentationProfileFile=");
- pw.println(instrumentationProfileFile);
- pw.print(prefix); pw.print("instrumentationArguments=");
- pw.println(instrumentationArguments);
- pw.print(prefix); pw.print("instrumentationInfo=");
- pw.println(instrumentationInfo);
- if (instrumentationInfo != null) {
- instrumentationInfo.dump(new PrintWriterPrinter(pw), prefix + " ");
- }
+ if (instr != null) {
+ pw.print(prefix); pw.print("instr="); pw.println(instr);
}
pw.print(prefix); pw.print("thread="); pw.println(thread);
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 8d2b1c2fda79..d210ed76eca8 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -28,6 +28,8 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.DumpUtils;
import com.android.internal.app.procstats.IProcessStats;
import com.android.internal.app.procstats.ProcessState;
@@ -78,6 +80,10 @@ public final class ProcessStatsService extends IProcessStats.Stub {
boolean mPendingWriteCommitted;
long mLastWriteTime;
+ /** For CTS to inject the screen state. */
+ @GuardedBy("mAm")
+ Boolean mInjectedScreenState;
+
public ProcessStatsService(ActivityManagerService am, File file) {
mAm = am;
mBaseDir = file;
@@ -128,6 +134,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
mMemFactorLowered = memFactor < mLastMemOnlyState;
mLastMemOnlyState = memFactor;
+ if (mInjectedScreenState != null) {
+ screenOn = mInjectedScreenState;
+ }
if (screenOn) {
memFactor += ProcessStats.ADJ_SCREEN_ON;
}
@@ -573,7 +582,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]");
pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]");
- pw.println(" [--start-testing] [--stop-testing] [<package.name>]");
+ pw.println(" [--start-testing] [--stop-testing] ");
+ pw.println(" [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]");
+ pw.println(" [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" -c: print only state in checkin format.");
pw.println(" --csv: output data suitable for putting in a spreadsheet.");
@@ -595,6 +606,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println(" --read: replace current stats with last-written stats.");
pw.println(" --start-testing: clear all stats and starting high frequency pss sampling.");
pw.println(" --stop-testing: stop high frequency pss sampling.");
+ pw.println(" --pretend-screen-on: pretend screen is on.");
+ pw.println(" --pretend-screen-off: pretend screen is off.");
+ pw.println(" --stop-pretend-screen: forget \"pretend screen\" and use the real state.");
pw.println(" -a: print everything.");
pw.println(" -h: print this help text.");
pw.println(" <package.name>: optional name of package to filter output by.");
@@ -800,6 +814,21 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println("Stopped high frequency sampling.");
quit = true;
}
+ } else if ("--pretend-screen-on".equals(arg)) {
+ synchronized (mAm) {
+ mInjectedScreenState = true;
+ }
+ quit = true;
+ } else if ("--pretend-screen-off".equals(arg)) {
+ synchronized (mAm) {
+ mInjectedScreenState = false;
+ }
+ quit = true;
+ } else if ("--stop-pretend-screen".equals(arg)) {
+ synchronized (mAm) {
+ mInjectedScreenState = null;
+ }
+ quit = true;
} else if ("-h".equals(arg)) {
dumpHelp(pw);
return;
diff --git a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
deleted file mode 100644
index ff395895e638..000000000000
--- a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.am;
-
-import android.graphics.Rect;
-import android.os.Handler;
-
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-
-/**
- * When resizing the docked stack, a caller can temporarily supply task bounds that are different
- * from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
- * this class manages this cycle.
- */
-class ResizeDockedStackTimeout {
-
- private static final long TIMEOUT_MS = 10 * 1000;
- private final ActivityManagerService mService;
- private final ActivityStackSupervisor mSupervisor;
- private final Handler mHandler;
- private final Rect mCurrentDockedBounds = new Rect();
-
- private final Runnable mTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- synchronized (mService) {
- mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
- PRESERVE_WINDOWS);
- }
- }
- };
-
- ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
- Handler handler) {
- mService = service;
- mSupervisor = supervisor;
- mHandler = handler;
- }
-
- void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
- mHandler.removeCallbacks(mTimeoutRunnable);
- if (!hasTempBounds) {
- return;
- }
- mCurrentDockedBounds.set(dockedBounds);
- mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
- }
-
-}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 7b4d289ac82a..e237e41a3d52 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -51,6 +51,7 @@ import android.util.Slog;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
+import com.android.server.wm.AppWindowContainerController;
import com.android.server.wm.TaskWindowContainerController;
import com.android.server.wm.TaskWindowContainerListener;
@@ -74,7 +75,6 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
@@ -85,6 +85,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRA
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
@@ -141,6 +142,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
private static final String ATTR_CALLING_UID = "calling_uid";
private static final String ATTR_CALLING_PACKAGE = "calling_package";
+ private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
@@ -188,14 +190,15 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
int mResizeMode; // The resize mode of this task and its activities.
// Based on the {@link ActivityInfo#resizeMode} of the root activity.
+ private boolean mSupportsPictureInPicture; // Whether or not this task and its activities
+ // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
+ // of the root activity.
boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
// changes on a temporary basis.
private int mLockTaskMode; // Which tasklock mode to launch this task in. One of
// ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
// privileged permissions.
- private boolean mIsOnTopLauncher; // Whether this task is an on-top launcher. See
- // android.R.attr#onTopLauncher.
/** Can't be put in lockTask mode. */
final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
@@ -356,8 +359,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean privileged, boolean _realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight) {
+ int resizeMode, boolean supportsPictureInPicture, boolean privileged,
+ boolean _realActivitySuspended, boolean userSetupComplete, int minWidth,
+ int minHeight) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -396,6 +400,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
mCallingUid = callingUid;
mCallingPackage = callingPackage;
mResizeMode = resizeMode;
+ mSupportsPictureInPicture = supportsPictureInPicture;
mPrivileged = privileged;
mMinWidth = minWidth;
mMinHeight = minHeight;
@@ -414,9 +419,10 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
final Configuration overrideConfig = getOverrideConfiguration();
- mWindowContainerController = new TaskWindowContainerController(taskId, this, getStackId(),
- userId, bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
- showForAllUsers, lastTaskDescription);
+ mWindowContainerController = new TaskWindowContainerController(taskId, this,
+ getStack().getWindowContainerController(), userId, bounds, overrideConfig,
+ mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers,
+ lastTaskDescription);
}
void removeWindowContainer() {
@@ -450,6 +456,12 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
mWindowContainerController.setTaskDockedResizing(resizing);
}
+ // TODO: Consolidate this with the resize() method below.
+ @Override
+ public void requestResize(Rect bounds, int resizeMode) {
+ mService.resizeTask(taskId, bounds, resizeMode);
+ }
+
boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
if (!isResizeable()) {
Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
@@ -520,25 +532,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
false /* forced */);
}
- // TODO: Remove once we have a stack controller.
- void positionWindowContainerAt(int position) {
- mWindowContainerController.positionAt(position, mBounds, getOverrideConfiguration());
- }
-
- // TODO: Replace with moveChildToTop?
- void moveWindowContainerToTop(boolean includingParents) {
- if (mWindowContainerController != null) {
- mWindowContainerController.moveToTop(includingParents);
- }
- }
-
- // TODO: Replace with moveChildToBottom?
- void moveWindowContainerToBottom() {
- if (mWindowContainerController != null) {
- mWindowContainerController.moveToBottom();
- }
- }
-
void getWindowContainerBounds(Rect bounds) {
mWindowContainerController.getBounds(bounds);
}
@@ -556,7 +549,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
// Must reparent first in window manager to avoid a situation where AM can delete the
// we are coming from in WM before we reparent because it became empty.
- mWindowContainerController.reparent(stackId, position);
+ mWindowContainerController.reparent(newStack.getWindowContainerController(), position);
final ActivityStack prevStack = mStack;
prevStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING);
@@ -691,7 +684,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
autoRemoveRecents = false;
}
mResizeMode = info.resizeMode;
- mIsOnTopLauncher = (info.flags & FLAG_ON_TOP_LAUNCHER) != 0;
+ mSupportsPictureInPicture = info.supportsPictureInPicture();
mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
setLockTaskAuth();
@@ -1032,9 +1025,17 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
addActivityAtIndex(mActivities.size(), r);
}
- // TODO: Figure-out if any of the call points expect the window container to be reparented and
- // correct them to use the right method.
+ /**
+ * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
+ * be in the current task or unparented to any task.
+ */
void addActivityAtIndex(int index, ActivityRecord r) {
+ if (r.task != null && r.task != this) {
+ throw new IllegalArgumentException("Can not add r=" + " to task=" + this
+ + " current parent=" + r.task);
+ }
+ r.task = this;
+
// Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
if (!mActivities.remove(r) && r.fullscreen) {
// Was not previously in list.
@@ -1065,6 +1066,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
}
}
+ index = Math.min(size, index);
mActivities.add(index, r);
updateEffectiveIntent();
if (r.isPersistable()) {
@@ -1073,7 +1075,12 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
// Sync. with window manager
updateOverrideConfigurationFromLaunchBounds();
- mWindowContainerController.positionChildAt(r.getWindowContainerController(), index);
+ final AppWindowContainerController appController = r.getWindowContainerController();
+ if (appController != null) {
+ // Only attempt to move in WM if the child has a controller. It is possible we haven't
+ // created controller for the activity we are starting yet.
+ mWindowContainerController.positionChildAt(appController, index);
+ }
r.onOverrideConfigurationSent();
}
@@ -1301,9 +1308,21 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
return mTaskToReturnTo == HOME_ACTIVITY_TYPE;
}
+ private boolean isResizeable(boolean checkSupportsPip) {
+ return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+ || (checkSupportsPip && mSupportsPictureInPicture)) && !mTemporarilyUnresizable;
+ }
+
boolean isResizeable() {
- return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode))
- && !mTemporarilyUnresizable;
+ return isResizeable(true /* checkSupportsPip */);
+ }
+
+ boolean supportsSplitScreen() {
+ // A task can not be docked even if it is considered resizeable because it only supports
+ // picture-in-picture mode but has a non-resizeable resizeMode
+ return mService.mSupportsSplitScreenMultiWindow
+ && isResizeable(false /* checkSupportsPip */)
+ && !ActivityInfo.isPreserveOrientationMode(mResizeMode);
}
/**
@@ -1312,7 +1331,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
* @param bounds The bounds to be tested.
* @return True if the requested bounds are okay for a resizing request.
*/
- boolean canResizeToBounds(Rect bounds) {
+ private boolean canResizeToBounds(Rect bounds) {
if (bounds == null || getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
// Note: If not on the freeform workspace, we ignore the bounds.
return true;
@@ -1325,15 +1344,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
&& (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
}
- boolean isOnTopLauncher() {
- return isHomeTask() && mIsOnTopLauncher;
- }
-
- boolean canGoInDockedStack() {
- return isResizeable() && mService.mSupportsSplitScreenMultiWindow &&
- !ActivityInfo.isPreserveOrientationMode(mResizeMode);
- }
-
/**
* Find the activity in the history stack within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
@@ -1482,6 +1492,8 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
+ out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
+ String.valueOf(mSupportsPictureInPicture));
out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
if (mLastNonFullscreenBounds != null) {
out.attribute(
@@ -1552,6 +1564,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
int callingUid = -1;
String callingPackage = "";
int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+ boolean supportsPictureInPicture = false;
boolean privileged = false;
Rect bounds = null;
int minWidth = INVALID_MIN_SIZE;
@@ -1618,6 +1631,8 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
callingPackage = attrValue;
} else if (ATTR_RESIZE_MODE.equals(attrName)) {
resizeMode = Integer.parseInt(attrValue);
+ } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) {
+ supportsPictureInPicture = Boolean.parseBoolean(attrValue);
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.parseBoolean(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
@@ -1690,6 +1705,15 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
if (taskType == HOME_ACTIVITY_TYPE && resizeMode == RESIZE_MODE_RESIZEABLE) {
resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
+ } else {
+ // This activity has previously marked itself explicitly as both resizeable and
+ // supporting picture-in-picture. Since there is no longer a requirement for
+ // picture-in-picture activities to be resizeable, we can mark this simply as
+ // resizeable and supporting picture-in-picture separately.
+ if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
+ resizeMode = RESIZE_MODE_RESIZEABLE;
+ supportsPictureInPicture = true;
+ }
}
final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
@@ -1697,8 +1721,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
- taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
- realActivitySuspended, userSetupComplete, minWidth, minHeight);
+ taskAffiliationColor, callingUid, callingPackage, resizeMode,
+ supportsPictureInPicture, privileged, realActivitySuspended, userSetupComplete,
+ minWidth, minHeight);
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -2084,6 +2109,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
+ pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
pw.print(" isResizeable=" + isResizeable());
pw.print(" firstActiveTime=" + lastActiveTime);
pw.print(" lastActiveTime=" + lastActiveTime);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 31ef94fb5381..1d60946129a7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -144,7 +144,6 @@ import java.util.Objects;
*/
public class AudioService extends IAudioService.Stub
implements AccessibilityManager.TouchExplorationStateChangeListener,
- AccessibilityManager.AccessibilityStateChangeListener,
AccessibilityManager.AccessibilityServicesStateChangeListener {
private static final String TAG = "AudioService";
@@ -689,7 +688,7 @@ public class AudioService extends IAudioService.Stub
mSettingsObserver = new SettingsObserver();
createStreamStates();
- mMediaFocusControl = new MediaFocusControl(mContext);
+ mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
readAndSetLowRamDevice();
@@ -5582,6 +5581,10 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.getCurrentAudioFocus();
}
+ public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
+ return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
+ }
+
private boolean readCameraSoundForced() {
return SystemProperties.getBoolean("audio.camerasound.force", false) ||
mContext.getResources().getBoolean(
@@ -5926,25 +5929,13 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// Accessibility
- /**
- * Compile-time constant to enable the use of an independent a11y volume:
- * - set to true to listen to a11y services state changes and read
- * the whether any exposes the FLAG_ENABLE_ACCESSIBILITY_VOLUME flag
- * - set to false to listen to when accessibility services are started (e.g. "TalkBack started")
- */
- private static final boolean USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME = false;
-
private void initA11yMonitoring() {
final AccessibilityManager accessibilityManager =
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
- updateA11yVolumeAlias(accessibilityManager.isEnabled());
+ updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
accessibilityManager.addTouchExplorationStateChangeListener(this);
- if (USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME) {
- accessibilityManager.addAccessibilityServicesStateChangeListener(this);
- } else {
- accessibilityManager.addAccessibilityStateChangeListener(this);
- }
+ accessibilityManager.addAccessibilityServicesStateChangeListener(this);
}
//---------------------------------------------------------------------------------
@@ -5982,12 +5973,6 @@ public class AudioService extends IAudioService.Stub
private static boolean sIndependentA11yVolume = false;
- // implementation of AccessibilityStateChangeListener
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- updateA11yVolumeAlias(enabled);
- }
-
// implementation of AccessibilityServicesStateChangeListener
@Override
public void onAccessibilityServicesStateChanged() {
@@ -6081,6 +6066,7 @@ public class AudioService extends IAudioService.Stub
pw.print(" mSafeMediaVolumeState=");
pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
+ pw.print(" sIndependentA11yVolume="); pw.println(sIndependentA11yVolume);
pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
pw.print(" mMcc="); pw.println(mMcc);
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index cc18114120eb..5275c0524d54 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -17,6 +17,7 @@
package com.android.server.audio;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.media.AudioAttributes;
import android.media.AudioFocusInfo;
import android.media.AudioManager;
@@ -47,6 +48,7 @@ public class FocusRequester {
private final String mPackageName;
private final int mCallingUid;
private final MediaFocusControl mFocusController; // never null
+
/**
* the audio focus gain request that caused the addition of this object in the focus stack.
*/
@@ -62,6 +64,10 @@ public class FocusRequester {
*/
private int mFocusLossReceived;
/**
+ * whether this focus owner listener was notified when it lost focus
+ */
+ private boolean mFocusLossWasNotified;
+ /**
* the audio attributes associated with the focus request
*/
private final AudioAttributes mAttributes;
@@ -124,6 +130,10 @@ public class FocusRequester {
return mCallingUid == uid;
}
+ int getClientUid() {
+ return mCallingUid;
+ }
+
String getClientId() {
return mClientId;
}
@@ -195,6 +205,7 @@ public class FocusRequester {
+ " -- gain: " + focusGainToString()
+ " -- flags: " + flagsToString(mGrantFlags)
+ " -- loss: " + focusLossToString()
+ + " -- notified: " + mFocusLossWasNotified
+ " -- uid: " + mCallingUid
+ " -- attr: " + mAttributes);
}
@@ -263,9 +274,9 @@ public class FocusRequester {
/**
* Called synchronized on MediaFocusControl.mAudioFocusLock
*/
- void handleExternalFocusGain(int focusGain) {
+ void handleExternalFocusGain(int focusGain, final FocusRequester fr) {
int focusLoss = focusLossForGainRequest(focusGain);
- handleFocusLoss(focusLoss);
+ handleFocusLoss(focusLoss, fr);
}
/**
@@ -273,6 +284,7 @@ public class FocusRequester {
*/
void handleFocusGain(int focusGain) {
try {
+ final int oldLoss = mFocusLossReceived;
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -282,8 +294,13 @@ public class FocusRequester {
Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
+ mClientId);
}
- fd.dispatchAudioFocusChange(focusGain, mClientId);
+ if (mFocusLossWasNotified) {
+ fd.dispatchAudioFocusChange(focusGain, mClientId);
+ } else if (oldLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
+ mFocusController.unduckPlayers(this);
+ }
}
+ mFocusLossWasNotified = false;
} catch (android.os.RemoteException e) {
Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
}
@@ -292,10 +309,11 @@ public class FocusRequester {
/**
* Called synchronized on MediaFocusControl.mAudioFocusLock
*/
- void handleFocusLoss(int focusLoss) {
+ void handleFocusLoss(int focusLoss, @Nullable final FocusRequester fr) {
try {
if (focusLoss != mFocusLossReceived) {
mFocusLossReceived = focusLoss;
+ mFocusLossWasNotified = false;
// before dispatching a focus loss, check if the following conditions are met:
// 1/ the framework is not supposed to notify the focus loser on a DUCK loss
// 2/ it is a DUCK loss
@@ -313,6 +331,27 @@ public class FocusRequester {
toAudioFocusInfo(), false /* wasDispatched */);
return;
}
+
+ // check enforcement by the framework
+ boolean handled = false;
+ if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+ && MediaFocusControl.ENFORCE_DUCKING
+ && fr != null) {
+ // candidate for enforcement by the framework
+ if (fr.mCallingUid != this.mCallingUid) {
+ handled = mFocusController.duckPlayers(fr, this);
+ } // else: the focus change is within the same app, so let the dispatching
+ // happen as if the framework was not involved.
+ }
+
+ if (handled) {
+ if (DEBUG) {
+ Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
+ + " to " + mClientId + ", ducking implemented by framework");
+ }
+ return; // with mFocusLossWasNotified = false
+ }
+
final IAudioFocusDispatcher fd = mFocusDispatcher;
if (fd != null) {
if (DEBUG) {
@@ -321,6 +360,7 @@ public class FocusRequester {
}
mFocusController.notifyExtPolicyFocusLoss_syncAf(
toAudioFocusInfo(), true /* wasDispatched */);
+ mFocusLossWasNotified = true;
fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
}
}
@@ -330,7 +370,7 @@ public class FocusRequester {
}
AudioFocusInfo toAudioFocusInfo() {
- return new AudioFocusInfo(mAttributes, mClientId, mPackageName,
+ return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName,
mFocusGainRequest, mFocusLossReceived, mGrantFlags);
}
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 206834e9adc4..a1c56538e9bd 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -40,16 +40,24 @@ import java.text.DateFormat;
* @hide
*
*/
-public class MediaFocusControl {
+public class MediaFocusControl implements PlayerFocusEnforcer {
private static final String TAG = "MediaFocusControl";
+ /**
+ * set to true so the framework enforces ducking itself, without communicating to apps
+ * that they lost focus.
+ */
+ static final boolean ENFORCE_DUCKING = false;
+
private final Context mContext;
private final AppOpsManager mAppOps;
+ private PlayerFocusEnforcer mFocusEnforcer; // never null
- protected MediaFocusControl(Context cntxt) {
+ protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
mContext = cntxt;
mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mFocusEnforcer = pfe;
}
protected void dump(PrintWriter pw) {
@@ -58,6 +66,17 @@ public class MediaFocusControl {
dumpFocusStack(pw);
}
+ //=================================================================
+ // PlayerFocusEnforcer implementation
+ @Override
+ public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
+ return mFocusEnforcer.duckPlayers(winner, loser);
+ }
+
+ @Override
+ public void unduckPlayers(FocusRequester winner) {
+ mFocusEnforcer.unduckPlayers(winner);
+ }
//==========================================================================================
// AudioFocus
@@ -75,7 +94,7 @@ public class MediaFocusControl {
if (!mFocusStack.empty()) {
// notify the current focus owner it lost focus after removing it from stack
final FocusRequester exFocusOwner = mFocusStack.pop();
- exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
+ exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null);
exFocusOwner.release();
}
}
@@ -97,12 +116,12 @@ public class MediaFocusControl {
* Focus is requested, propagate the associated loss throughout the stack.
* @param focusGain the new focus gain that will later be added at the top of the stack
*/
- private void propagateFocusLossFromGain_syncAf(int focusGain) {
+ private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr) {
// going through the audio focus stack to signal new focus, traversing order doesn't
// matter as all entries respond to the same external focus gain
Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- stackIterator.next().handleExternalFocusGain(focusGain);
+ stackIterator.next().handleExternalFocusGain(focusGain, fr);
}
}
@@ -237,7 +256,7 @@ public class MediaFocusControl {
Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
new Exception());
// no exclusive owner, push at top of stack, focus is granted, propagate change
- propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
+ propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr);
mFocusStack.push(nfr);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
} else {
@@ -381,6 +400,38 @@ public class MediaFocusControl {
}
}
+ /**
+ * Return the volume ramp time expected before playback with the given AudioAttributes would
+ * start after gaining audio focus.
+ * @param attr attributes of the sound about to start playing
+ * @return time in ms
+ */
+ protected int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
+ switch (attr.getUsage()) {
+ case AudioAttributes.USAGE_MEDIA:
+ case AudioAttributes.USAGE_GAME:
+ return 1000;
+ case AudioAttributes.USAGE_ALARM:
+ case AudioAttributes.USAGE_NOTIFICATION_RINGTONE:
+ case AudioAttributes.USAGE_ASSISTANT:
+ case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY:
+ case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ return 700;
+ case AudioAttributes.USAGE_VOICE_COMMUNICATION:
+ case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ case AudioAttributes.USAGE_NOTIFICATION:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ case AudioAttributes.USAGE_NOTIFICATION_EVENT:
+ case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION:
+ return 500;
+ case AudioAttributes.USAGE_UNKNOWN:
+ default:
+ return 0;
+ }
+ }
+
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
@@ -463,7 +514,7 @@ public class MediaFocusControl {
} else {
// propagate the focus change through the stack
if (!mFocusStack.empty()) {
- propagateFocusLossFromGain_syncAf(focusChangeHint);
+ propagateFocusLossFromGain_syncAf(focusChangeHint, nfr);
}
// push focus requester at the top of the audio focus stack
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index c6b2cf64c30c..4930c5374513 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -37,12 +37,13 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
/**
* Class to receive and dispatch updates from AudioSystem about recording configurations.
*/
public final class PlaybackActivityMonitor
- implements AudioPlaybackConfiguration.PlayerDeathMonitor {
+ implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
public final static String TAG = "AudioService.PlaybackActivityMonitor";
private final static boolean DEBUG = false;
@@ -134,12 +135,18 @@ public final class PlaybackActivityMonitor
}
protected void dump(PrintWriter pw) {
+ // players
pw.println("\nPlaybackActivityMonitor dump time: "
+ DateFormat.getTimeInstance().format(new Date()));
synchronized(mPlayerLock) {
for (AudioPlaybackConfiguration conf : mPlayers.values()) {
conf.dump(pw);
}
+ // ducked players
+ pw.println("\n ducked player piids:");
+ for (int piid : mDuckedPlayers) {
+ pw.println(" " + piid);
+ }
}
}
@@ -211,7 +218,7 @@ public final class PlaybackActivityMonitor
List<AudioPlaybackConfiguration> sysConfigs) {
ArrayList<AudioPlaybackConfiguration> publicConfigs =
new ArrayList<AudioPlaybackConfiguration>();
- // only add active anonymized configurations,
+ // only add active anonymized configurations,
for (AudioPlaybackConfiguration config : sysConfigs) {
if (config.isActive()) {
publicConfigs.add(AudioPlaybackConfiguration.anonymizedCopy(config));
@@ -220,6 +227,82 @@ public final class PlaybackActivityMonitor
return publicConfigs;
}
+
+ //=================================================================
+ // PlayerFocusEnforcer implementation
+ private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
+
+ @Override
+ public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
+ winner.getClientUid(), loser.getClientUid())); }
+ synchronized (mPlayerLock) {
+ if (mPlayers.isEmpty()) {
+ return true;
+ }
+ final Set<Integer> piidSet = mPlayers.keySet();
+ final Iterator<Integer> piidIterator = piidSet.iterator();
+ // find which players to duck
+ while (piidIterator.hasNext()) {
+ final Integer piid = piidIterator.next();
+ final AudioPlaybackConfiguration apc = mPlayers.get(piid);
+ if (!winner.hasSameUid(apc.getClientUid())
+ && loser.hasSameUid(apc.getClientUid())
+ && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
+ {
+ if (mDuckedPlayers.contains(piid)) {
+ if (DEBUG) { Log.v(TAG, "player " + piid + " already ducked"); }
+ } else if (apc.getAudioAttributes().getContentType() ==
+ AudioAttributes.CONTENT_TYPE_SPEECH) {
+ // the player is speaking, ducking will make the speech unintelligible
+ // so let the app handle it instead
+ return false;
+ } else {
+ try {
+ if (DEBUG) { Log.v(TAG, "ducking player " + piid); }
+ //FIXME just a test before we have VolumeShape
+ apc.getPlayerProxy().setPan(-1.0f);
+ mDuckedPlayers.add(piid);
+ } catch (Exception e) {
+ Log.e(TAG, "Error ducking player " + piid, e);
+ // something went wrong trying to duck, so let the app handle it
+ // instead, it may know things we don't
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void unduckPlayers(FocusRequester winner) {
+ if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
+ synchronized (mPlayerLock) {
+ if (mDuckedPlayers.isEmpty()) {
+ return;
+ }
+ for (int piid : mDuckedPlayers) {
+ final AudioPlaybackConfiguration apc = mPlayers.get(piid);
+ if (apc != null
+ && winner.hasSameUid(apc.getClientUid())) {
+ try {
+ if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
+ //FIXME just a test before we have VolumeShape
+ apc.getPlayerProxy().setPan(0.0f);
+ mDuckedPlayers.remove(new Integer(piid));
+ } catch (Exception e) {
+ Log.e(TAG, "Error unducking player " + piid, e);
+ }
+ } else {
+ Log.e(TAG, "Error unducking player " + piid + ", player not found");
+ }
+ }
+ }
+ }
+
//=================================================================
// Track playback activity listeners
diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
new file mode 100644
index 000000000000..acb4f0d8f3a9
--- /dev/null
+++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.audio;
+
+public interface PlayerFocusEnforcer {
+
+ /**
+ * Ducks the players associated with the "loser" focus owner (i.e. same UID). Returns true if
+ * at least one active player was found and ducked, false otherwise.
+ * @param winner
+ * @param loser
+ * @return
+ */
+ public boolean duckPlayers(FocusRequester winner, FocusRequester loser);
+
+ public void unduckPlayers(FocusRequester winner);
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 8d4f0a925d8d..4487d5b9b28e 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -40,6 +40,8 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
@@ -50,18 +52,106 @@ import com.android.server.SystemService;
import java.util.HashSet;
import java.util.List;
+import java.lang.Thread;
+import java.lang.Runnable;
+import java.lang.InterruptedException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+// The following class is Android Emulator specific. It is used to read and
+// write contents of the host system's clipboard.
+class HostClipboardMonitor implements Runnable {
+ public interface HostClipboardCallback {
+ void onHostClipboardUpdated(String contents);
+ }
+
+ private RandomAccessFile mPipe = null;
+ private HostClipboardCallback mHostClipboardCallback;
+ private static final String PIPE_NAME = "pipe:clipboard";
+ private static final String PIPE_DEVICE = "/dev/qemu_pipe";
+
+ private void openPipe() {
+ try {
+ // String.getBytes doesn't include the null terminator,
+ // but the QEMU pipe device requires the pipe service name
+ // to be null-terminated.
+ byte[] b = new byte[PIPE_NAME.length() + 1];
+ b[PIPE_NAME.length()] = 0;
+ System.arraycopy(
+ PIPE_NAME.getBytes(),
+ 0,
+ b,
+ 0,
+ PIPE_NAME.length());
+ mPipe = new RandomAccessFile(PIPE_DEVICE, "rw");
+ mPipe.write(b);
+ } catch (IOException e) {
+ try {
+ if (mPipe != null) mPipe.close();
+ } catch (IOException ee) {}
+ mPipe = null;
+ }
+ }
+
+ public HostClipboardMonitor(HostClipboardCallback cb) {
+ mHostClipboardCallback = cb;
+ }
+
+ @Override
+ public void run() {
+ while(!Thread.interrupted()) {
+ try {
+ // There's no guarantee that QEMU pipes will be ready at the moment
+ // this method is invoked. We simply try to get the pipe open and
+ // retry on failure indefinitely.
+ while (mPipe == null) {
+ openPipe();
+ Thread.sleep(100);
+ }
+ int size = mPipe.readInt();
+ size = Integer.reverseBytes(size);
+ byte[] receivedData = new byte[size];
+ mPipe.readFully(receivedData);
+ mHostClipboardCallback.onHostClipboardUpdated(
+ new String(receivedData));
+ } catch (IOException e) {
+ try {
+ mPipe.close();
+ } catch (IOException ee) {}
+ mPipe = null;
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ public void setHostClipboard(String content) {
+ try {
+ if (mPipe != null) {
+ mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
+ mPipe.write(content.getBytes());
+ }
+ } catch(IOException e) {
+ Slog.e("HostClipboardMonitor",
+ "Failed to set host clipboard " + e.getMessage());
+ }
+ }
+}
+
/**
* Implementation of the clipboard for copy and paste.
*/
public class ClipboardService extends SystemService {
private static final String TAG = "ClipboardService";
+ private static final boolean IS_EMULATOR =
+ SystemProperties.getBoolean("ro.kernel.qemu", false);
private final IActivityManager mAm;
private final IUserManager mUm;
private final PackageManager mPm;
private final AppOpsManager mAppOps;
private final IBinder mPermissionOwner;
+ private HostClipboardMonitor mHostClipboardMonitor = null;
+ private Thread mHostMonitorThread = null;
private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
@@ -82,6 +172,23 @@ public class ClipboardService extends SystemService {
Slog.w("clipboard", "AM dead", e);
}
mPermissionOwner = permOwner;
+ if (IS_EMULATOR) {
+ mHostClipboardMonitor = new HostClipboardMonitor(
+ new HostClipboardMonitor.HostClipboardCallback() {
+ @Override
+ public void onHostClipboardUpdated(String contents){
+ ClipData clip =
+ new ClipData("host clipboard",
+ new String[]{"text/plain"},
+ new ClipData.Item(contents));
+ synchronized(mClipboards) {
+ setPrimaryClipInternal(getClipboard(0), clip);
+ }
+ }
+ });
+ mHostMonitorThread = new Thread(mHostClipboardMonitor);
+ mHostMonitorThread.start();
+ }
}
@Override
@@ -142,6 +249,11 @@ public class ClipboardService extends SystemService {
if (clip != null && clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
+ if (clip.getItemAt(0).getText() != null &&
+ mHostClipboardMonitor != null) {
+ mHostClipboardMonitor.setHostClipboard(
+ clip.getItemAt(0).getText().toString());
+ }
final int callingUid = Binder.getCallingUid();
if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
callingPackage) != AppOpsManager.MODE_ALLOWED) {
@@ -292,6 +404,10 @@ public class ClipboardService extends SystemService {
return;
}
clipboard.primaryClip = clip;
+ final ClipDescription description = clipboard.primaryClip.getDescription();
+ if (description != null) {
+ description.setTimestamp(SystemClock.elapsedRealtime());
+ }
final long ident = Binder.clearCallingIdentity();
final int n = clipboard.primaryClipListeners.beginBroadcast();
try {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b0e45097aff6..9d63462d6abc 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1244,10 +1244,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
return false;
}
- private boolean isSimCardAbsent(String state) {
- return IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state);
- }
-
private boolean isSimCardLoaded(String state) {
return IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state);
}
@@ -1264,9 +1260,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
// used to verify this receiver is still current
final private int mGenerationNumber;
- // we're interested in edge-triggered LOADED notifications, so
- // ignore LOADED unless we saw an ABSENT state first
- private boolean mSimAbsentSeen = false;
+ // used to check the sim state transition from non-loaded to loaded
+ private boolean mSimNotLoadedSeen = false;
public SimChangeBroadcastReceiver(int generationNumber) {
mGenerationNumber = generationNumber;
@@ -1284,16 +1279,16 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
final String state = intent.getStringExtra(
IccCardConstants.INTENT_KEY_ICC_STATE);
- Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" +
- mSimAbsentSeen);
+ Log.d(TAG, "got Sim changed to state " + state + ", mSimNotLoadedSeen=" +
+ mSimNotLoadedSeen);
- if (isSimCardAbsent(state)) {
- if (!mSimAbsentSeen) mSimAbsentSeen = true;
+ if (!isSimCardLoaded(state)) {
+ if (!mSimNotLoadedSeen) mSimNotLoadedSeen = true;
return;
}
- if (isSimCardLoaded(state) && mSimAbsentSeen) {
- mSimAbsentSeen = false;
+ if (isSimCardLoaded(state) && mSimNotLoadedSeen) {
+ mSimNotLoadedSeen = false;
if (!hasMobileHotspotProvisionApp()) return;
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 23481dc2dbfd..017c5fb4d4ec 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -40,7 +40,9 @@ import java.util.HashMap;
* pertaining to the current and any potential upstream network.
*
* Calling #start() registers two callbacks: one to track the system default
- * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+ * network and a second to observe all networks. The latter is necessary
+ * while the expression of preferred upstreams remains a list of legacy
+ * connectivity types. In future, this can be revisited.
*
* The methods and data members of this class are only to be accessed and
* modified from the tethering master state machine thread. Any other
@@ -48,6 +50,10 @@ import java.util.HashMap;
*
* TODO: Move upstream selection logic here.
*
+ * All callback methods are run on the same thread as the specified target
+ * state machine. This class does not require locking when accessed from this
+ * thread. Access from other threads is not advised.
+ *
* @hide
*/
public class UpstreamNetworkMonitor {
@@ -60,15 +66,20 @@ public class UpstreamNetworkMonitor {
public static final int EVENT_ON_LINKPROPERTIES = 3;
public static final int EVENT_ON_LOST = 4;
+ private static final int CALLBACK_LISTEN_ALL = 1;
+ private static final int CALLBACK_TRACK_DEFAULT = 2;
+ private static final int CALLBACK_MOBILE_REQUEST = 3;
+
private final Context mContext;
private final StateMachine mTarget;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private ConnectivityManager mCM;
+ private NetworkCallback mListenAllCallback;
private NetworkCallback mDefaultNetworkCallback;
- private NetworkCallback mDunTetheringCallback;
private NetworkCallback mMobileNetworkCallback;
private boolean mDunRequired;
+ private Network mCurrentDefault;
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
mContext = ctx;
@@ -85,16 +96,13 @@ public class UpstreamNetworkMonitor {
public void start() {
stop();
- mDefaultNetworkCallback = new UpstreamNetworkCallback();
- cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
+ cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
- final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
- .build();
- mDunTetheringCallback = new UpstreamNetworkCallback();
- cm().registerNetworkCallback(dunTetheringRequest, mDunTetheringCallback);
+ mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
+ cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
}
public void stop() {
@@ -103,8 +111,8 @@ public class UpstreamNetworkMonitor {
releaseCallback(mDefaultNetworkCallback);
mDefaultNetworkCallback = null;
- releaseCallback(mDunTetheringCallback);
- mDunTetheringCallback = null;
+ releaseCallback(mListenAllCallback);
+ mListenAllCallback = null;
mNetworkMap.clear();
}
@@ -128,30 +136,25 @@ public class UpstreamNetworkMonitor {
return;
}
- final NetworkRequest.Builder builder = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- if (mDunRequired) {
- builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
- } else {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- }
- final NetworkRequest mobileUpstreamRequest = builder.build();
+ // The following use of the legacy type system cannot be removed until
+ // after upstream selection no longer finds networks by legacy type.
+ // See also http://b/34364553 .
+ final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
+
+ final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
+ .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
+ .build();
// The existing default network and DUN callbacks will be notified.
// Therefore, to avoid duplicate notifications, we only register a no-op.
- mMobileNetworkCallback = new NetworkCallback();
+ mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
// TODO: Change the timeout from 0 (no onUnavailable callback) to some
// moderate callback timeout. This might be useful for updating some UI.
// Additionally, we log a message to aid in any subsequent debugging.
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
- // The following use of the legacy type system cannot be removed until
- // after upstream selection no longer finds networks by legacy type.
- // See also b/34364553.
- final int apnType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
- cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, apnType);
+ cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType);
}
public void releaseMobileNetworkRequest() {
@@ -165,86 +168,118 @@ public class UpstreamNetworkMonitor {
return (network != null) ? mNetworkMap.get(network) : null;
}
- private void handleAvailable(Network network) {
- if (VDBG) {
- Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
- }
+ private void handleAvailable(int callbackType, Network network) {
+ if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
+
if (!mNetworkMap.containsKey(network)) {
mNetworkMap.put(network,
new NetworkState(null, null, null, network, null, null));
}
- final ConnectivityManager cm = cm();
-
- if (mDefaultNetworkCallback != null) {
- cm.requestNetworkCapabilities(mDefaultNetworkCallback);
- cm.requestLinkProperties(mDefaultNetworkCallback);
+ // Always request whatever extra information we can, in case this
+ // was already up when start() was called, in which case we would
+ // not have been notified of any information that had not changed.
+ switch (callbackType) {
+ case CALLBACK_LISTEN_ALL:
+ break;
+ case CALLBACK_TRACK_DEFAULT:
+ cm().requestNetworkCapabilities(mDefaultNetworkCallback);
+ cm().requestLinkProperties(mDefaultNetworkCallback);
+ mCurrentDefault = network;
+ break;
+ case CALLBACK_MOBILE_REQUEST:
+ cm().requestNetworkCapabilities(mMobileNetworkCallback);
+ cm().requestLinkProperties(mMobileNetworkCallback);
+ break;
}
- // Requesting updates for mDunTetheringCallback is not
- // necessary. Because it's a listen, it will already have
- // heard all NetworkCapabilities and LinkProperties updates
- // since UpstreamNetworkMonitor was started. Because we
- // start UpstreamNetworkMonitor before chooseUpstreamType()
- // is ever invoked (it can register a DUN request) this is
- // mostly safe. However, if a DUN network is already up for
- // some reason (unlikely, because DUN is restricted and,
- // unless the DUN network is shared with another APN, only
- // the system can request it and this is the only part of
- // the system that requests it) we won't know its
- // LinkProperties or NetworkCapabilities.
-
+ // Requesting updates for mListenAllCallback is not currently possible
+ // because it's a "listen". Two possible solutions to getting updates
+ // about networks without waiting for a change (which might never come)
+ // are:
+ //
+ // [1] extend request{NetworkCapabilities,LinkProperties}() to
+ // take a Network argument and have ConnectivityService do
+ // what's required (if the network satisfies the request)
+ //
+ // [2] explicitly file a NetworkRequest for each connectivity type
+ // listed as a preferred upstream and wait for these callbacks
+ // to be notified (requires tracking many more callbacks).
+ //
+ // Until this is addressed, networks that exist prior to the "listen"
+ // registration and which do not subsequently change will not cause
+ // us to learn their NetworkCapabilities nor their LinkProperties.
+
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_AVAILABLE, network);
}
private void handleNetCap(Network network, NetworkCapabilities newNc) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ final NetworkState prev = mNetworkMap.get(network);
+ if (prev == null || newNc.equals(prev.networkCapabilities)) {
+ // Ignore notifications about networks for which we have not yet
+ // received onAvailable() (should never happen) and any duplicate
+ // notifications (e.g. matching more than one of our callbacks).
return;
}
+
if (VDBG) {
Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
network, newNc));
}
- final NetworkState prev = mNetworkMap.get(network);
- mNetworkMap.put(network,
- new NetworkState(null, prev.linkProperties, newNc,
- network, null, null));
+ mNetworkMap.put(network, new NetworkState(
+ null, prev.linkProperties, newNc, network, null, null));
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_CAPABILITIES, network);
}
private void handleLinkProp(Network network, LinkProperties newLp) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ final NetworkState prev = mNetworkMap.get(network);
+ if (prev == null || newLp.equals(prev.linkProperties)) {
+ // Ignore notifications about networks for which we have not yet
+ // received onAvailable() (should never happen) and any duplicate
+ // notifications (e.g. matching more than one of our callbacks).
return;
}
+
if (VDBG) {
Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
network, newLp));
}
- final NetworkState prev = mNetworkMap.get(network);
- mNetworkMap.put(network,
- new NetworkState(null, newLp, prev.networkCapabilities,
- network, null, null));
+ mNetworkMap.put(network, new NetworkState(
+ null, newLp, prev.networkCapabilities, network, null, null));
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_LINKPROPERTIES, network);
}
- private void handleLost(Network network) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ private void handleLost(int callbackType, Network network) {
+ if (callbackType == CALLBACK_TRACK_DEFAULT) {
+ mCurrentDefault = null;
+ // Receiving onLost() for a default network does not necessarily
+ // mean the network is gone. We wait for a separate notification
+ // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
+ // clearing all state.
return;
}
- if (VDBG) {
- Log.d(TAG, "EVENT_ON_LOST for " + network);
+
+ if (!mNetworkMap.containsKey(network)) {
+ // Ignore loss of networks about which we had not previously
+ // learned any information or for which we have already processed
+ // an onLost() notification.
+ return;
}
+
+ if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
+
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target. Likewise,
+ // if the current upstream network is gone, notify the target of the
+ // fact that we now have no upstream at all.
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
}
@@ -261,9 +296,15 @@ public class UpstreamNetworkMonitor {
* tethering master state machine thread for subsequent processing.
*/
private class UpstreamNetworkCallback extends NetworkCallback {
+ private final int mCallbackType;
+
+ UpstreamNetworkCallback(int callbackType) {
+ mCallbackType = callbackType;
+ }
+
@Override
public void onAvailable(Network network) {
- mTarget.getHandler().post(() -> handleAvailable(network));
+ mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
}
@Override
@@ -278,7 +319,7 @@ public class UpstreamNetworkMonitor {
@Override
public void onLost(Network network) {
- mTarget.getHandler().post(() -> handleLost(network));
+ mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
}
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 3da49d8e13fb..168744b5652f 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -18,9 +18,6 @@ package com.android.server.display;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.twilight.TwilightListener;
-import com.android.server.twilight.TwilightManager;
-import com.android.server.twilight.TwilightState;
import android.annotation.Nullable;
import android.hardware.Sensor;
@@ -55,9 +52,6 @@ class AutomaticBrightnessController {
// non-zero, which in turn ensures that the total weight is non-zero.
private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
- // Specifies the maximum magnitude of the time of day adjustment.
- private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1f;
-
// Debounce for sampling user-initiated changes in display brightness to ensure
// the user is satisfied with the result before storing the sample.
private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
@@ -74,9 +68,6 @@ class AutomaticBrightnessController {
// The light sensor, or null if not available or needed.
private final Sensor mLightSensor;
- // The twilight service.
- private final TwilightManager mTwilight;
-
// The auto-brightness spline adjustment.
// The brightness values have been scaled to a range of 0..1.
private final Spline mScreenAutoBrightnessSpline;
@@ -186,8 +177,6 @@ class AutomaticBrightnessController {
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
- private boolean mUseTwilight;
-
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -196,7 +185,6 @@ class AutomaticBrightnessController {
int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
HysteresisLevels dynamicHysteresis) {
mCallbacks = callbacks;
- mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
mScreenAutoBrightnessSpline = autoBrightnessSpline;
mScreenBrightnessRangeMinimum = brightnessMin;
@@ -233,7 +221,7 @@ class AutomaticBrightnessController {
}
public void configure(boolean enable, float adjustment, boolean dozing,
- boolean userInitiatedChange, boolean useTwilight) {
+ boolean userInitiatedChange) {
// While dozing, the application processor may be suspended which will prevent us from
// receiving new information from the light sensor. On some devices, we may be able to
// switch to a wake-up light sensor instead but for now we will simply disable the sensor
@@ -242,7 +230,6 @@ class AutomaticBrightnessController {
mDozing = dozing;
boolean changed = setLightSensorEnabled(enable && !dozing);
changed |= setScreenAutoBrightnessAdjustment(adjustment);
- changed |= setUseTwilight(useTwilight);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
@@ -251,17 +238,6 @@ class AutomaticBrightnessController {
}
}
- private boolean setUseTwilight(boolean useTwilight) {
- if (mUseTwilight == useTwilight) return false;
- if (useTwilight) {
- mTwilight.registerListener(mTwilightListener, mHandler);
- } else {
- mTwilight.unregisterListener(mTwilightListener);
- }
- mUseTwilight = useTwilight;
- return true;
- }
-
public void dump(PrintWriter pw) {
pw.println();
pw.println("Automatic Brightness Controller Configuration:");
@@ -276,7 +252,6 @@ class AutomaticBrightnessController {
pw.println();
pw.println("Automatic Brightness Controller State:");
pw.println(" mLightSensor=" + mLightSensor);
- pw.println(" mTwilight.getLastTwilightState()=" + mTwilight.getLastTwilightState());
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
pw.println(" mAmbientLux=" + mAmbientLux);
@@ -522,19 +497,6 @@ class AutomaticBrightnessController {
}
}
- if (mUseTwilight) {
- TwilightState state = mTwilight.getLastTwilightState();
- if (state != null && state.isNight()) {
- final long duration = state.sunriseTimeMillis() - state.sunsetTimeMillis();
- final long progress = System.currentTimeMillis() - state.sunsetTimeMillis();
- final float amount = (float) Math.pow(2.0 * progress / duration - 1.0, 2.0);
- gamma *= 1 + amount * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
- if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: twilight amount=" + amount);
- }
- }
- }
-
if (gamma != 1.0f) {
final float in = value;
value = MathUtils.pow(value, gamma);
@@ -649,13 +611,6 @@ class AutomaticBrightnessController {
}
};
- private final TwilightListener mTwilightListener = new TwilightListener() {
- @Override
- public void onTwilightStateChanged(@Nullable TwilightState state) {
- updateAutoBrightness(true /*sendUpdate*/);
- }
- };
-
/** Callbacks to request updates to the display's power state. */
interface Callbacks {
void updateBrightness();
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 671918209b25..4a52b3ce5d95 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -93,6 +93,11 @@ final class DisplayDeviceInfo {
public static final int FLAG_ROUND = 1 << 8;
/**
+ * Flag: This display can show its content when non-secure keyguard is shown.
+ */
+ public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 9;
+
+ /**
* Touch attachment: Display does not receive touch.
*/
public static final int TOUCH_NONE = 0;
@@ -420,6 +425,9 @@ final class DisplayDeviceInfo {
if ((flags & FLAG_ROUND) != 0) {
msg.append(", FLAG_ROUND");
}
+ if ((flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
+ msg.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
+ }
return msg.toString();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index cd0779324194..fd89b9700714 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -16,13 +16,19 @@
package com.android.server.display;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
+import static android.hardware.display.DisplayManager
+ .VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+
import com.android.internal.util.IndentingPrintWriter;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.SensorManager;
-import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
@@ -1446,11 +1452,17 @@ public final class DisplayManagerService extends SystemService {
throw new IllegalArgumentException("Surface can't be single-buffered");
}
- if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
- flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+ if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+ flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+
+ // Public displays can't be allowed to show content when locked.
+ if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
+ throw new IllegalArgumentException(
+ "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE");
+ }
}
- if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
- flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+ if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+ flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
}
if (projection != null) {
@@ -1465,7 +1477,7 @@ public final class DisplayManagerService extends SystemService {
}
if (callingUid != Process.SYSTEM_UID &&
- (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+ (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
if (!canProjectVideo(projection)) {
throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+ "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
@@ -1473,7 +1485,7 @@ public final class DisplayManagerService extends SystemService {
+ "display.");
}
}
- if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+ if ((flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
if (!canProjectSecureVideo(projection)) {
throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+ "or an appropriate MediaProjection token to create a "
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 015345c23a1a..bed269cf6c4f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -642,7 +642,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
- userInitiatedChange, mPowerRequest.useTwilight);
+ userInitiatedChange);
}
// Apply brightness boost.
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 287a25aa9b3e..40a895210480 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -223,6 +223,9 @@ final class LogicalDisplay {
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROUND) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_ROUND;
}
+ if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
+ mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+ }
mBaseDisplayInfo.type = deviceInfo.type;
mBaseDisplayInfo.address = deviceInfo.address;
mBaseDisplayInfo.name = deviceInfo.name;
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 0357b1b42935..7237fdbc945e 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -111,7 +111,7 @@ public final class NightDisplayService extends SystemService
getLocalService(DisplayTransformManager.class);
if (enabled) {
dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_IDENTITY);
- } else if (mController.isActivated()) {
+ } else if (mController != null && mController.isActivated()) {
dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_NIGHT);
}
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 9d0fde5f2027..74e025d205b5 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -16,8 +16,14 @@
package com.android.server.display;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+import static android.hardware.display.DisplayManager
+ .VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
+
import android.content.Context;
-import android.hardware.display.DisplayManager;
import android.hardware.display.IVirtualDisplayCallback;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
@@ -63,7 +69,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int ownerUid, String ownerPackageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
- boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
+ boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
IBinder appToken = callback.asBinder();
IBinder displayToken = SurfaceControl.createDisplay(name, secure);
final String baseUniqueId =
@@ -308,23 +314,23 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.yDpi = mDensityDpi;
mInfo.presentationDeadlineNanos = 1000000000L / (int) REFRESH_RATE; // 1 frame
mInfo.flags = 0;
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
| DisplayDeviceInfo.FLAG_NEVER_BLANK;
}
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
} else {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
}
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
}
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
// For demonstration purposes, allow rotation of the external display.
// In the future we might allow the user to configure this directly.
if ("portrait".equals(SystemProperties.get(
@@ -333,6 +339,9 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
}
}
}
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+ }
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 997222ca876e..e83b228fefd4 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.os.Binder;
import android.os.Bundle;
@@ -41,6 +42,7 @@ import android.os.IHwBinder;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.security.KeyStore;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.SystemClock;
@@ -63,7 +65,6 @@ import org.json.JSONObject;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
-
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintService;
@@ -82,6 +83,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -109,6 +112,10 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
new ArrayList<>();
+ private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
+ new CopyOnWriteArrayList<>();
+ private final Map<Integer, Long> mAuthenticatorIds =
+ Collections.synchronizedMap(new HashMap<>());
private final AppOpsManager mAppOps;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -126,7 +133,6 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
private final UserManager mUserManager;
private ClientMonitor mCurrentClient;
private ClientMonitor mPendingClient;
- private long mCurrentAuthenticatorId;
private PerformanceStats mPerformanceStats;
// Normal fingerprint authentications are tracked by mPerformanceMap.
@@ -235,6 +241,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
if (mHalDeviceId != 0) {
+ loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
@@ -245,6 +252,26 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
return mDaemon;
}
+ /** Populates existing authenticator ids. To be used only during the start of the service. */
+ private void loadAuthenticatorIds() {
+ // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+ // background if it takes too long.
+ long t = System.currentTimeMillis();
+
+ mAuthenticatorIds.clear();
+ for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ int userId = getUserOrWorkProfileId(null, user.id);
+ if (!mAuthenticatorIds.containsKey(userId)) {
+ updateActiveGroup(userId, null);
+ }
+ }
+
+ t = System.currentTimeMillis() - t;
+ if (t > 1000) {
+ Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
+ }
+ }
+
protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid="
+ groupId + "rem=" + remaining);
@@ -276,8 +303,18 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
}
}
- protected void handleAuthenticated(long deviceId, int fingerId, int groupId) {
+ protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
+ ArrayList<Byte> token) {
ClientMonitor client = mCurrentClient;
+ if (fingerId != 0) {
+ // Ugh...
+ final byte[] byteToken = new byte[token.size()];
+ for (int i = 0; i < token.size(); i++) {
+ byteToken[i] = token.get(i);
+ }
+ // Send to Keystore
+ KeyStore.getInstance().addAuthToken(byteToken);
+ }
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
}
@@ -328,6 +365,9 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
mCurrentClient = null;
}
+ if (mPendingClient == null) {
+ notifyClientActiveCallbacks(false);
+ }
}
private boolean inLockoutMode() {
@@ -397,6 +437,8 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
+ newClient.getClass().getSuperclass().getSimpleName()
+ "(" + newClient.getOwnerString() + ")"
+ ", initiatedByClient = " + initiatedByClient + ")");
+ notifyClientActiveCallbacks(true);
+
newClient.start();
}
}
@@ -480,14 +522,23 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
boolean isCurrentUserOrProfile(int userId) {
UserManager um = UserManager.get(mContext);
+ if (um == null) {
+ Slog.e(TAG, "Unable to acquire UserManager");
+ return false;
+ }
- // Allow current user or profiles of the current user...
- for (int profileId : um.getEnabledProfileIds(userId)) {
- if (profileId == userId) {
- return true;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Allow current user or profiles of the current user...
+ for (int profileId : um.getEnabledProfileIds(mCurrentUserId)) {
+ if (profileId == userId) {
+ return true;
+ }
}
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- return false;
}
private boolean isForegroundActivity(int uid, int pid) {
@@ -568,6 +619,18 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
}
}
+ private void notifyClientActiveCallbacks(boolean isActive) {
+ List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
+ for (int i = 0; i < callbacks.size(); i++) {
+ try {
+ callbacks.get(i).onClientActiveChanged(isActive);
+ } catch (RemoteException re) {
+ // If the remote is dead, stop notifying it
+ mClientActiveCallbacks.remove(callbacks.get(i));
+ }
+ }
+ }
+
private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
IFingerprintServiceReceiver receiver, int flags, boolean restricted,
String opPackageName) {
@@ -721,11 +784,12 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
}
@Override
- public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) {
+ public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
+ ArrayList<Byte> token) {
mHandler.post(new Runnable() {
@Override
public void run() {
- handleAuthenticated(deviceId, fingerId, groupId);
+ handleAuthenticated(deviceId, fingerId, groupId, token);
}
});
}
@@ -1036,6 +1100,26 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
}
});
}
+
+ @Override
+ public boolean isClientActive() {
+ checkPermission(MANAGE_FINGERPRINT);
+ synchronized(FingerprintService.this) {
+ return (mCurrentClient != null) || (mPendingClient != null);
+ }
+ }
+
+ @Override
+ public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
+ checkPermission(MANAGE_FINGERPRINT);
+ mClientActiveCallbacks.add(callback);
+ }
+
+ @Override
+ public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
+ checkPermission(MANAGE_FINGERPRINT);
+ mClientActiveCallbacks.remove(callback);
+ }
}
private void dumpInternal(PrintWriter pw) {
@@ -1143,7 +1227,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
mCurrentUserId = userId;
}
- mCurrentAuthenticatorId = daemon.getAuthenticatorId();
+ mAuthenticatorIds.put(userId, daemon.getAuthenticatorId());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveGroup():", e);
}
@@ -1166,8 +1250,14 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
* @return true if this is a work profile
*/
private boolean isWorkProfile(int userId) {
- UserInfo info = mUserManager.getUserInfo(userId);
- return info != null && info.isManagedProfile();
+ UserInfo userInfo = null;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ userInfo = mUserManager.getUserInfo(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return userInfo != null && userInfo.isManagedProfile();
}
private void listenForUserSwitches() {
@@ -1187,9 +1277,11 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
/***
* @param opPackageName the name of the calling package
- * @return authenticator id for the current user
+ * @return authenticator id for the calling user
*/
public long getAuthenticatorId(String opPackageName) {
- return mCurrentAuthenticatorId;
+ final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+ Long authenticatorId = mAuthenticatorIds.get(userId);
+ return authenticatorId != null ? authenticatorId : 0;
}
}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index 19eed3536c2e..93c14b94d27e 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -152,7 +152,7 @@ public class IntentFirewall {
// component-filter that matches this intent
List<Rule> candidateRules;
candidateRules = resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/,
- false /*visibleToEphemeral*/, false /*isEphemeral*/, 0);
+ false /*visibleToEphemeral*/, false /*isInstant*/, 0);
if (candidateRules == null) {
candidateRules = new ArrayList<Rule>();
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index fbb393846c52..3793b911a038 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -84,6 +84,7 @@ import android.util.SparseArray;
import android.util.Xml;
import android.view.IInputFilter;
import android.view.IInputFilterHost;
+import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -180,6 +181,9 @@ public class InputManagerService extends IInputManager.Stub
IInputFilter mInputFilter; // guarded by mInputFilterLock
InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ private IWindow mFocusedWindow;
+ private boolean mFocusedWindowHasCapture;
+
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);
@@ -226,6 +230,7 @@ public class InputManagerService extends IInputManager.Stub
private static native void nativeSetPointerIconType(long ptr, int iconId);
private static native void nativeReloadPointerIcons(long ptr);
private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
+ private static native void nativeSetPointerCapture(long ptr, boolean detached);
// Input event injection constants defined in InputDispatcher.h.
private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -1503,7 +1508,16 @@ public class InputManagerService extends IInputManager.Stub
}
}
- public void setInputWindows(InputWindowHandle[] windowHandles) {
+ public void setInputWindows(InputWindowHandle[] windowHandles,
+ InputWindowHandle focusedWindowHandle) {
+ final IWindow newFocusedWindow =
+ focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
+ if (mFocusedWindow != newFocusedWindow) {
+ mFocusedWindow = newFocusedWindow;
+ if (mFocusedWindowHasCapture) {
+ setPointerCapture(false);
+ }
+ }
nativeSetInputWindows(mPtr, windowHandles);
}
@@ -1511,6 +1525,30 @@ public class InputManagerService extends IInputManager.Stub
nativeSetFocusedApplication(mPtr, application);
}
+ @Override
+ public void requestPointerCapture(IBinder windowToken, boolean enabled) {
+ if (mFocusedWindow == null || mFocusedWindow.asBinder() != windowToken) {
+ Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
+ + windowToken);
+ return;
+ }
+ if (mFocusedWindowHasCapture == enabled) {
+ Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
+ return;
+ }
+ setPointerCapture(enabled);
+ try {
+ mFocusedWindow.dispatchPointerCaptureChanged(enabled);
+ } catch (RemoteException ex) {
+ /* ignore */
+ }
+ }
+
+ private void setPointerCapture(boolean enabled) {
+ mFocusedWindowHasCapture = enabled;
+ nativeSetPointerCapture(mPtr, enabled);
+ }
+
public void setInputDispatchMode(boolean enabled, boolean frozen) {
nativeSetInputDispatchMode(mPtr, enabled, frozen);
}
diff --git a/services/core/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
index eb3581ad6dad..3d6f7ad16a7a 100644
--- a/services/core/java/com/android/server/input/InputWindowHandle.java
+++ b/services/core/java/com/android/server/input/InputWindowHandle.java
@@ -18,6 +18,7 @@ package com.android.server.input;
import android.graphics.Region;
import android.view.InputChannel;
+import android.view.IWindow;
/**
* Functions as a handle for a window that can receive input.
@@ -36,6 +37,9 @@ public final class InputWindowHandle {
// The window manager's window state.
public final Object windowState;
+ // The client window.
+ public final IWindow clientWindow;
+
// The input channel associated with the window.
public InputChannel inputChannel;
@@ -93,9 +97,10 @@ public final class InputWindowHandle {
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
- Object windowState, int displayId) {
+ Object windowState, IWindow clientWindow, int displayId) {
this.inputApplicationHandle = inputApplicationHandle;
this.windowState = windowState;
+ this.clientWindow = clientWindow;
this.displayId = displayId;
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index b089ba7ee9ed..7cb223dec5f3 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -70,6 +70,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
/** Amount of time a job is allowed to execute for before being considered timed-out. */
private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins.
+ /** Amount of time the JobScheduler waits for the initial service launch+bind. */
+ private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
/** Amount of time the JobScheduler will wait for a response from an app for a message. */
private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
@@ -645,8 +647,20 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private void scheduleOpTimeOut() {
removeOpTimeOut();
- final long timeoutMillis = (mVerb == VERB_EXECUTING) ?
- EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+ final long timeoutMillis;
+ switch (mVerb) {
+ case VERB_EXECUTING:
+ timeoutMillis = EXECUTING_TIMESLICE_MILLIS;
+ break;
+
+ case VERB_BINDING:
+ timeoutMillis = OP_BIND_TIMEOUT_MILLIS;
+ break;
+
+ default:
+ timeoutMillis = OP_TIMEOUT_MILLIS;
+ break;
+ }
if (DEBUG) {
Slog.d(TAG, "Scheduling time out for '" +
mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index eb8f8fc9af96..17b005d8c890 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -72,7 +72,6 @@ import android.os.WorkSource;
import android.provider.Settings;
import android.provider.Telephony.Carriers;
import android.provider.Telephony.Sms.Intents;
-import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
@@ -82,17 +81,17 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.NtpTrustedTime;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Map;
@@ -411,7 +410,6 @@ public class GnssLocationProvider implements LocationProviderInterface {
private WorkSource mClientSource = new WorkSource();
private GeofenceHardwareImpl mGeofenceHardwareImpl;
-
private int mYearOfHardware = 0;
// Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
@@ -1125,6 +1123,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
mGnssMeasurementsProvider.onGpsEnabledChanged();
mGnssNavigationMessageProvider.onGpsEnabledChanged();
+ enableBatching();
} else {
synchronized (mLock) {
mEnabled = false;
@@ -1156,6 +1155,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
mAlarmManager.cancel(mWakeupIntent);
mAlarmManager.cancel(mTimeoutIntent);
+ disableBatching();
// do this before releasing wakelock
native_cleanup();
@@ -1791,6 +1791,84 @@ public class GnssLocationProvider implements LocationProviderInterface {
};
}
+ public interface GnssBatchingProvider {
+ /**
+ * Returns the GNSS batching size
+ */
+ int getSize();
+ /**
+ * Starts the hardware batching operation
+ */
+ boolean start(long periodNanos, boolean wakeOnFifoFull);
+ /**
+ * Forces a flush of existing locations from the hardware batching
+ */
+ void flush();
+ /**
+ * Stops the batching operation
+ */
+ boolean stop();
+ }
+
+ /**
+ * @hide
+ */
+ public GnssBatchingProvider getGnssBatchingProvider() {
+ return new GnssBatchingProvider() {
+ @Override
+ public int getSize() {
+ return native_get_batch_size();
+ }
+ @Override
+ public boolean start(long periodNanos, boolean wakeOnFifoFull) {
+ if (periodNanos <= 0) {
+ Log.e(TAG, "Invalid periodNanos " + periodNanos +
+ "in batching request, not started");
+ return false;
+ }
+ return native_start_batch(periodNanos, wakeOnFifoFull);
+ }
+ @Override
+ public void flush() {
+ native_flush_batch();
+ }
+ @Override
+ public boolean stop() {
+ return native_stop_batch();
+ }
+ };
+ }
+
+ /**
+ * Initialize Batching if enabled
+ */
+ private void enableBatching() {
+ if (!native_init_batching()) {
+ Log.e(TAG, "Failed to initialize GNSS batching");
+ };
+ }
+
+ /**
+ * Disable batching
+ */
+ private void disableBatching() {
+ native_stop_batch();
+ native_cleanup_batching();
+ }
+
+ /**
+ * called from native code - GNSS location batch callback
+ */
+ private void reportLocationBatch(Location[] locationArray) {
+ List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
+ if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
+ try {
+ mILocationManager.reportLocationBatch(locations);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling reportLocationBatch");
+ }
+ }
+
/**
* called from native code to request XTRA data
*/
@@ -2117,7 +2195,10 @@ public class GnssLocationProvider implements LocationProviderInterface {
// note that this assumes the message will not be removed from the queue before
// it is handled (otherwise the wake lock would be leaked).
mWakeLock.acquire();
- Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
+ if (Log.isLoggable(TAG, Log.INFO)) {
+ Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
+ + ", " + obj + ")");
+ }
mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
}
@@ -2175,8 +2256,10 @@ public class GnssLocationProvider implements LocationProviderInterface {
if (msg.arg2 == 1) {
// wakelock was taken for this message, release it
mWakeLock.release();
- Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
- + msg.obj + ")");
+ if (Log.isLoggable(TAG, Log.INFO)) {
+ Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
+ + ", " + msg.arg1 + ", " + msg.obj + ")");
+ }
}
}
@@ -2424,6 +2507,40 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
}
+ /**
+ * @return A string representing the given message ID.
+ */
+ private String messageIdAsString(int message) {
+ switch (message) {
+ case ENABLE:
+ return "ENABLE";
+ case SET_REQUEST:
+ return "SET_REQUEST";
+ case UPDATE_NETWORK_STATE:
+ return "UPDATE_NETWORK_STATE";
+ case REQUEST_SUPL_CONNECTION:
+ return "REQUEST_SUPL_CONNECTION";
+ case RELEASE_SUPL_CONNECTION:
+ return "RELEASE_SUPL_CONNECTION";
+ case INJECT_NTP_TIME:
+ return "INJECT_NTP_TIME";
+ case DOWNLOAD_XTRA_DATA:
+ return "DOWNLOAD_XTRA_DATA";
+ case INJECT_NTP_TIME_FINISHED:
+ return "INJECT_NTP_TIME_FINISHED";
+ case DOWNLOAD_XTRA_DATA_FINISHED:
+ return "DOWNLOAD_XTRA_DATA_FINISHED";
+ case UPDATE_LOCATION:
+ return "UPDATE_LOCATION";
+ case SUBSCRIPTION_OR_SIM_CHANGED:
+ return "SUBSCRIPTION_OR_SIM_CHANGED";
+ case INITIALIZE_HANDLER:
+ return "INITIALIZE_HANDLER";
+ default:
+ return "<Unknown>";
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
@@ -2441,7 +2558,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
s.append(")\n");
- s.append(native_get_internal_state());
+ s.append(" internal state: ").append(native_get_internal_state());
+ s.append("\n");
+
pw.append(s);
}
@@ -2562,4 +2681,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
private static native boolean native_set_gps_lock(int gpsLock);
private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
+ // GNSS 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/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ede6e30becd3..10ecb867e8f0 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1123,6 +1123,38 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void addQueueItem(MediaDescription description) {
+ try {
+ mCb.onAddQueueItem(description);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in addQueueItem.", e);
+ }
+ }
+
+ public void addQueueItemAt(MediaDescription description, int index) {
+ try {
+ mCb.onAddQueueItemAt(description, index);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in addQueueItemAt.", e);
+ }
+ }
+
+ public void removeQueueItem(MediaDescription description) {
+ try {
+ mCb.onRemoveQueueItem(description);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in removeQueueItem.", e);
+ }
+ }
+
+ public void removeQueueItemAt(int index) {
+ try {
+ mCb.onRemoveQueueItemAt(index);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in removeQueueItem.", e);
+ }
+ }
+
public void adjustVolume(int direction) {
try {
mCb.onAdjustVolume(direction);
@@ -1397,6 +1429,30 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void addQueueItem(MediaDescription description) {
+ updateCallingPackage();
+ mSessionCb.addQueueItem(description);
+ }
+
+ @Override
+ public void addQueueItemAt(MediaDescription description, int index) {
+ updateCallingPackage();
+ mSessionCb.addQueueItemAt(description, index);
+ }
+
+ @Override
+ public void removeQueueItem(MediaDescription description) {
+ updateCallingPackage();
+ mSessionCb.removeQueueItem(description);
+ }
+
+ @Override
+ public void removeQueueItemAt(int index) {
+ updateCallingPackage();
+ mSessionCb.removeQueueItemAt(index);
+ }
+
+ @Override
public CharSequence getQueueTitle() {
return mQueueTitle;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9b37f12e468a..98177feef85b 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,6 +17,7 @@
package com.android.server.media;
import android.Manifest;
+import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.KeyguardManager;
@@ -36,10 +37,13 @@ import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
+import android.media.session.IOnMediaKeyListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -78,10 +82,11 @@ import java.util.List;
public class MediaSessionService extends SystemService implements Monitor {
private static final String TAG = "MediaSessionService";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- // Leave log for media key event always.
- private static final boolean DEBUG_MEDIA_KEY_EVENT = DEBUG || true;
+ // Leave log for key event always.
+ private static final boolean DEBUG_KEY_EVENT = true;
private static final int WAKELOCK_TIMEOUT = 5000;
+ private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
/* package */final IBinder mICallback = new Binder();
@@ -150,10 +155,10 @@ public class MediaSessionService extends SystemService implements Monitor {
}
/**
- * Tells the system UI that volume has changed on a remote session.
+ * Tells the system UI that volume has changed on an active remote session.
*/
public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
- if (mRvc == null) {
+ if (mRvc == null || !session.isActive()) {
return;
}
try {
@@ -523,6 +528,14 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ private String getCallingPackageName(int uid) {
+ String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ return packages[0];
+ }
+ return "";
+ }
+
/**
* Information about a particular user. The contents of this object is
* guarded by mLock.
@@ -534,6 +547,15 @@ public class MediaSessionService extends SystemService implements Monitor {
private PendingIntent mLastMediaButtonReceiver;
private ComponentName mRestoredMediaButtonReceiver;
+ private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
+ private int mOnVolumeKeyLongPressListenerUid;
+ private KeyEvent mInitialDownVolumeKeyEvent;
+ private int mInitialDownVolumeStream;
+ private boolean mInitialDownMusicOnly;
+
+ private IOnMediaKeyListener mOnMediaKeyListener;
+ private int mOnMediaKeyListenerUid;
+
public UserRecord(Context context, int userId) {
mContext = context;
mUserId = userId;
@@ -564,6 +586,12 @@ public class MediaSessionService extends SystemService implements Monitor {
String indent = prefix + " ";
pw.println(indent + "MediaButtonReceiver:" + mLastMediaButtonReceiver);
pw.println(indent + "Restored ButtonReceiver:" + mRestoredMediaButtonReceiver);
+ pw.println(indent + "Volume key long-press listener:" + mOnVolumeKeyLongPressListener);
+ pw.println(indent + "Volume key long-press listener package:" +
+ getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
+ pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
+ pw.println(indent + "Media key listener package: " +
+ getCallingPackageName(mOnMediaKeyListenerUid));
int size = mSessions.size();
pw.println(indent + size + " Sessions:");
for (int i = 0; i < size; i++) {
@@ -769,28 +797,190 @@ public class MediaSessionService extends SystemService implements Monitor {
}
synchronized (mLock) {
- // If we don't have a media button receiver to fall back on
- // include non-playing sessions for dispatching
- boolean useNotPlayingSessions = true;
- for (int userId : mCurrentUserIdList) {
- UserRecord ur = mUserRecords.get(userId);
- if (ur.mLastMediaButtonReceiver != null
- || ur.mRestoredMediaButtonReceiver != null) {
- useNotPlayingSessions = false;
- break;
+ if (!isGlobalPriorityActive() && isVoiceKey(keyEvent.getKeyCode())) {
+ handleVoiceKeyEventLocked(keyEvent, needWakeLock);
+ } else {
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock, true);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
+ if (getContext().checkPermission(
+ android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER" +
+ " permission.");
+ }
+
+ synchronized (mLock) {
+ UserRecord user = mUserRecords.get(UserHandle.getUserId(uid));
+ if (user.mOnVolumeKeyLongPressListener != null &&
+ user.mOnVolumeKeyLongPressListenerUid != uid) {
+ Log.w(TAG, "Volume key long-press listener cannot be reset by another app");
+ return;
+ }
+
+ user.mOnVolumeKeyLongPressListener = listener;
+ user.mOnVolumeKeyLongPressListenerUid = uid;
+
+ Log.d(TAG, "Volume key long-press listener "
+ + listener + " is set by " + getCallingPackageName(uid));
+
+ if (user.mOnVolumeKeyLongPressListener != null) {
+ try {
+ user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ user.mOnVolumeKeyLongPressListener = null;
+ }
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set death recipient "
+ + user.mOnVolumeKeyLongPressListener);
+ user.mOnVolumeKeyLongPressListener = null;
}
}
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
- if (DEBUG) {
- Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
- + useNotPlayingSessions);
+ @Override
+ public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Enforce SET_MEDIA_KEY_LISTENER permission.
+ if (getContext().checkPermission(
+ android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER" +
+ " permission.");
+ }
+
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ UserRecord user = mUserRecords.get(userId);
+ if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
+ Log.w(TAG, "Media key listener cannot be reset by another app");
+ return;
+ }
+
+ user.mOnMediaKeyListener = listener;
+ user.mOnMediaKeyListenerUid = uid;
+
+ Log.d(TAG, "Media key listener " + user.mOnMediaKeyListener
+ + " is set by " + getCallingPackageName(uid));
+
+ if (user.mOnMediaKeyListener != null) {
+ try {
+ user.mOnMediaKeyListener.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ user.mOnMediaKeyListener = null;
+ }
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
+ user.mOnMediaKeyListener = null;
+ }
}
- MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
- mCurrentUserIdList, useNotPlayingSessions);
- if (isVoiceKey(keyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(keyEvent, needWakeLock, session);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Handles the dispatching of the volume button events to one of the
+ * registered listeners. If there's a volume key long-press listener and
+ * there's no active global priority session, long-pressess will be sent to the
+ * long-press listener instead of adjusting volume.
+ *
+ * @param keyEvent a non-null KeyEvent whose key code is one of the
+ * {@link KeyEvent#KEYCODE_VOLUME_UP},
+ * {@link KeyEvent#KEYCODE_VOLUME_DOWN},
+ * or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
+ * @param stream stream type to adjust volume.
+ * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
+ */
+ @Override
+ public void dispatchVolumeKeyEvent(KeyEvent keyEvent, int stream, boolean musicOnly) {
+ if (keyEvent == null ||
+ (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
+ && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
+ && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+ Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
+ return;
+ }
+
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ if (DEBUG) {
+ Log.d(TAG, "dispatchVolumeKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+ + keyEvent);
+ }
+
+ try {
+ synchronized (mLock) {
+ // Only consider full user.
+ UserRecord user = mUserRecords.get(mCurrentUserIdList.get(0));
+
+ if (mPriorityStack.isGlobalPriorityActive()
+ || user.mOnVolumeKeyLongPressListener == null) {
+ dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
} else {
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+ // TODO: Consider the case when both volume up and down keys are pressed
+ // at the same time.
+ if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+ if (keyEvent.getRepeatCount() == 0) {
+ user.mInitialDownVolumeKeyEvent = keyEvent;
+ user.mInitialDownVolumeStream = stream;
+ user.mInitialDownMusicOnly = musicOnly;
+ }
+ if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
+ if (user.mInitialDownVolumeKeyEvent != null) {
+ dispatchVolumeKeyLongPressLocked(
+ user.mInitialDownVolumeKeyEvent);
+ // Mark that the key is already handled.
+ user.mInitialDownVolumeKeyEvent = null;
+ }
+ dispatchVolumeKeyLongPressLocked(keyEvent);
+ }
+ } else { // if up
+ if (user.mInitialDownVolumeKeyEvent != null
+ && user.mInitialDownVolumeKeyEvent.getDownTime()
+ == keyEvent.getDownTime()) {
+ // Short-press. Should change volume.
+ dispatchVolumeKeyEventLocked(
+ user.mInitialDownVolumeKeyEvent,
+ user.mInitialDownVolumeStream,
+ user.mInitialDownMusicOnly);
+ dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
+ } else {
+ dispatchVolumeKeyLongPressLocked(keyEvent);
+ }
+ }
}
}
} finally {
@@ -798,14 +988,66 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
+ // Only consider full user.
+ UserRecord user = mUserRecords.get(mCurrentUserIdList.get(0));
+ try {
+ user.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
+ }
+ }
+
+ private void dispatchVolumeKeyEventLocked(
+ KeyEvent keyEvent, int stream, boolean musicOnly) {
+ boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+ boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
+ int direction = 0;
+ boolean isMute = false;
+ switch (keyEvent.getKeyCode()) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ direction = AudioManager.ADJUST_RAISE;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ direction = AudioManager.ADJUST_LOWER;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ isMute = true;
+ break;
+ }
+ if (down || up) {
+ int flags = AudioManager.FLAG_FROM_KEY;
+ if (musicOnly) {
+ // This flag is used when the screen is off to only affect active media.
+ flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
+ } else {
+ // These flags are consistent with the home screen
+ if (up) {
+ flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
+ } else {
+ flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
+ }
+ }
+ if (direction != 0) {
+ // If this is action up we want to send a beep for non-music events
+ if (up) {
+ direction = 0;
+ }
+ dispatchAdjustVolumeLocked(stream, direction, flags);
+ } else if (isMute) {
+ if (down && keyEvent.getRepeatCount() == 0) {
+ dispatchAdjustVolumeLocked(stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+ }
+ }
+ }
+ }
+
@Override
public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- MediaSessionRecord session = mPriorityStack
- .getDefaultVolumeSession(mCurrentUserIdList);
- dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
+ dispatchAdjustVolumeLocked(suggestedStream, delta, flags);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -881,8 +1123,9 @@ public class MediaSessionService extends SystemService implements Monitor {
return resolvedUserId;
}
- private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
- MediaSessionRecord session) {
+ private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags) {
+ MediaSessionRecord session = mPriorityStack.getDefaultVolumeSession(mCurrentUserIdList);
+
boolean preferSuggestedStream = false;
if (isValidLocalStreamType(suggestedStream)
&& AudioSystem.isStreamActive(suggestedStream, 0)) {
@@ -925,13 +1168,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
- MediaSessionRecord session) {
- if (session != null && session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
- // If the phone app has priority just give it the event
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
- return;
- }
+ private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
int action = keyEvent.getAction();
boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
if (action == KeyEvent.ACTION_DOWN) {
@@ -948,24 +1185,60 @@ public class MediaSessionService extends SystemService implements Monitor {
if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
// Resend the down then send this event through
KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(downEvent, needWakeLock, session);
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+ dispatchMediaKeyEventLocked(downEvent, needWakeLock, true);
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock, true);
}
}
}
}
private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
- MediaSessionRecord session) {
+ boolean checkMediaKeyListener) {
+ // If we don't have a media button receiver to fall back on
+ // include non-playing sessions for dispatching.
+ boolean useNotPlayingSessions = true;
+ for (int userId : mCurrentUserIdList) {
+ UserRecord ur = mUserRecords.get(userId);
+ if (ur.mLastMediaButtonReceiver != null
+ || ur.mRestoredMediaButtonReceiver != null) {
+ useNotPlayingSessions = false;
+ break;
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
+ + useNotPlayingSessions);
+ }
+
+ MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
+ mCurrentUserIdList, useNotPlayingSessions);
+
+ if ((session == null
+ || !session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY))
+ && checkMediaKeyListener) {
+ // Only consider full user.
+ UserRecord user = mUserRecords.get(mCurrentUserIdList.get(0));
+ if (user.mOnMediaKeyListener != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Send " + keyEvent + " to media key listener");
+ }
+ try {
+ user.mOnMediaKeyListener.onMediaKey(keyEvent,
+ new MediaKeyListenerResultReceiver(keyEvent, needWakeLock));
+ return;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send " + keyEvent + " to media key listener");
+ }
+ }
+ }
if (session != null) {
- if (DEBUG_MEDIA_KEY_EVENT) {
+ if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
}
if (needWakeLock) {
mKeyEventReceiver.aquireWakeLockLocked();
}
- // If we don't need a wakelock use -1 as the id so we
- // won't release it later
+ // If we don't need a wakelock use -1 as the id so we won't release it later.
session.sendMediaButton(keyEvent,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mKeyEventReceiver, Process.SYSTEM_UID,
@@ -986,7 +1259,7 @@ public class MediaSessionService extends SystemService implements Monitor {
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
if (user.mLastMediaButtonReceiver != null) {
- if (DEBUG_MEDIA_KEY_EVENT) {
+ if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent
+ " to the last known pendingIntent "
+ user.mLastMediaButtonReceiver);
@@ -995,7 +1268,7 @@ public class MediaSessionService extends SystemService implements Monitor {
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mediaButtonIntent, mKeyEventReceiver, mHandler);
} else {
- if (DEBUG_MEDIA_KEY_EVENT) {
+ if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+ user.mRestoredMediaButtonReceiver);
}
@@ -1081,6 +1354,46 @@ public class MediaSessionService extends SystemService implements Monitor {
&& streamType <= AudioManager.STREAM_NOTIFICATION;
}
+ private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
+ private KeyEvent mKeyEvent;
+ private boolean mNeedWakeLock;
+ private boolean mHandled;
+
+ private MediaKeyListenerResultReceiver(KeyEvent keyEvent, boolean needWakeLock) {
+ super(mHandler);
+ mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+ mKeyEvent = keyEvent;
+ mNeedWakeLock = needWakeLock;
+ }
+
+ @Override
+ public void run() {
+ Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
+ dispatchMediaKeyEvent();
+ }
+
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
+ mHandled = true;
+ mHandler.removeCallbacks(this);
+ return;
+ }
+ dispatchMediaKeyEvent();
+ }
+
+ private void dispatchMediaKeyEvent() {
+ if (mHandled) {
+ return;
+ }
+ mHandled = true;
+ mHandler.removeCallbacks(this);
+ synchronized (mLock) {
+ dispatchMediaKeyEventLocked(mKeyEvent, mNeedWakeLock, false);
+ }
+ }
+ }
+
private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 1e0035d65939..d6c89a41dc32 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -30,7 +30,8 @@ import android.provider.Settings;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.Slog;
+
+import com.android.internal.util.NotificationMessagingUtil;
import java.util.Comparator;
import java.util.Objects;
@@ -41,23 +42,28 @@ import java.util.Objects;
public class NotificationComparator
implements Comparator<NotificationRecord> {
- private final String DEFAULT_SMS_APP_SETTING = Settings.Secure.SMS_DEFAULT_APPLICATION;
-
private final Context mContext;
+ private final NotificationMessagingUtil mMessagingUtil;
private String mDefaultPhoneApp;
- private ArrayMap<Integer, String> mDefaultSmsApp = new ArrayMap<>();
public NotificationComparator(Context context) {
mContext = context;
mContext.registerReceiver(mPhoneAppBroadcastReceiver,
new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver);
+ mMessagingUtil = new NotificationMessagingUtil(mContext);
}
@Override
public int compare(NotificationRecord left, NotificationRecord right) {
- // First up: sufficiently important ongoing notifications of certain categories
+ // first all colorized notifications
+ boolean leftImportantColorized = isImportantColorized(left);
+ boolean rightImportantColorized = isImportantColorized(right);
+
+ if (leftImportantColorized != rightImportantColorized) {
+ return -1 * Boolean.compare(leftImportantColorized, rightImportantColorized);
+ }
+
+ // sufficiently important ongoing notifications of certain categories
boolean leftImportantOngoing = isImportantOngoing(left);
boolean rightImportantOngoing = isImportantOngoing(right);
@@ -66,9 +72,15 @@ public class NotificationComparator
return -1 * Boolean.compare(leftImportantOngoing, rightImportantOngoing);
}
+ boolean leftMessaging = isImportantMessaging(left);
+ boolean rightMessaging = isImportantMessaging(right);
+ if (leftMessaging != rightMessaging) {
+ return -1 * Boolean.compare(leftMessaging, rightMessaging);
+ }
+
// Next: sufficiently import person to person communication
- boolean leftPeople = isImportantMessaging(left);
- boolean rightPeople = isImportantMessaging(right);
+ boolean leftPeople = isImportantPeople(left);
+ boolean rightPeople = isImportantPeople(right);
if (leftPeople && rightPeople){
// by contact proximity, close to far. if same proximity, check further fields.
@@ -106,6 +118,13 @@ public class NotificationComparator
return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs());
}
+ private boolean isImportantColorized(NotificationRecord record) {
+ if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
+ return false;
+ }
+ return record.getNotification().isColorized();
+ }
+
private boolean isImportantOngoing(NotificationRecord record) {
if (!isOngoing(record)) {
return false;
@@ -114,54 +133,33 @@ public class NotificationComparator
if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
return false;
}
-
// TODO: add whitelist
return isCall(record) || isMediaNotification(record);
}
- protected boolean isImportantMessaging(NotificationRecord record) {
+ protected boolean isImportantPeople(NotificationRecord record) {
if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
return false;
}
-
- Class<? extends Notification.Style> style = getNotificationStyle(record);
- if (Notification.MessagingStyle.class.equals(style)) {
- return true;
- }
-
if (record.getContactAffinity() > ValidateNotificationPeople.NONE) {
return true;
}
-
- if (record.getNotification().category == Notification.CATEGORY_MESSAGE
- && isDefaultMessagingApp(record)) {
- return true;
- }
-
return false;
}
+ protected boolean isImportantMessaging(NotificationRecord record) {
+ return mMessagingUtil.isImportantMessaging(record.sbn, record.getImportance());
+ }
+
private boolean isOngoing(NotificationRecord record) {
final int ongoingFlags =
Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_ONGOING_EVENT;
return (record.getNotification().flags & ongoingFlags) != 0;
}
-
- private Class<? extends Notification.Style> getNotificationStyle(NotificationRecord record) {
- String templateClass =
- record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE);
-
- if (!TextUtils.isEmpty(templateClass)) {
- return Notification.getNotificationStyleClass(templateClass);
- }
- return null;
- }
-
private boolean isMediaNotification(NotificationRecord record) {
- return record.getNotification().extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION) != null;
+ return record.getNotification().hasMediaSession();
}
private boolean isCall(NotificationRecord record) {
@@ -178,18 +176,6 @@ public class NotificationComparator
return Objects.equals(pkg, mDefaultPhoneApp);
}
- @SuppressWarnings("deprecation")
- private boolean isDefaultMessagingApp(NotificationRecord record) {
- final int userId = record.getUserId();
- if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
- if (mDefaultSmsApp.get(userId) == null) {
- mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId));
- }
- return Objects.equals(mDefaultSmsApp.get(userId), record.sbn.getPackageName());
- }
-
private final BroadcastReceiver mPhoneAppBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -197,17 +183,4 @@ public class NotificationComparator
intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
}
};
-
- private final ContentObserver mSmsContentObserver = new ContentObserver(
- new Handler(Looper.getMainLooper())) {
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
- mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId));
-
- }
- }
- };
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 96459be9234a..32c98a1c2545 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -17,6 +17,8 @@
package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
@@ -32,6 +34,7 @@ import static android.service.notification.NotificationListenerService.REASON_PA
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
+import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
@@ -50,9 +53,11 @@ import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.NotificationChannelGroup;
import android.app.backup.BackupManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
@@ -83,6 +88,7 @@ import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.IRingtonePlayer;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -109,6 +115,9 @@ import android.service.notification.IStatusBarNotificationHolder;
import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
+import android.service.notification.NotificationRecordProto;
+import android.service.notification.NotificationServiceDumpProto;
+import android.service.notification.NotificationServiceProto;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
@@ -122,6 +131,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -129,6 +139,8 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -165,6 +177,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -229,6 +242,12 @@ public class NotificationManagerService extends SystemService {
private static final long DELAY_FOR_ASSISTANT_TIME = 100;
+ private static final String ACTION_NOTIFICATION_TIMEOUT =
+ NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
+ private static final int REQUEST_CODE_TIMEOUT = 1;
+ private static final String SCHEME_TIMEOUT = "timeout";
+ private static final String EXTRA_KEY = "key";
+
private IActivityManager mAm;
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
@@ -237,6 +256,7 @@ public class NotificationManagerService extends SystemService {
@Nullable StatusBarManagerInternal mStatusBar;
Vibrator mVibrator;
private WindowManagerInternal mWindowManagerInternal;
+ private AlarmManager mAlarmManager;
final IBinder mForegroundToken = new Binder();
private Handler mHandler;
@@ -245,10 +265,6 @@ public class NotificationManagerService extends SystemService {
private Light mNotificationLight;
Light mAttentionLight;
- private int mDefaultNotificationColor;
- private int mDefaultNotificationLedOn;
-
- private int mDefaultNotificationLedOff;
private long[] mFallbackVibrationPattern;
private boolean mUseAttentionLight;
@@ -314,6 +330,7 @@ public class NotificationManagerService extends SystemService {
private SnoozeHelper mSnoozeHelper;
private GroupHelper mGroupHelper;
+ private boolean mIsTelevision;
private static class Archive {
final int mBufferSize;
@@ -538,6 +555,9 @@ public class NotificationManagerService extends SystemService {
return;
}
final long now = System.currentTimeMillis();
+ MetricsLogger.action(r.getLogMaker(now)
+ .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+ .setType(MetricsEvent.TYPE_ACTION));
EventLogTags.writeNotificationClicked(key,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
@@ -559,6 +579,10 @@ public class NotificationManagerService extends SystemService {
return;
}
final long now = System.currentTimeMillis();
+ MetricsLogger.action(r.getLogMaker(now)
+ .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(actionIndex));
EventLogTags.writeNotificationActionClicked(key, actionIndex,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
// TODO: Log action click via UsageStats.
@@ -575,6 +599,8 @@ public class NotificationManagerService extends SystemService {
@Override
public void onPanelRevealed(boolean clearEffects, int items) {
+ MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
+ MetricsLogger.histogram(getContext(), "notification_load", items);
EventLogTags.writeNotificationPanelRevealed(items);
if (clearEffects) {
clearEffects();
@@ -583,6 +609,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void onPanelHidden() {
+ MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
EventLogTags.writeNotificationPanelHidden();
}
@@ -644,6 +671,9 @@ public class NotificationManagerService extends SystemService {
if (r != null) {
r.stats.onExpansionChanged(userAction, expanded);
final long now = System.currentTimeMillis();
+ MetricsLogger.action(r.getLogMaker(now)
+ .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+ .setType(MetricsEvent.TYPE_DETAIL));
EventLogTags.writeNotificationExpansion(key,
userAction ? 1 : 0, expanded ? 1 : 0,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
@@ -682,6 +712,29 @@ public class NotificationManagerService extends SystemService {
updateLightsLocked();
}
+ private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
+ final NotificationRecord record;
+ synchronized (mNotificationLock) {
+ record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
+ }
+ if (record != null) {
+ cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
+ record.sbn.getPackageName(), record.sbn.getTag(),
+ record.sbn.getId(), 0,
+ Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
+ REASON_TIMEOUT, null);
+ }
+ }
+ }
+ };
+
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -801,9 +854,6 @@ public class NotificationManagerService extends SystemService {
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
// turn off LED when user passes through lock screen
mNotificationLight.turnOff();
- if (mStatusBar != null) {
- mStatusBar.notificationLightOff();
- }
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
// reload per-user settings
@@ -872,15 +922,6 @@ public class NotificationManagerService extends SystemService {
private SettingsObserver mSettingsObserver;
private ZenModeHelper mZenModeHelper;
- private final Runnable mBuzzBeepBlinked = new Runnable() {
- @Override
- public void run() {
- if (mStatusBar != null) {
- mStatusBar.buzzBeepBlinked();
- }
- }
- };
-
static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
int[] ar = r.getIntArray(resid);
if (ar == null) {
@@ -910,14 +951,10 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
- void setStatusBarManager(StatusBarManagerInternal statusBar) {
- mStatusBar = statusBar;
- }
-
- @VisibleForTesting
void setLights(Light light) {
mNotificationLight = light;
mAttentionLight = light;
+ mNotificationPulseEnabled = true;
}
@VisibleForTesting
@@ -951,6 +988,16 @@ public class NotificationManagerService extends SystemService {
mPackageManager = packageManager;
}
+ @VisibleForTesting
+ void setRankingHelper(RankingHelper rankingHelper) {
+ mRankingHelper = rankingHelper;
+ }
+
+ @VisibleForTesting
+ void setIsTelevision(boolean isTelevision) {
+ mIsTelevision = isTelevision;
+ }
+
// TODO: Tests should call onStart instead once the methods above are removed.
@VisibleForTesting
void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
@@ -966,6 +1013,7 @@ public class NotificationManagerService extends SystemService {
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mHandler = new WorkerHandler(looper);
mRankingThread.start();
@@ -1071,13 +1119,6 @@ public class NotificationManagerService extends SystemService {
mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
- mDefaultNotificationColor = resources.getColor(
- R.color.config_defaultNotificationColor);
- mDefaultNotificationLedOn = resources.getInteger(
- R.integer.config_defaultNotificationLedOn);
- mDefaultNotificationLedOff = resources.getInteger(
- R.integer.config_defaultNotificationLedOff);
-
mFallbackVibrationPattern = getLongArray(resources,
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
@@ -1132,10 +1173,17 @@ public class NotificationManagerService extends SystemService {
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
null);
+ IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
+ timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
+ getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
+
mSettingsObserver = new SettingsObserver(mHandler);
mArchive = new Archive(resources.getInteger(
R.integer.config_notificationServiceArchiveSize));
+
+ mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
+ || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
}
@Override
@@ -1563,6 +1611,21 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void createNotificationChannelGroups(String pkg,
+ ParceledListSlice channelGroupList) throws RemoteException {
+ checkCallerIsSystemOrSameApp(pkg);
+ List<NotificationChannelGroup> groups = channelGroupList.getList();
+ final int groupSize = groups.size();
+ for (int i = 0; i < groupSize; i++) {
+ final NotificationChannelGroup group = groups.get(i);
+ Preconditions.checkNotNull(group, "group in list is null");
+ mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
+ true /* fromTargetApp */);
+ }
+ savePolicyFile();
+ }
+
+ @Override
public void createNotificationChannels(String pkg,
ParceledListSlice channelsList) throws RemoteException {
checkCallerIsSystemOrSameApp(pkg);
@@ -1620,6 +1683,13 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
+ String pkg, int uid, boolean includeDeleted) {
+ checkCallerIsSystem();
+ return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
+ }
+
+ @Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
return mRankingHelper.getNotificationChannels(
@@ -1683,6 +1753,9 @@ public class NotificationManagerService extends SystemService {
/**
* Public API for getting a list of current notifications for the calling package/uid.
*
+ * Note that since notification posting is done asynchronously, this will not return
+ * notifications that are in the process of being posted.
+ *
* @returns A list of all the package's notifications, in natural order.
*/
@Override
@@ -1944,31 +2017,16 @@ public class NotificationManagerService extends SystemService {
}
/**
- * Allow an INotificationListener to snooze a single notification.
+ * Allows the notification assistant to un-snooze a single notification.
*
- * @param token The binder for the listener, to check that the caller is allowed
+ * @param token The binder for the assistant, to check that the caller is allowed
*/
@Override
- public void snoozeNotificationFromListener(INotificationListener token, String key) {
+ public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
long identity = Binder.clearCallingIdentity();
try {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, null, info);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
- * Allow an INotificationListener to un-snooze a single notification.
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- @Override
- public void unsnoozeNotificationFromListener(INotificationListener token, String key) {
- long identity = Binder.clearCallingIdentity();
- try {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ final ManagedServiceInfo info =
+ mNotificationAssistants.checkServiceTokenLocked(token);
unsnoozeNotificationInt(key, info);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2039,6 +2097,36 @@ public class NotificationManagerService extends SystemService {
}
}
+ /**
+ * Allow an INotificationListener to request the list of outstanding snoozed notifications
+ * seen by the current user. Useful when starting up, after which point the listener
+ * callbacks should be used.
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ * @returns The return value will contain the notifications specified in keys, in that
+ * order, or if keys is null, all the notifications, in natural order.
+ */
+ @Override
+ public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
+ INotificationListener token, int trim) {
+ synchronized (mNotificationLock) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
+ final int N = snoozedRecords.size();
+ final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
+ for (int i=0; i < N; i++) {
+ final NotificationRecord r = snoozedRecords.get(i);
+ if (r == null) continue;
+ StatusBarNotification sbn = r.sbn;
+ if (!isVisibleToListener(sbn, info)) continue;
+ StatusBarNotification sbnToSend =
+ (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
+ list.add(sbnToSend);
+ }
+ return new ParceledListSlice<>(list);
+ }
+ }
+
@Override
public void requestHintsFromListener(INotificationListener token, int hints) {
final long identity = Binder.clearCallingIdentity();
@@ -2316,6 +2404,8 @@ public class NotificationManagerService extends SystemService {
final DumpFilter filter = DumpFilter.parseFromArguments(args);
if (filter != null && filter.stats) {
dumpJson(pw, filter);
+ } else if (filter != null && filter.proto) {
+ dumpProto(fd, filter);
} else {
dumpImpl(pw, filter);
}
@@ -2648,10 +2738,8 @@ public class NotificationManagerService extends SystemService {
summaries.put(pkg, summarySbn.getKey());
}
}
- if (summaryRecord != null) {
- synchronized (mNotificationLock) {
- mEnqueuedNotifications.add(summaryRecord);
- }
+ if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
+ summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
}
}
@@ -2682,6 +2770,33 @@ public class NotificationManagerService extends SystemService {
pw.println(dump);
}
+ private void dumpProto(FileDescriptor fd, DumpFilter filter) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ synchronized (mNotificationLock) {
+ long records = proto.start(NotificationServiceDumpProto.RECORDS);
+ int N = mNotificationList.size();
+ if (N > 0) {
+ for (int i = 0; i < N; i++) {
+ final NotificationRecord nr = mNotificationList.get(i);
+ if (filter.filtered && !filter.matches(nr.sbn)) continue;
+ nr.dump(proto, filter.redact);
+ proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
+ }
+ }
+ N = mEnqueuedNotifications.size();
+ if (N > 0) {
+ for (int i = 0; i < N; i++) {
+ final NotificationRecord nr = mEnqueuedNotifications.get(i);
+ if (filter.filtered && !filter.matches(nr.sbn)) continue;
+ nr.dump(proto, filter.redact);
+ proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
+ }
+ }
+ proto.end(records);
+ }
+ proto.flush();
+ }
+
void dumpImpl(PrintWriter pw, DumpFilter filter) {
pw.print("Current Notification Manager state");
if (filter.filtered) {
@@ -2882,13 +2997,15 @@ public class NotificationManagerService extends SystemService {
+ " notification=" + notification);
}
checkCallerIsSystemOrSameApp(pkg);
- final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
- final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
final int userId = ActivityManager.handleIncomingUser(callingPid,
callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
final UserHandle user = new UserHandle(userId);
+ if (pkg == null || notification == null) {
+ throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ + " id=" + id + " notification=" + notification);
+ }
// Fix the notification as best we can.
try {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
@@ -2902,22 +3019,60 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerEnqueuedByApp(pkg);
-
- if (pkg == null || notification == null) {
- throw new IllegalArgumentException("null not allowed: pkg=" + pkg
- + " id=" + id + " notification=" + notification);
+ // setup local book-keeping
+ String channelId = notification.getChannel();
+ if (mIsTelevision && (new Notification.TvExtender(notification)).getChannel() != null) {
+ channelId = (new Notification.TvExtender(notification)).getChannel();
}
final NotificationChannel channel = mRankingHelper.getNotificationChannelWithFallback(pkg,
- callingUid, notification.getChannel(), false /* includeDeleted */);
+ callingUid, channelId, false /* includeDeleted */);
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, callingUid, callingPid, notification,
user, null, System.currentTimeMillis());
+ final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
+
+ if (!checkDisqualifyingFeatures(userId, callingUid, id,tag, r)) {
+ return;
+ }
+
+ // Whitelist pending intents.
+ if (notification.allPendingIntents != null) {
+ final int intentCount = notification.allPendingIntents.size();
+ if (intentCount > 0) {
+ final ActivityManagerInternal am = LocalServices
+ .getService(ActivityManagerInternal.class);
+ final long duration = LocalServices.getService(
+ DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
+ for (int i = 0; i < intentCount; i++) {
+ PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
+ if (pendingIntent != null) {
+ am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
+ }
+ }
+ }
+ }
+
+ mHandler.post(new EnqueueNotificationRunnable(userId, r));
+
+ idOut[0] = id;
+ }
+
+ /**
+ * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
+ *
+ * Has side effects.
+ */
+ private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
+ NotificationRecord r) {
+ final String pkg = r.sbn.getPackageName();
+ final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
+ final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
// Limit the number of notifications that any given package except the android
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
synchronized (mNotificationLock) {
- if (mNotificationsByKey.get(n.getKey()) != null) {
+ if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
// this is an update, rate limit updates only
final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
if (appEnqueueRate > mMaxPackageEnqueueRate) {
@@ -2928,16 +3083,18 @@ public class NotificationManagerService extends SystemService {
+ ". Shedding events. package=" + pkg);
mLastOverRateLogTime = now;
}
- return;
+ return false;
}
}
int count = 0;
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
- final NotificationRecord r = mNotificationList.get(i);
- if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
- if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
+ final NotificationRecord existing = mNotificationList.get(i);
+ if (existing.sbn.getPackageName().equals(pkg)
+ && existing.sbn.getUserId() == userId) {
+ if (existing.sbn.getId() == id
+ && TextUtils.equals(existing.sbn.getTag(), tag)) {
break; // Allow updating existing notification
}
count++;
@@ -2945,42 +3102,53 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerOverCountQuota(pkg);
Slog.e(TAG, "Package has already posted " + count
+ " notifications. Not showing more. package=" + pkg);
- return;
+ return false;
}
}
}
}
}
- // Whitelist pending intents.
- if (notification.allPendingIntents != null) {
- final int intentCount = notification.allPendingIntents.size();
- if (intentCount > 0) {
- final ActivityManagerInternal am = LocalServices
- .getService(ActivityManagerInternal.class);
- final long duration = LocalServices.getService(
- DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
- for (int i = 0; i < intentCount; i++) {
- PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
- if (pendingIntent != null) {
- am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
- }
- }
+ // snoozed apps
+ if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
+ // TODO: log to event log
+ if (DBG) {
+ Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
}
+ mSnoozeHelper.update(userId, r);
+ savePolicyFile();
+ return false;
}
- // Sanitize inputs
- notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
- Notification.PRIORITY_MAX);
- // setup local book-keeping
- final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
- synchronized (mNotificationLock) {
- mEnqueuedNotifications.add(r);
+ // blocked apps
+ if (isBlocked(r, mUsageStats)) {
+ return false;
}
- mHandler.post(new EnqueueNotificationRunnable(userId, r));
- idOut[0] = id;
+ return true;
+ }
+
+ protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
+ final String pkg = r.sbn.getPackageName();
+ final int callingUid = r.sbn.getUid();
+
+ final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
+ if (isPackageSuspended) {
+ Slog.e(TAG, "Suppressing notification from package due to package "
+ + "suspended by administrator.");
+ usageStats.registerSuspendedByAdmin(r);
+ return isPackageSuspended;
+ }
+
+ final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
+ || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
+ || !noteNotificationOp(pkg, callingUid);
+ if (isBlocked) {
+ Slog.e(TAG, "Suppressing notification from package by user request.");
+ usageStats.registerBlocked(r);
+ }
+ return isBlocked;
}
protected class EnqueueNotificationRunnable implements Runnable {
@@ -2995,15 +3163,8 @@ public class NotificationManagerService extends SystemService {
@Override
public void run() {
synchronized (mNotificationLock) {
- if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) {
- // TODO: log to event log
- if (DBG) {
- Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
- }
- mSnoozeHelper.update(userId, r);
- savePolicyFile();
- return;
- }
+ mEnqueuedNotifications.add(r);
+ scheduleTimeoutLocked(r);
final StatusBarNotification n = r.sbn;
if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
@@ -3039,51 +3200,22 @@ public class NotificationManagerService extends SystemService {
mRankingHelper.extractSignals(r);
- // blocked apps
- if (isBlocked(r, mUsageStats)) {
- return;
- }
-
// tell the assistant service about the notification
if (mNotificationAssistants.isEnabled()) {
mNotificationAssistants.onNotificationEnqueued(r);
- mHandler.postDelayed(new PostNotificationRunnable(userId, r.getKey()),
+ mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
DELAY_FOR_ASSISTANT_TIME);
} else {
- mHandler.post(new PostNotificationRunnable(userId, r.getKey()));
+ mHandler.post(new PostNotificationRunnable(r.getKey()));
}
}
}
-
- protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
- final String pkg = r.sbn.getPackageName();
- final int callingUid = r.sbn.getUid();
-
- final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
- if (isPackageSuspended) {
- Slog.e(TAG, "Suppressing notification from package due to package "
- + "suspended by administrator.");
- usageStats.registerSuspendedByAdmin(r);
- return isPackageSuspended;
- }
-
- final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
- || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
- || !noteNotificationOp(pkg, callingUid);
- if (isBlocked) {
- Slog.e(TAG, "Suppressing notification from package by user request.");
- usageStats.registerBlocked(r);
- }
- return isBlocked;
- }
}
protected class PostNotificationRunnable implements Runnable {
private final String key;
- private final int userId;
- PostNotificationRunnable(int userId, String key) {
- this.userId = userId;
+ PostNotificationRunnable(String key) {
this.key = key;
}
@@ -3224,6 +3356,22 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void scheduleTimeoutLocked(NotificationRecord record) {
+ if (record.getNotification().getTimeout() > System.currentTimeMillis()) {
+ final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
+ REQUEST_CODE_TIMEOUT,
+ new Intent(ACTION_NOTIFICATION_TIMEOUT)
+ .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
+ .appendPath(record.getKey()).build())
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(EXTRA_KEY, record.getKey()),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ mAlarmManager.setExactAndAllowWhileIdle(
+ AlarmManager.RTC_WAKEUP, record.getNotification().getTimeout(), pi);
+ }
+ }
+
+ @VisibleForTesting
void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
@@ -3314,7 +3462,7 @@ public class NotificationManagerService extends SystemService {
// light
// release the light
boolean wasShowLights = mLights.remove(key);
- if (shouldShowLights(record) && aboveThreshold
+ if (record.getLight() != null && aboveThreshold
&& ((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
mLights.add(key);
@@ -3331,18 +3479,16 @@ public class NotificationManagerService extends SystemService {
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
} else {
+ MetricsLogger.action(record.getLogMaker()
+ .setCategory(MetricsEvent.NOTIFICATION_ALERT)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
EventLogTags.writeNotificationAlert(key,
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
- mHandler.post(mBuzzBeepBlinked);
}
}
}
- private boolean shouldShowLights(final NotificationRecord record) {
- return record.getChannel().shouldShowLights()
- || (record.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0;
- }
-
private boolean playSound(final NotificationRecord record, Uri soundUri) {
boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
// do not play notifications if there is a user of exclusive audio focus
@@ -3801,6 +3947,10 @@ public class NotificationManagerService extends SystemService {
mArchive.record(r.sbn);
final long now = System.currentTimeMillis();
+ MetricsLogger.action(r.getLogMaker(now)
+ .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+ .setType(MetricsEvent.TYPE_DISMISS)
+ .setSubtype(reason));
EventLogTags.writeNotificationCanceled(canceledKey, reason,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
}
@@ -3982,14 +4132,14 @@ public class NotificationManagerService extends SystemService {
void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
ManagedServiceInfo listener) {
String listenerName = listener == null ? null : listener.component.toShortString();
+ if (until < System.currentTimeMillis() && snoozeCriterionId == null) {
+ return;
+ }
// TODO: write to event log
if (DBG) {
Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
listenerName));
}
- if (until != SNOOZE_UNTIL_UNSPECIFIED && until < System.currentTimeMillis()) {
- return;
- }
// Needs to post so that it can cancel notifications not yet enqueued.
mHandler.post(new Runnable() {
@Override
@@ -4002,8 +4152,6 @@ public class NotificationManagerService extends SystemService {
if (snoozeCriterionId != null) {
mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
snoozeCriterionId);
- }
- if (until == SNOOZE_UNTIL_UNSPECIFIED) {
mSnoozeHelper.snooze(r);
} else {
mSnoozeHelper.snooze(r, until);
@@ -4116,28 +4264,12 @@ public class NotificationManagerService extends SystemService {
// Don't flash while we are in a call or screen is on
if (ledNotification == null || mInCall || mScreenOn) {
mNotificationLight.turnOff();
- if (mStatusBar != null) {
- mStatusBar.notificationLightOff();
- }
} else {
- final Notification ledno = ledNotification.sbn.getNotification();
- int ledARGB = ledno.ledARGB;
- int ledOnMS = ledno.ledOnMS;
- int ledOffMS = ledno.ledOffMS;
- if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0
- || (ledno.flags & Notification.FLAG_SHOW_LIGHTS) == 0) {
- ledARGB = mDefaultNotificationColor;
- ledOnMS = mDefaultNotificationLedOn;
- ledOffMS = mDefaultNotificationLedOff;
- }
- if (mNotificationPulseEnabled) {
+ NotificationRecord.Light light = ledNotification.getLight();
+ if (light != null && mNotificationPulseEnabled) {
// pulse repeatedly
- mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
- ledOnMS, ledOffMS);
- }
- if (mStatusBar != null) {
- // let SystemUI make an independent decision
- mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
+ mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
+ light.onMs, light.offMs);
}
}
}
@@ -4422,18 +4554,18 @@ public class NotificationManagerService extends SystemService {
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyEnqueued(info, sbnToPost, importance, fromUser);
+ notifyEnqueued(info, sbnToPost);
}
});
}
}
private void notifyEnqueued(final ManagedServiceInfo info,
- final StatusBarNotification sbn, int importance, boolean fromUser) {
+ final StatusBarNotification sbn) {
final INotificationListener assistant = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
- assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
+ assistant.onNotificationEnqueued(sbnHolder);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
}
@@ -4723,11 +4855,15 @@ public class NotificationManagerService extends SystemService {
public long since;
public boolean stats;
public boolean redact = true;
+ public boolean proto = false;
public static DumpFilter parseFromArguments(String[] args) {
final DumpFilter filter = new DumpFilter();
for (int ai = 0; ai < args.length; ai++) {
final String a = args[ai];
+ if ("--proto".equals(args[0])) {
+ filter.proto = true;
+ }
if ("--noredact".equals(a) || "--reveal".equals(a)) {
filter.redact = false;
} else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 2a5a25f8e866..3016b17db7b9 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -31,18 +31,24 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.media.AudioSystem;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationRecordProto;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -117,6 +123,8 @@ public final class NotificationRecord {
private ArrayList<String> mPeopleOverride;
private ArrayList<SnoozeCriterion> mSnoozeCriteria;
private boolean mShowBadge;
+ private LogMaker mLogMaker;
+ private Light mLight;
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
@@ -135,6 +143,7 @@ public final class NotificationRecord {
mVibration = calculateVibration();
mAttributes = calculateAttributes();
mImportance = calculateImportance();
+ mLight = calculateLights();
}
private boolean isPreChannelsNotification() {
@@ -170,6 +179,36 @@ public final class NotificationRecord {
return sound;
}
+ private Light calculateLights() {
+ int defaultLightColor = mContext.getResources().getColor(
+ com.android.internal.R.color.config_defaultNotificationColor);
+ int defaultLightOn = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOn);
+ int defaultLightOff = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOff);
+
+ int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
+ : defaultLightColor;
+ Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
+ defaultLightOn, defaultLightOff) : null;
+ if (mPreChannelsNotification
+ && (getChannel().getUserLockedFields()
+ & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
+ final Notification notification = sbn.getNotification();
+ if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+ light = new Light(notification.ledARGB, notification.ledOnMS,
+ notification.ledOffMS);
+ if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ light = new Light(defaultLightColor, defaultLightOn,
+ defaultLightOff);
+ }
+ } else {
+ light = null;
+ }
+ }
+ return light;
+ }
+
private long[] calculateVibration() {
long[] vibration;
final long[] defaultVibration = NotificationManagerService.getLongArray(
@@ -200,18 +239,26 @@ public final class NotificationRecord {
private AudioAttributes calculateAttributes() {
final Notification n = sbn.getNotification();
- AudioAttributes attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
-
- if (n.audioAttributes != null) {
- // prefer audio attributes to stream type
- attributes = n.audioAttributes;
- } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
- // the stream type is valid, use it
- attributes = new AudioAttributes.Builder()
- .setInternalLegacyStreamType(n.audioStreamType)
- .build();
- } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
- Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
+ AudioAttributes attributes = getChannel().getAudioAttributes();
+ if (attributes == null) {
+ attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
+ }
+
+ if (mPreChannelsNotification
+ && (getChannel().getUserLockedFields()
+ & NotificationChannel.USER_LOCKED_SOUND) == 0) {
+ if (n.audioAttributes != null) {
+ // prefer audio attributes to stream type
+ attributes = n.audioAttributes;
+ } else if (n.audioStreamType >= 0
+ && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
+ // the stream type is valid, use it
+ attributes = new AudioAttributes.Builder()
+ .setInternalLegacyStreamType(n.audioStreamType)
+ .build();
+ } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
+ Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
+ }
}
return attributes;
}
@@ -226,6 +273,8 @@ public final class NotificationRecord {
n.priority = Notification.PRIORITY_MAX;
}
+ n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
+ Notification.PRIORITY_MAX);
switch (n.priority) {
case Notification.PRIORITY_MIN:
requestedImportance = IMPORTANCE_MIN;
@@ -290,6 +339,24 @@ public final class NotificationRecord {
/** @deprecated Use {@link #getUser()} instead. */
public int getUserId() { return sbn.getUserId(); }
+ void dump(ProtoOutputStream proto, boolean redact) {
+ proto.write(NotificationRecordProto.KEY, sbn.getKey());
+ if (getChannel() != null) {
+ proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
+ }
+ proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
+ proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
+ proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
+ proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
+ proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
+ if (getSound() != null) {
+ proto.write(NotificationRecordProto.SOUND, getSound().toString());
+ }
+ if (getAudioAttributes() != null) {
+ proto.write(NotificationRecordProto.SOUND_USAGE, getAudioAttributes().getUsage());
+ }
+ }
+
void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
final Notification notification = sbn.getNotification();
final Icon icon = notification.getSmallIcon();
@@ -309,15 +376,8 @@ public final class NotificationRecord {
pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
pw.println(prefix + " tickerText=" + notification.tickerText);
pw.println(prefix + " contentView=" + notification.contentView);
- pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x",
- notification.defaults, notification.flags));
- pw.println(prefix + " sound=" + notification.sound);
- pw.println(prefix + " audioStreamType=" + notification.audioStreamType);
- pw.println(prefix + " audioAttributes=" + notification.audioAttributes);
pw.println(prefix + String.format(" color=0x%08x", notification.color));
- pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
- pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
- notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
+ pw.println(prefix + " timeout=" + TimeUtils.formatForLogging(notification.getTimeout()));
if (notification.actions != null && notification.actions.length > 0) {
pw.println(prefix + " actions={");
final int N = notification.actions.length;
@@ -384,12 +444,22 @@ public final class NotificationRecord {
pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs);
pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects);
- pw.println(prefix + " notificationChannel= " + notification.getChannel());
+ if (mPreChannelsNotification) {
+ pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x",
+ notification.defaults, notification.flags));
+ pw.println(prefix + " n.sound=" + notification.sound);
+ pw.println(prefix + " n.audioStreamType=" + notification.audioStreamType);
+ pw.println(prefix + " n.audioAttributes=" + notification.audioAttributes);
+ pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
+ notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
+ pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
+ }
pw.println(prefix + " mSound= " + mSound);
pw.println(prefix + " mVibration= " + mVibration);
pw.println(prefix + " mAttributes= " + mAttributes);
+ pw.println(prefix + " mLight= " + mLight);
pw.println(prefix + " mShowBadge=" + mShowBadge);
- pw.println(prefix + " channel=" + getChannel());
+ pw.println(prefix + " effectiveNotificationChannel=" + getChannel());
if (getPeopleOverride() != null) {
pw.println(prefix + " overridePeople= " + TextUtils.join(",", getPeopleOverride()));
}
@@ -583,9 +653,16 @@ public final class NotificationRecord {
final long now = System.currentTimeMillis();
mVisibleSinceMs = visible ? now : mVisibleSinceMs;
stats.onVisibilityChanged(visible);
+ MetricsLogger.action(getLogMaker(now)
+ .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+ .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
+ .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank));
+ if (visible) {
+ MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
+ }
EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
- (int) (now - mCreationTimeMs),
- (int) (now - mUpdateTimeMs),
+ getLifespanMs(now),
+ getFreshnessMs(now),
0, // exposure time
rank);
}
@@ -661,6 +738,10 @@ public final class NotificationRecord {
return mShowBadge;
}
+ public Light getLight() {
+ return mLight;
+ }
+
public Uri getSound() {
return mSound;
}
@@ -688,4 +769,68 @@ public final class NotificationRecord {
protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
mSnoozeCriteria = snoozeCriteria;
}
+
+ public LogMaker getLogMaker(long now) {
+ if (mLogMaker == null) {
+ mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
+ .setPackageName(sbn.getPackageName())
+ .addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId())
+ .addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag());
+ }
+ return mLogMaker
+ .setCategory(MetricsEvent.VIEW_UNKNOWN)
+ .setType(MetricsEvent.TYPE_UNKNOWN)
+ .setSubtype(0)
+ .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now));
+ }
+
+ public LogMaker getLogMaker() {
+ return getLogMaker(System.currentTimeMillis());
+ }
+
+ @VisibleForTesting
+ static final class Light {
+ public final int color;
+ public final int onMs;
+ public final int offMs;
+
+ public Light(int color, int onMs, int offMs) {
+ this.color = color;
+ this.onMs = onMs;
+ this.offMs = offMs;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Light light = (Light) o;
+
+ if (color != light.color) return false;
+ if (onMs != light.onMs) return false;
+ return offMs == light.offMs;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = color;
+ result = 31 * result + onMs;
+ result = 31 * result + offMs;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Light{" +
+ "color=" + color +
+ ", onMs=" + onMs +
+ ", offMs=" + offMs +
+ '}';
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 492d5c639a7d..6a0072216f70 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -16,8 +16,11 @@
package com.android.server.notification;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.content.pm.ParceledListSlice;
+import java.util.Collection;
+
public interface RankingConfig {
void setImportance(String packageName, int uid, int importance);
@@ -25,6 +28,12 @@ public interface RankingConfig {
void setShowBadge(String packageName, int uid, boolean showBadge);
boolean canShowBadge(String packageName, int uid);
+ Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
+ int uid);
+ void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
+ boolean fromTargetApp);
+ ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
+ int uid, boolean includeDeleted);
void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp);
void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 1861bcb7df85..4cbeec815c31 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -23,6 +23,7 @@ import com.android.internal.util.Preconditions;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -46,6 +47,7 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -59,6 +61,7 @@ public class RankingHelper implements RankingConfig {
private static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CHANNEL = "channel";
+ private static final String TAG_GROUP = "channelGroup";
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
@@ -174,7 +177,6 @@ public class RankingHelper implements RankingConfig {
safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
- // Channels
final int innerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
@@ -184,6 +186,17 @@ public class RankingHelper implements RankingConfig {
}
String tagName = parser.getName();
+ // Channel groups
+ if (TAG_GROUP.equals(tagName)) {
+ String id = parser.getAttributeValue(null, ATT_ID);
+ CharSequence groupName = parser.getAttributeValue(null, ATT_NAME);
+ if (!TextUtils.isEmpty(id)) {
+ final NotificationChannelGroup group =
+ new NotificationChannelGroup(id, groupName);
+ r.groups.put(id, group);
+ }
+ }
+ // Channels
if (TAG_CHANNEL.equals(tagName)) {
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
@@ -302,7 +315,8 @@ public class RankingHelper implements RankingConfig {
}
final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
|| r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY
- || r.showBadge != DEFAULT_SHOW_BADGE || r.channels.size() > 0;
+ || r.showBadge != DEFAULT_SHOW_BADGE || r.channels.size() > 0
+ || r.groups.size() > 0;
if (hasNonDefaultSettings) {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
@@ -321,6 +335,10 @@ public class RankingHelper implements RankingConfig {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
}
+ for (NotificationChannelGroup group : r.groups.values()) {
+ group.writeXml(out);
+ }
+
for (NotificationChannel channel : r.channels.values()) {
channel.writeXml(out);
}
@@ -441,6 +459,21 @@ public class RankingHelper implements RankingConfig {
}
@Override
+ public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
+ boolean fromTargetApp) {
+ Preconditions.checkNotNull(pkg);
+ Preconditions.checkNotNull(group);
+ Preconditions.checkNotNull(group.getId());
+ Preconditions.checkNotNull(group.getName());
+ Record r = getOrCreateRecord(pkg, uid);
+ if (r == null) {
+ throw new IllegalArgumentException("Invalid package");
+ }
+ r.groups.put(group.getId(), group);
+ updateConfig();
+ }
+
+ @Override
public void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp) {
Preconditions.checkNotNull(pkg);
@@ -454,6 +487,10 @@ public class RankingHelper implements RankingConfig {
if (IMPORTANCE_NONE == r.importance) {
throw new IllegalArgumentException("Package blocked");
}
+ if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
+ throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
+ }
+
NotificationChannel existing = r.channels.get(channel.getId());
// Keep existing settings
if (existing != null) {
@@ -526,13 +563,14 @@ public class RankingHelper implements RankingConfig {
channel.setImportance(updatedChannel.getImportance());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
- channel.setLights(updatedChannel.shouldShowLights());
+ channel.enableLights(updatedChannel.shouldShowLights());
+ channel.setLightColor(updatedChannel.getLightColor());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_PRIORITY) == 0) {
channel.setBypassDnd(updatedChannel.canBypassDnd());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) == 0) {
- channel.setSound(updatedChannel.getSound());
+ channel.setSound(updatedChannel.getSound(), updatedChannel.getAudioAttributes());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
channel.enableVibration(updatedChannel.shouldVibrate());
@@ -549,8 +587,9 @@ public class RankingHelper implements RankingConfig {
channel.setShowBadge(updatedChannel.canShowBadge());
}
if (updatedChannel.isDeleted()) {
- updatedChannel.setDeleted(true);
+ channel.setDeleted(true);
}
+ // Assistant cannot change the group
r.channels.put(channel.getId(), channel);
updateConfig();
@@ -632,6 +671,51 @@ public class RankingHelper implements RankingConfig {
}
@Override
+ public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
+ int uid, boolean includeDeleted) {
+ Preconditions.checkNotNull(pkg);
+ List<NotificationChannelGroup> groups = new ArrayList<>();
+ Record r = getRecord(pkg, uid);
+ if (r == null) {
+ return ParceledListSlice.emptyList();
+ }
+ NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ int N = r.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = r.channels.valueAt(i);
+ if (includeDeleted || !nc.isDeleted()) {
+ if (nc.getGroup() != null) {
+ // lazily populate channel list
+ NotificationChannelGroup ncg = r.groups.get(nc.getGroup());
+ ncg.addChannel(nc);
+ } else {
+ nonGrouped.addChannel(nc);
+ }
+ }
+ }
+ for (NotificationChannelGroup group : r.groups.values()) {
+ if (group.getChannels().size() > 0) {
+ groups.add(group);
+ }
+ }
+ if (nonGrouped.getChannels().size() > 0) {
+ groups.add(nonGrouped);
+ }
+ return new ParceledListSlice<>(groups);
+ }
+
+ @Override
+ @VisibleForTesting
+ public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
+ int uid) {
+ Record r = getRecord(pkg, uid);
+ if (r == null) {
+ return new ArrayList<>();
+ }
+ return r.groups.values();
+ }
+
+ @Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
boolean includeDeleted) {
Preconditions.checkNotNull(pkg);
@@ -723,6 +807,12 @@ public class RankingHelper implements RankingConfig {
pw.print(" ");
pw.println(channel);
}
+ for (NotificationChannelGroup group : r.groups.values()) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(" ");
+ pw.println(group);
+ }
}
}
}
@@ -758,6 +848,9 @@ public class RankingHelper implements RankingConfig {
for (NotificationChannel channel : r.channels.values()) {
record.put("channel", channel.toJson());
}
+ for (NotificationChannelGroup group : r.groups.values()) {
+ record.put("group", group.toJson());
+ }
} catch (JSONException e) {
// pass
}
@@ -871,5 +964,6 @@ public class RankingHelper implements RankingConfig {
boolean showBadge = DEFAULT_SHOW_BADGE;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
+ ArrayMap<String, NotificationChannelGroup> groups = new ArrayMap<>();
}
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index e14700a99512..f2aff1102b0b 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -41,6 +41,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -98,6 +99,26 @@ public class SnoozeHelper {
return Collections.EMPTY_LIST;
}
+ protected List<NotificationRecord> getSnoozed() {
+ List<NotificationRecord> snoozedForUser = new ArrayList<>();
+ int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final int N = userIds.length;
+ for (int i = 0; i < N; i++) {
+ final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+ mSnoozedNotifications.get(userIds[i]);
+ if (snoozedPkgs != null) {
+ final int M = snoozedPkgs.size();
+ for (int j = 0; j < M; j++) {
+ final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
+ if (records != null) {
+ snoozedForUser.addAll(records.values());
+ }
+ }
+ }
+ }
+ return snoozedForUser;
+ }
+
/**
* Snoozes a notification and schedules an alarm to repost at that time.
*/
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 5dd651f2d431..a30e06399614 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -46,7 +46,6 @@ import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import android.os.SystemClock;
-import com.android.internal.logging.MetricsLogger;
/**
* This {@link NotificationSignalExtractor} attempts to validate
@@ -264,9 +263,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
// record the best available data, so far:
affinityOut[0] = affinity;
- MetricsLogger.histogram(mBaseContext, "validate_people_cache_latency",
- (int) (SystemClock.elapsedRealtime() - start));
-
if (pendingLookups.isEmpty()) {
if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
return null;
@@ -485,9 +481,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
mUsageStats.registerPeopleAffinity(mRecord, mContactAffinity > NONE,
mContactAffinity == STARRED_CONTACT, false /* cached */);
}
-
- MetricsLogger.histogram(mBaseContext, "validate_people_lookup_latency",
- (int) (SystemClock.elapsedRealtime() - start));
}
@Override
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
new file mode 100644
index 000000000000..04d91f882d04
--- /dev/null
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.content.om.OverlayInfo;
+import android.content.pm.PackageInfo;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.Installer;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Handle the creation and deletion of idmap files.
+ *
+ * The actual work is performed by the idmap binary, launched through Installer
+ * and installd.
+ *
+ * Note: this class is subclassed in the OMS unit tests, and hence not marked as final.
+ */
+class IdmapManager {
+ private final Installer mInstaller;
+
+ IdmapManager(final Installer installer) {
+ mInstaller = installer;
+ }
+
+ boolean createIdmap(@NonNull final PackageInfo targetPackage,
+ @NonNull final PackageInfo overlayPackage, int userId) {
+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
+ if (DEBUG) {
+ Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
+ + overlayPackage.packageName);
+ }
+ final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid);
+ final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
+ final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
+ try {
+ mInstaller.idmap(targetPath, overlayPath, sharedGid);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
+ + overlayPath + ": " + e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
+ if (DEBUG) {
+ Slog.d(TAG, "remove idmap for " + oi.baseCodePath);
+ }
+ try {
+ mInstaller.removeIdmap(oi.baseCodePath);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ boolean idmapExists(@NonNull final OverlayInfo oi) {
+ // unused OverlayInfo.userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
+ return new File(getIdmapPath(oi.baseCodePath)).isFile();
+ }
+
+ boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
+ return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile();
+ }
+
+ boolean isDangerous(@NonNull final PackageInfo overlayPackage, final int userId) {
+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
+ return isDangerous(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath()));
+ }
+
+ private String getIdmapPath(@NonNull final String baseCodePath) {
+ final StringBuilder sb = new StringBuilder("/data/resource-cache/");
+ sb.append(baseCodePath.substring(1).replace('/', '@'));
+ sb.append("@idmap");
+ return sb.toString();
+ }
+
+ private boolean isDangerous(@NonNull final String idmapPath) {
+ try (DataInputStream dis = new DataInputStream(new FileInputStream(idmapPath))) {
+ final int magic = dis.readInt();
+ final int version = dis.readInt();
+ final int dangerous = dis.readInt();
+ return dangerous != 0;
+ } catch (IOException e) {
+ return true;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
new file mode 100644
index 000000000000..cc709ce6f176
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -0,0 +1,850 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import static android.app.AppGlobals.getPackageManager;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_CHANGED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.pm.PackageManager.SIGNATURE_MATCH;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.FgThread;
+import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.Installer;
+import com.android.server.pm.UserManagerService;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Service to manage asset overlays.
+ *
+ * <p>Asset overlays are additional resources that come from apks loaded
+ * alongside the system and app apks. This service, the OverlayManagerService
+ * (OMS), tracks which installed overlays to use and provides methods to change
+ * this. Changes propagate to running applications as part of the Activity
+ * lifecycle. This allows Activities to reread their resources at a well
+ * defined point.</p>
+ *
+ * <p>By itself, the OMS will not change what overlays should be active.
+ * Instead, it is only responsible for making sure that overlays *can* be used
+ * from a technical and security point of view and to activate overlays in
+ * response to external requests. The responsibility to toggle overlays on and
+ * off lies within components that implement different use-cases such as themes
+ * or dynamic customization.</p>
+ *
+ * <p>The OMS receives input from three sources:</p>
+ *
+ * <ul>
+ * <li>Callbacks from the SystemService class, specifically when the
+ * Android framework is booting and when the end user switches Android
+ * users.</li>
+ *
+ * <li>Intents from the PackageManagerService (PMS). Overlays are regular
+ * apks, and whenever a package is installed (or removed, or has a
+ * component enabled or disabled), the PMS broadcasts this as an intent.
+ * When the OMS receives one of these intents, it updates its internal
+ * representation of the available overlays and, if there was a visible
+ * change, triggers an asset refresh in the affected apps.</li>
+ *
+ * <li>External requests via the {@link IOverlayManager AIDL interface}.
+ * The interface allows clients to read information about the currently
+ * available overlays, change whether an overlay should be used or not, and
+ * change the relative order in which overlay packages are loaded.
+ * Read-access is granted if the request targets the same Android user as
+ * the caller runs as, or if the caller holds the
+ * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
+ * caller is granted read-access and additionaly holds the
+ * CHANGE_OVERLAY_PACKAGES permission.</li>
+ * </ul>
+ *
+ * <p>The AIDL interface works with String package names, int user IDs, and
+ * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
+ * specific pair of target and overlay packages and include information such as
+ * the current state of the overlay. OverlayInfo objects are immutable.</p>
+ *
+ * <p>Internally, OverlayInfo objects are maintained by the
+ * OverlayManagerSettings class. The OMS and its helper classes are notified of
+ * changes to the settings by the OverlayManagerSettings.ChangeListener
+ * callback interface. The file /data/system/overlays.xml is used to persist
+ * the settings.</p>
+ *
+ * <p>Creation and deletion of idmap files are handled by the IdmapManager
+ * class.</p>
+ *
+ * <p>The following is an overview of OMS and its related classes. Note how box
+ * (2) does the heavy lifting, box (1) interacts with the Android framework,
+ * and box (3) replaces box (1) during unit testing.</p>
+ *
+ * <pre>
+ * Android framework
+ * | ^
+ * . . . | . . . . | . . . .
+ * . | | .
+ * . AIDL, broadcasts .
+ * . intents | .
+ * . | | . . . . . . . . . . . .
+ * . v | . .
+ * . OverlayManagerService . OverlayManagerTests .
+ * . \ . / .
+ * . (1) \ . / (3) .
+ * . . . . . . . . . . \ . . . / . . . . . . . . .
+ * . \ / .
+ * . (2) \ / .
+ * . OverlayManagerServiceImpl .
+ * . | | .
+ * . | | .
+ * . OverlayManagerSettings IdmapManager .
+ * . .
+ * . . . . . . . . . . . . . . . . . . . . . .
+ * </pre>
+ *
+ * <p>Finally, here is a list of keywords used in the OMS context.</p>
+ *
+ * <ul>
+ * <li><b>target [package]</b> -- A regular apk that may have its resource
+ * pool extended by zero or more overlay packages.</li>
+ *
+ * <li><b>overlay [package]</b> -- An apk that provides additional
+ * resources to another apk.</li>
+ *
+ * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
+ *
+ * <li><b>approved</b> -- An overlay is approved if the OMS has verified
+ * that it can be used technically speaking (its target package is
+ * installed, at least one resource name in both packages match, the
+ * idmap was created, etc) and that it is secure to do so. External
+ * clients can not change this state.</li>
+ *
+ * <li><b>not approved</b> -- The opposite of approved.</li>
+ *
+ * <li><b>enabled</b> -- An overlay currently in active use and thus part
+ * of resource lookups. This requires the overlay to be approved. Only
+ * external clients can change this state.</li>
+ *
+ * <li><b>disabled</b> -- The opposite of enabled.</li>
+ *
+ * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
+ * used during resource lookup. Also the name of the binary that creates
+ * the mapping.</li>
+ * </ul>
+ */
+public final class OverlayManagerService extends SystemService {
+
+ static final String TAG = "OverlayManager";
+
+ static final boolean DEBUG = false;
+
+ static final String PERMISSION_DENIED = "Operation not permitted for user shell";
+
+ private final Object mLock = new Object();
+
+ private final AtomicFile mSettingsFile;
+
+ private final PackageManagerHelper mPackageManager;
+
+ private final UserManagerService mUserManager;
+
+ private final OverlayManagerSettings mSettings;
+
+ private final OverlayManagerServiceImpl mImpl;
+
+ private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
+
+ public OverlayManagerService(@NonNull final Context context,
+ @NonNull final Installer installer) {
+ super(context);
+ mSettingsFile =
+ new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"));
+ mPackageManager = new PackageManagerHelper();
+ mUserManager = UserManagerService.getInstance();
+ IdmapManager im = new IdmapManager(installer);
+ mSettings = new OverlayManagerSettings();
+ mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings);
+
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
+ packageFilter, null, null);
+
+ final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
+ userFilter, null, null);
+
+ restoreSettings();
+ onSwitchUser(UserHandle.USER_SYSTEM);
+ schedulePersistSettings();
+
+ mSettings.addChangeListener(new OverlayChangeListener());
+
+ publishBinderService(Context.OVERLAY_SERVICE, mService);
+ publishLocalService(OverlayManagerService.class, this);
+ }
+
+ @Override
+ public void onStart() {
+ // Intentionally left empty.
+ }
+
+ @Override
+ public void onSwitchUser(final int newUserId) {
+ // ensure overlays in the settings are up-to-date, and propagate
+ // any asset changes to the rest of the system
+ final List<String> targets;
+ synchronized (mLock) {
+ targets = mImpl.onSwitchUser(newUserId);
+ }
+ updateAssets(newUserId, targets);
+ }
+
+ private final class PackageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final Uri data = intent.getData();
+ if (data == null) {
+ Slog.e(TAG, "Cannot handle package broadcast with null data");
+ return;
+ }
+ final String packageName = data.getSchemeSpecificPart();
+
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ final int[] userIds;
+ final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
+ if (extraUid == UserHandle.USER_NULL) {
+ userIds = mUserManager.getUserIds();
+ } else {
+ userIds = new int[] { UserHandle.getUserId(extraUid) };
+ }
+
+ switch (intent.getAction()) {
+ case ACTION_PACKAGE_ADDED:
+ if (replacing) {
+ onPackageUpgraded(packageName, userIds);
+ } else {
+ onPackageAdded(packageName, userIds);
+ }
+ break;
+ case ACTION_PACKAGE_CHANGED:
+ onPackageChanged(packageName, userIds);
+ break;
+ case ACTION_PACKAGE_REMOVED:
+ if (replacing) {
+ onPackageUpgrading(packageName, userIds);
+ } else {
+ onPackageRemoved(packageName, userIds);
+ }
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ private void onPackageAdded(@NonNull final String packageName,
+ @NonNull final int[] userIds) {
+ for (final int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (!isOverlayPackage(pi)) {
+ mImpl.onTargetPackageAdded(packageName, userId);
+ } else {
+ mImpl.onOverlayPackageAdded(packageName, userId);
+ }
+ }
+ }
+ }
+ }
+
+ private void onPackageChanged(@NonNull final String packageName,
+ @NonNull final int[] userIds) {
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (!isOverlayPackage(pi)) {
+ mImpl.onTargetPackageChanged(packageName, userId);
+ } else {
+ mImpl.onOverlayPackageChanged(packageName, userId);
+ }
+ }
+ }
+ }
+ }
+
+ private void onPackageUpgrading(@NonNull final String packageName,
+ @NonNull final int[] userIds) {
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ mPackageManager.forgetPackageInfo(packageName, userId);
+ final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+ if (oi == null) {
+ mImpl.onTargetPackageUpgrading(packageName, userId);
+ } else {
+ mImpl.onOverlayPackageUpgrading(packageName, userId);
+ }
+ }
+ }
+ }
+
+ private void onPackageUpgraded(@NonNull final String packageName,
+ @NonNull final int[] userIds) {
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (!isOverlayPackage(pi)) {
+ mImpl.onTargetPackageUpgraded(packageName, userId);
+ } else {
+ mImpl.onOverlayPackageUpgraded(packageName, userId);
+ }
+ }
+ }
+ }
+ }
+
+ private void onPackageRemoved(@NonNull final String packageName,
+ @NonNull final int[] userIds) {
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ mPackageManager.forgetPackageInfo(packageName, userId);
+ final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+ if (oi == null) {
+ mImpl.onTargetPackageRemoved(packageName, userId);
+ } else {
+ mImpl.onOverlayPackageRemoved(packageName, userId);
+ }
+ }
+ }
+ }
+ }
+
+ private final class UserReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ switch (intent.getAction()) {
+ case ACTION_USER_REMOVED:
+ final int userId =
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId != UserHandle.USER_NULL) {
+ synchronized (mLock) {
+ mImpl.onUserRemoved(userId);
+ mPackageManager.forgetAllPackageInfos(userId);
+ }
+ }
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ private final IBinder mService = new IOverlayManager.Stub() {
+ @Override
+ public Map<String, List<OverlayInfo>> getAllOverlays(int userId)
+ throws RemoteException {
+ userId = handleIncomingUser(userId, "getAllOverlays");
+
+ synchronized (mLock) {
+ return mImpl.getOverlaysForUser(userId);
+ }
+ }
+
+ @Override
+ public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
+ int userId) throws RemoteException {
+ userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
+ if (targetPackageName == null) {
+ return Collections.emptyList();
+ }
+
+ synchronized (mLock) {
+ return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+ }
+ }
+
+ @Override
+ public OverlayInfo getOverlayInfo(@Nullable final String packageName,
+ int userId) throws RemoteException {
+ userId = handleIncomingUser(userId, "getOverlayInfo");
+ if (packageName == null) {
+ return null;
+ }
+
+ synchronized (mLock) {
+ return mImpl.getOverlayInfo(packageName, userId);
+ }
+ }
+
+ @Override
+ public boolean setEnabled(@Nullable final String packageName, final boolean enable,
+ int userId) throws RemoteException {
+ enforceChangeOverlayPackagesPermission("setEnabled");
+ userId = handleIncomingUser(userId, "setEnabled");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setEnabled(packageName, enable, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public boolean setPriority(@Nullable final String packageName,
+ @Nullable final String parentPackageName, int userId) throws RemoteException {
+ enforceChangeOverlayPackagesPermission("setPriority");
+ userId = handleIncomingUser(userId, "setPriority");
+ if (packageName == null || parentPackageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setPriority(packageName, parentPackageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public boolean setHighestPriority(@Nullable final String packageName, int userId)
+ throws RemoteException {
+ enforceChangeOverlayPackagesPermission("setHighestPriority");
+ userId = handleIncomingUser(userId, "setHighestPriority");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setHighestPriority(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public boolean setLowestPriority(@Nullable final String packageName, int userId)
+ throws RemoteException {
+ enforceChangeOverlayPackagesPermission("setLowestPriority");
+ userId = handleIncomingUser(userId, "setLowestPriority");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setLowestPriority(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void onShellCommand(@NonNull final FileDescriptor in,
+ @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
+ @NonNull final String[] args, @NonNull final ShellCallback callback,
+ @NonNull final ResultReceiver resultReceiver) {
+ (new OverlayManagerShellCommand(this)).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override
+ protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
+ @NonNull final String[] argv) {
+ enforceDumpPermission("dump");
+
+ final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
+
+ synchronized (mLock) {
+ mImpl.onDump(pw);
+ mPackageManager.dump(pw, verbose);
+ }
+ }
+
+ /**
+ * Ensure that the caller has permission to interact with the given userId.
+ * If the calling user is not the same as the provided user, the caller needs
+ * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
+ * root).
+ *
+ * @param userId the user to interact with
+ * @param message message for any SecurityException
+ */
+ private int handleIncomingUser(final int userId, @NonNull final String message) {
+ return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, true, message, null);
+ }
+
+ /**
+ * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
+ * system or root).
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the permission check fails
+ */
+ private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
+ }
+
+ /**
+ * Enforce that the caller holds the DUMP permission (or is system or root).
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the permission check fails
+ */
+ private void enforceDumpPermission(@NonNull final String message) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
+ message);
+ }
+ };
+
+ private boolean isOverlayPackage(@NonNull final PackageInfo pi) {
+ return pi != null && pi.overlayTarget != null;
+ }
+
+ private final class OverlayChangeListener implements OverlayManagerSettings.ChangeListener {
+ @Override
+ public void onSettingsChanged() {
+ schedulePersistSettings();
+ }
+
+ @Override
+ public void onOverlayAdded(@NonNull final OverlayInfo oi) {
+ scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled());
+ }
+
+ @Override
+ public void onOverlayRemoved(@NonNull final OverlayInfo oi) {
+ scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled());
+ }
+
+ @Override
+ public void onOverlayChanged(@NonNull final OverlayInfo oi,
+ @NonNull final OverlayInfo oldOi) {
+ scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled());
+ }
+
+ @Override
+ public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
+ scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled());
+ }
+
+ private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi,
+ final boolean doUpdate) {
+ FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate));
+ }
+
+ private final class BroadcastRunnable implements Runnable {
+ private final String mAction;
+ private final OverlayInfo mOverlayInfo;
+ private final boolean mDoUpdate;
+
+ BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi,
+ final boolean doUpdate) {
+ mAction = action;
+ mOverlayInfo = oi;
+ mDoUpdate = doUpdate;
+ }
+
+ @Override
+ public void run() {
+ if (mDoUpdate) {
+ updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName);
+ }
+ sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName,
+ mOverlayInfo.userId);
+ }
+
+ private void sendBroadcast(@NonNull final String action,
+ @NonNull final String targetPackageName, @NonNull final String packageName,
+ final int userId) {
+ final Intent intent = new Intent(action, Uri.fromParts("package",
+ String.format("%s/%s", targetPackageName, packageName), null));
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ if (DEBUG) {
+ Slog.d(TAG, String.format("send broadcast %s", intent));
+ }
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(null, intent, null, null, 0,
+ null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
+ userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ }
+
+ }
+ }
+
+ private void updateAssets(final int userId, final String targetPackageName) {
+ final List<String> list = new ArrayList<>();
+ list.add(targetPackageName);
+ updateAssets(userId, list);
+ }
+
+ private void updateAssets(final int userId, List<String> targetPackageNames) {
+ // TODO: implement when we integrate OMS properly
+ }
+
+ private void schedulePersistSettings() {
+ if (mPersistSettingsScheduled.getAndSet(true)) {
+ return;
+ }
+ IoThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mPersistSettingsScheduled.set(false);
+ synchronized (mLock) {
+ FileOutputStream stream = null;
+ try {
+ stream = mSettingsFile.startWrite();
+ mSettings.persist(stream);
+ mSettingsFile.finishWrite(stream);
+ } catch (IOException | XmlPullParserException e) {
+ mSettingsFile.failWrite(stream);
+ Slog.e(TAG, "failed to persist overlay state", e);
+ }
+ }
+ }
+ });
+ }
+
+ private void restoreSettings() {
+ synchronized (mLock) {
+ if (!mSettingsFile.getBaseFile().exists()) {
+ return;
+ }
+ try (final FileInputStream stream = mSettingsFile.openRead()) {
+ mSettings.restore(stream);
+
+ // We might have data for dying users if the device was
+ // restarted before we received USER_REMOVED. Remove data for
+ // users that will not exist after the system is ready.
+
+ final List<UserInfo> deadUsers = getDeadUsers();
+ final int N = deadUsers.size();
+ for (int i = 0; i < N; i++) {
+ final UserInfo deadUser = deadUsers.get(i);
+ final int userId = deadUser.getUserHandle().getIdentifier();
+ mSettings.removeUser(userId);
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "failed to restore overlay state", e);
+ }
+ }
+ }
+
+ private List<UserInfo> getDeadUsers() {
+ final List<UserInfo> users = mUserManager.getUsers(false);
+ final List<UserInfo> onlyLiveUsers = mUserManager.getUsers(true);
+ users.removeAll(onlyLiveUsers);
+ return users;
+ }
+
+ private static final class PackageManagerHelper implements
+ OverlayManagerServiceImpl.PackageManagerHelper {
+
+ private final IPackageManager mPackageManager;
+ private final PackageManagerInternal mPackageManagerInternal;
+
+ // Use a cache for performance and for consistency within OMS: because
+ // additional PACKAGE_* intents may be delivered while we process an
+ // intent, querying the PackageManagerService for the actual current
+ // state may lead to contradictions within OMS. Better then to lag
+ // behind until all pending intents have been processed.
+ private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
+
+ PackageManagerHelper() {
+ mPackageManager = getPackageManager();
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ }
+
+ public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
+ final boolean useCache) {
+ if (useCache) {
+ final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
+ if (cachedPi != null) {
+ return cachedPi;
+ }
+ }
+ try {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
+ if (useCache && pi != null) {
+ cachePackageInfo(packageName, userId, pi);
+ }
+ return pi;
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ return null;
+ }
+
+ @Override
+ public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
+ return getPackageInfo(packageName, userId, true);
+ }
+
+ @Override
+ public boolean signaturesMatching(@NonNull final String packageName1,
+ @NonNull final String packageName2, final int userId) {
+ // The package manager does not support different versions of packages
+ // to be installed for different users: ignore userId for now.
+ try {
+ return mPackageManager.checkSignatures(packageName1, packageName2) == SIGNATURE_MATCH;
+ } catch (RemoteException e) {
+ // Intentionally left blank
+ }
+ return false;
+ }
+
+ @Override
+ public List<PackageInfo> getOverlayPackages(final int userId) {
+ return mPackageManagerInternal.getOverlayPackages(userId);
+ }
+
+ public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
+ final int userId) {
+ final HashMap<String, PackageInfo> map = mCache.get(userId);
+ return map == null ? null : map.get(packageName);
+ }
+
+ public void cachePackageInfo(@NonNull final String packageName, final int userId,
+ @NonNull final PackageInfo pi) {
+ HashMap<String, PackageInfo> map = mCache.get(userId);
+ if (map == null) {
+ map = new HashMap<>();
+ mCache.put(userId, map);
+ }
+ map.put(packageName, pi);
+ }
+
+ public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
+ final HashMap<String, PackageInfo> map = mCache.get(userId);
+ if (map == null) {
+ return;
+ }
+ map.remove(packageName);
+ if (map.isEmpty()) {
+ mCache.delete(userId);
+ }
+ }
+
+ public void forgetAllPackageInfos(final int userId) {
+ mCache.delete(userId);
+ }
+
+ private static final String TAB1 = " ";
+ private static final String TAB2 = TAB1 + TAB1;
+
+ public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
+ pw.println("PackageInfo cache");
+
+ if (!verbose) {
+ int count = 0;
+ final int N = mCache.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mCache.keyAt(i);
+ count += mCache.get(userId).size();
+ }
+ pw.println(TAB1 + count + " package(s)");
+ return;
+ }
+
+ if (mCache.size() == 0) {
+ pw.println(TAB1 + "<empty>");
+ return;
+ }
+
+ final int N = mCache.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mCache.keyAt(i);
+ pw.println(TAB1 + "User " + userId);
+ final HashMap<String, PackageInfo> map = mCache.get(userId);
+ for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
+ pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
new file mode 100644
index 000000000000..0e33409cd0ea
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import static android.content.om.OverlayInfo.STATE_DISABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED;
+import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Internal implementation of OverlayManagerService.
+ *
+ * Methods in this class should only be called by the OverlayManagerService.
+ * This class is not thread-safe; the caller is expected to ensure the
+ * necessary thread synchronization.
+ *
+ * @see OverlayManagerService
+ */
+final class OverlayManagerServiceImpl {
+ private final PackageManagerHelper mPackageManager;
+ private final IdmapManager mIdmapManager;
+ private final OverlayManagerSettings mSettings;
+
+ OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
+ @NonNull final IdmapManager idmapManager,
+ @NonNull final OverlayManagerSettings settings) {
+ mPackageManager = packageManager;
+ mIdmapManager = idmapManager;
+ mSettings = settings;
+ }
+
+ /*
+ * Call this when switching to a new Android user. Will return a list of
+ * target packages that must refresh their overlays. This list is the union
+ * of two sets: the set of targets with currently active overlays, and the
+ * set of targets that had, but no longer have, active overlays.
+ */
+ List<String> onSwitchUser(final int newUserId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onSwitchUser newUserId=" + newUserId);
+ }
+
+ final Set<String> packagesToUpdateAssets = new ArraySet<>();
+ final ArrayMap<String, List<OverlayInfo>> tmp = mSettings.getOverlaysForUser(newUserId);
+ final int tmpSize = tmp.size();
+ final ArrayMap<String, OverlayInfo> storedOverlayInfos = new ArrayMap<>(tmpSize);
+ for (int i = 0; i < tmpSize; i++) {
+ final List<OverlayInfo> chunk = tmp.valueAt(i);
+ final int chunkSize = chunk.size();
+ for (int j = 0; j < chunkSize; j++) {
+ final OverlayInfo oi = chunk.get(j);
+ storedOverlayInfos.put(oi.packageName, oi);
+ }
+ }
+
+ List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
+ final int overlayPackagesSize = overlayPackages.size();
+ for (int i = 0; i < overlayPackagesSize; i++) {
+ final PackageInfo overlayPackage = overlayPackages.get(i);
+ final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
+ if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
+ if (oi != null) {
+ packagesToUpdateAssets.add(oi.targetPackageName);
+ }
+ mSettings.init(overlayPackage.packageName, newUserId,
+ overlayPackage.overlayTarget,
+ overlayPackage.applicationInfo.getBaseCodePath());
+ }
+
+ try {
+ final PackageInfo targetPackage =
+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, newUserId);
+ updateState(targetPackage, overlayPackage, newUserId);
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ mSettings.remove(overlayPackage.packageName, newUserId);
+ }
+
+ packagesToUpdateAssets.add(overlayPackage.overlayTarget);
+ storedOverlayInfos.remove(overlayPackage.packageName);
+ }
+
+ // any OverlayInfo left in storedOverlayInfos is no longer
+ // installed and should be removed
+ final int storedOverlayInfosSize = storedOverlayInfos.size();
+ for (int i = 0; i < storedOverlayInfosSize; i++) {
+ final OverlayInfo oi = storedOverlayInfos.get(i);
+ mSettings.remove(oi.packageName, oi.userId);
+ removeIdmapIfPossible(oi);
+ packagesToUpdateAssets.add(oi.targetPackageName);
+ }
+
+ // remove target packages that are not installed
+ final Iterator<String> iter = packagesToUpdateAssets.iterator();
+ while (iter.hasNext()) {
+ String targetPackageName = iter.next();
+ if (mPackageManager.getPackageInfo(targetPackageName, newUserId) == null) {
+ iter.remove();
+ }
+ }
+
+ return new ArrayList<String>(packagesToUpdateAssets);
+ }
+
+ void onUserRemoved(final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onUserRemoved userId=" + userId);
+ }
+ mSettings.removeUser(userId);
+ }
+
+ void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
+ }
+
+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
+ updateAllOverlaysForTarget(packageName, userId, targetPackage);
+ }
+
+ void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
+ }
+
+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
+ updateAllOverlaysForTarget(packageName, userId, targetPackage);
+ }
+
+ void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId=" + userId);
+ }
+
+ updateAllOverlaysForTarget(packageName, userId, null);
+ }
+
+ void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
+ }
+
+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
+ updateAllOverlaysForTarget(packageName, userId, targetPackage);
+ }
+
+ void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
+ }
+
+ updateAllOverlaysForTarget(packageName, userId, null);
+ }
+
+ private void updateAllOverlaysForTarget(@NonNull final String packageName, final int userId,
+ @Nullable final PackageInfo targetPackage) {
+ final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(packageName, userId);
+ final int N = ois.size();
+ for (int i = 0; i < N; i++) {
+ final OverlayInfo oi = ois.get(i);
+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId);
+ if (overlayPackage == null) {
+ mSettings.remove(oi.packageName, oi.userId);
+ removeIdmapIfPossible(oi);
+ } else {
+ try {
+ updateState(targetPackage, overlayPackage, userId);
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ mSettings.remove(oi.packageName, userId);
+ }
+ }
+ }
+ }
+
+ void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
+ }
+
+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
+ if (overlayPackage == null) {
+ Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
+ onOverlayPackageRemoved(packageName, userId);
+ return;
+ }
+
+ final PackageInfo targetPackage =
+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId);
+
+ mSettings.init(packageName, userId, overlayPackage.overlayTarget,
+ overlayPackage.applicationInfo.getBaseCodePath());
+ try {
+ updateState(targetPackage, overlayPackage, userId);
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ mSettings.remove(packageName, userId);
+ }
+ }
+
+ void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
+ Slog.wtf(TAG, "onOverlayPackageChanged called, but only pre-installed overlays supported");
+ }
+
+ void onOverlayPackageUpgrading(@NonNull final String packageName, final int userId) {
+ Slog.wtf(TAG, "onOverlayPackageUpgrading called, but only pre-installed overlays supported");
+ }
+
+ void onOverlayPackageUpgraded(@NonNull final String packageName, final int userId) {
+ Slog.wtf(TAG, "onOverlayPackageUpgraded called, but only pre-installed overlays supported");
+ }
+
+ void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
+ Slog.wtf(TAG, "onOverlayPackageRemoved called, but only pre-installed overlays supported");
+ }
+
+ OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId) {
+ try {
+ return mSettings.getOverlayInfo(packageName, userId);
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ return null;
+ }
+ }
+
+ List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName,
+ final int userId) {
+ return mSettings.getOverlaysForTarget(targetPackageName, userId);
+ }
+
+ Map<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
+ return mSettings.getOverlaysForUser(userId);
+ }
+
+ boolean setEnabled(@NonNull final String packageName, final boolean enable,
+ final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
+ packageName, enable, userId));
+ }
+
+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
+ if (overlayPackage == null) {
+ return false;
+ }
+
+ try {
+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
+ final PackageInfo targetPackage =
+ mPackageManager.getPackageInfo(oi.targetPackageName, userId);
+ mSettings.setEnabled(packageName, userId, enable);
+ updateState(targetPackage, overlayPackage, userId);
+ return true;
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ return false;
+ }
+ }
+
+ boolean setPriority(@NonNull final String packageName,
+ @NonNull final String newParentPackageName, final int userId) {
+ return mSettings.setPriority(packageName, newParentPackageName, userId);
+ }
+
+ boolean setHighestPriority(@NonNull final String packageName, final int userId) {
+ return mSettings.setHighestPriority(packageName, userId);
+ }
+
+ boolean setLowestPriority(@NonNull final String packageName, final int userId) {
+ return mSettings.setLowestPriority(packageName, userId);
+ }
+
+ void onDump(@NonNull final PrintWriter pw) {
+ mSettings.dump(pw);
+ }
+
+ List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
+ final int userId) {
+ final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName, userId);
+ final List<String> paths = new ArrayList<>(overlays.size());
+ final int N = overlays.size();
+ for (int i = 0; i < N; i++) {
+ final OverlayInfo oi = overlays.get(i);
+ if (oi.isEnabled()) {
+ paths.add(oi.packageName);
+ }
+ }
+ return paths;
+ }
+
+ private void updateState(@Nullable final PackageInfo targetPackage,
+ @NonNull final PackageInfo overlayPackage, final int userId)
+ throws OverlayManagerSettings.BadKeyException {
+ if (targetPackage != null) {
+ mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
+ }
+
+ mSettings.setBaseCodePath(overlayPackage.packageName, userId,
+ overlayPackage.applicationInfo.getBaseCodePath());
+
+ final int currentState = mSettings.getState(overlayPackage.packageName, userId);
+ final int newState = calculateNewState(targetPackage, overlayPackage, userId);
+ if (currentState != newState) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("%s:%d: %s -> %s",
+ overlayPackage.packageName, userId,
+ OverlayInfo.stateToString(currentState),
+ OverlayInfo.stateToString(newState)));
+ }
+ mSettings.setState(overlayPackage.packageName, userId, newState);
+ }
+ }
+
+ private int calculateNewState(@Nullable final PackageInfo targetPackage,
+ @NonNull final PackageInfo overlayPackage, final int userId)
+ throws OverlayManagerSettings.BadKeyException {
+ if (targetPackage == null) {
+ return STATE_MISSING_TARGET;
+ }
+
+ if (!mIdmapManager.idmapExists(overlayPackage, userId)) {
+ return STATE_NO_IDMAP;
+ }
+
+ final boolean enabled = mSettings.getEnabled(overlayPackage.packageName, userId);
+ return enabled ? STATE_ENABLED : STATE_DISABLED;
+ }
+
+ private void removeIdmapIfPossible(@NonNull final OverlayInfo oi) {
+ // For a given package, all Android users share the same idmap file.
+ // This works because Android currently does not support users to
+ // install different versions of the same package. It also means we
+ // cannot remove an idmap file if any user still needs it.
+ //
+ // When/if the Android framework allows different versions of the same
+ // package to be installed for different users, idmap file handling
+ // should be revised:
+ //
+ // - an idmap file should be unique for each {user, package} pair
+ //
+ // - the path to the idmap file should be passed to the native Asset
+ // Manager layers, just like the path to the apk is passed today
+ //
+ // As part of that change, calls to this method should be replaced by
+ // direct calls to IdmapManager.removeIdmap, without looping over all
+ // users.
+
+ if (!mIdmapManager.idmapExists(oi)) {
+ return;
+ }
+ final List<Integer> userIds = mSettings.getUsers();
+ final int N = userIds.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = userIds.get(i);
+ try {
+ final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId);
+ if (tmp != null && tmp.isEnabled()) {
+ // someone is still using the idmap file -> we cannot remove it
+ return;
+ }
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ // intentionally left empty
+ }
+ }
+ mIdmapManager.removeIdmap(oi, oi.userId);
+ }
+
+ interface PackageManagerHelper {
+ PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+ boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2,
+ int userId);
+ List<PackageInfo> getOverlayPackages(int userId);
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
new file mode 100644
index 000000000000..44908a748b32
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import static android.content.om.OverlayInfo.STATE_UNKNOWN;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayInfo;
+import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
+import android.util.Slog;
+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.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+/**
+ * Data structure representing the current state of all overlay packages in the
+ * system.
+ *
+ * Modifications to the data are exposed through the ChangeListener interface.
+ *
+ * @see ChangeListener
+ * @see OverlayManagerService
+ */
+final class OverlayManagerSettings {
+ private final List<ChangeListener> mListeners = new ArrayList<>();
+
+ private final ArrayList<SettingsItem> mItems = new ArrayList<>();
+
+ void init(@NonNull final String packageName, final int userId,
+ @NonNull final String targetPackageName, @NonNull final String baseCodePath) {
+ remove(packageName, userId);
+ final SettingsItem item =
+ new SettingsItem(packageName, userId, targetPackageName, baseCodePath);
+ mItems.add(item);
+ }
+
+ void remove(@NonNull final String packageName, final int userId) {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ return;
+ }
+ final OverlayInfo oi = item.getOverlayInfo();
+ mItems.remove(item);
+ if (oi != null) {
+ notifyOverlayRemoved(oi);
+ }
+ }
+
+ boolean contains(@NonNull final String packageName, final int userId) {
+ return select(packageName, userId) != null;
+ }
+
+ OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId)
+ throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ return item.getOverlayInfo();
+ }
+
+ String getTargetPackageName(@NonNull final String packageName, final int userId)
+ throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ return item.getTargetPackageName();
+ }
+
+ void setBaseCodePath(@NonNull final String packageName, final int userId,
+ @NonNull final String path) throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ item.setBaseCodePath(path);
+ notifySettingsChanged();
+ }
+
+ boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ return item.isEnabled();
+ }
+
+ void setEnabled(@NonNull final String packageName, final int userId, final boolean enable)
+ throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ if (enable == item.isEnabled()) {
+ return; // nothing to do
+ }
+
+ item.setEnabled(enable);
+ notifySettingsChanged();
+ }
+
+ int getState(@NonNull final String packageName, final int userId) throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ return item.getState();
+ }
+
+ void setState(@NonNull final String packageName, final int userId, final int state)
+ throws BadKeyException {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ throw new BadKeyException(packageName, userId);
+ }
+ final OverlayInfo previous = item.getOverlayInfo();
+ item.setState(state);
+ final OverlayInfo current = item.getOverlayInfo();
+ if (previous.state == STATE_UNKNOWN) {
+ notifyOverlayAdded(current);
+ notifySettingsChanged();
+ } else if (current.state != previous.state) {
+ notifyOverlayChanged(current, previous);
+ notifySettingsChanged();
+ }
+ }
+
+ List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
+ final int userId) {
+ final List<SettingsItem> items = selectWhereTarget(targetPackageName, userId);
+ if (items.isEmpty()) {
+ return Collections.emptyList();
+ }
+ final List<OverlayInfo> out = new ArrayList<>(items.size());
+ final int N = items.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = items.get(i);
+ out.add(item.getOverlayInfo());
+ }
+ return out;
+ }
+
+ ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
+ final List<SettingsItem> items = selectWhereUser(userId);
+ if (items.isEmpty()) {
+ return ArrayMap.EMPTY;
+ }
+ final ArrayMap<String, List<OverlayInfo>> out = new ArrayMap<>(items.size());
+ final int N = items.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = items.get(i);
+ final String targetPackageName = item.getTargetPackageName();
+ if (!out.containsKey(targetPackageName)) {
+ out.put(targetPackageName, new ArrayList<OverlayInfo>());
+ }
+ final List<OverlayInfo> overlays = out.get(targetPackageName);
+ overlays.add(item.getOverlayInfo());
+ }
+ return out;
+ }
+
+ List<String> getTargetPackageNamesForUser(final int userId) {
+ final List<SettingsItem> items = selectWhereUser(userId);
+ if (items.isEmpty()) {
+ return Collections.emptyList();
+ }
+ final List<String> out = new ArrayList<>();
+ final int N = items.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = items.get(i);
+ final String targetPackageName = item.getTargetPackageName();
+ if (!out.contains(targetPackageName)) {
+ out.add(targetPackageName);
+ }
+ }
+ return out;
+ }
+
+ List<Integer> getUsers() {
+ final ArrayList<Integer> users = new ArrayList<>();
+ final int N = mItems.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = mItems.get(i);
+ if (!users.contains(item.userId)) {
+ users.add(item.userId);
+ }
+ }
+ return users;
+ }
+
+ void removeUser(final int userId) {
+ final Iterator<SettingsItem> iter = mItems.iterator();
+ while (iter.hasNext()) {
+ final SettingsItem item = iter.next();
+ if (item.userId == userId) {
+ iter.remove();
+ }
+ }
+ }
+
+ boolean setPriority(@NonNull final String packageName,
+ @NonNull final String newParentPackageName, final int userId) {
+ if (packageName.equals(newParentPackageName)) {
+ return false;
+ }
+ final SettingsItem rowToMove = select(packageName, userId);
+ if (rowToMove == null) {
+ return false;
+ }
+ final SettingsItem newParentRow = select(newParentPackageName, userId);
+ if (newParentRow == null) {
+ return false;
+ }
+ if (!rowToMove.getTargetPackageName().equals(newParentRow.getTargetPackageName())) {
+ return false;
+ }
+
+ mItems.remove(rowToMove);
+ final ListIterator<SettingsItem> iter = mItems.listIterator();
+ while (iter.hasNext()) {
+ final SettingsItem item = iter.next();
+ if (item.userId == userId && item.packageName.equals(newParentPackageName)) {
+ iter.add(rowToMove);
+ notifyOverlayPriorityChanged(rowToMove.getOverlayInfo());
+ notifySettingsChanged();
+ return true;
+ }
+ }
+
+ Slog.wtf(TAG, "failed to find the parent item a second time");
+ return false;
+ }
+
+ boolean setLowestPriority(@NonNull final String packageName, final int userId) {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ return false;
+ }
+ mItems.remove(item);
+ mItems.add(0, item);
+ notifyOverlayPriorityChanged(item.getOverlayInfo());
+ notifySettingsChanged();
+ return true;
+ }
+
+ boolean setHighestPriority(@NonNull final String packageName, final int userId) {
+ final SettingsItem item = select(packageName, userId);
+ if (item == null) {
+ return false;
+ }
+ mItems.remove(item);
+ mItems.add(item);
+ notifyOverlayPriorityChanged(item.getOverlayInfo());
+ notifySettingsChanged();
+ return true;
+ }
+
+ private static final String TAB1 = " ";
+ private static final String TAB2 = TAB1 + TAB1;
+ private static final String TAB3 = TAB2 + TAB1;
+
+ void dump(@NonNull final PrintWriter pw) {
+ pw.println("Settings");
+ dumpItems(pw);
+ dumpListeners(pw);
+ }
+
+ private void dumpItems(@NonNull final PrintWriter pw) {
+ pw.println(TAB1 + "Items");
+
+ if (mItems.isEmpty()) {
+ pw.println(TAB2 + "<none>");
+ return;
+ }
+
+ final int N = mItems.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = mItems.get(i);
+ final StringBuilder sb = new StringBuilder();
+ sb.append(TAB2 + item.packageName + ":" + item.userId + " {\n");
+ sb.append(TAB3 + "packageName.......: " + item.packageName + "\n");
+ sb.append(TAB3 + "userId............: " + item.userId + "\n");
+ sb.append(TAB3 + "targetPackageName.: " + item.getTargetPackageName() + "\n");
+ sb.append(TAB3 + "baseCodePath......: " + item.getBaseCodePath() + "\n");
+ sb.append(TAB3 + "state.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
+ sb.append(TAB3 + "isEnabled.........: " + item.isEnabled() + "\n");
+ sb.append(TAB2 + "}");
+ pw.println(sb.toString());
+ }
+ }
+
+ private void dumpListeners(@NonNull final PrintWriter pw) {
+ pw.println(TAB1 + "Change listeners");
+
+ if (mListeners.isEmpty()) {
+ pw.println(TAB2 + "<none>");
+ return;
+ }
+
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener ch = mListeners.get(i);
+ pw.println(TAB2 + ch);
+ }
+
+ }
+
+ void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException {
+ Serializer.restore(mItems, is);
+ }
+
+ void persist(@NonNull final OutputStream os) throws IOException, XmlPullParserException {
+ Serializer.persist(mItems, os);
+ }
+
+ private static final class Serializer {
+ private static final String TAG_OVERLAYS = "overlays";
+ private static final String TAG_ITEM = "item";
+
+ private static final String ATTR_BASE_CODE_PATH = "baseCodePath";
+ private static final String ATTR_IS_ENABLED = "isEnabled";
+ private static final String ATTR_PACKAGE_NAME = "packageName";
+ private static final String ATTR_STATE = "state";
+ private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName";
+ private static final String ATTR_USER_ID = "userId";
+ private static final String ATTR_VERSION = "version";
+
+ private static final int CURRENT_VERSION = 1;
+
+ public static void restore(@NonNull final ArrayList<SettingsItem> table,
+ @NonNull final InputStream is) throws IOException, XmlPullParserException {
+
+ try (InputStreamReader reader = new InputStreamReader(is)) {
+ table.clear();
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(reader);
+ XmlUtils.beginDocument(parser, TAG_OVERLAYS);
+ int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+ if (version != CURRENT_VERSION) {
+ throw new XmlPullParserException("unrecognized version " + version);
+ }
+ int depth = parser.getDepth();
+
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ switch (parser.getName()) {
+ case TAG_ITEM:
+ final SettingsItem item = restoreRow(parser, depth + 1);
+ table.add(item);
+ break;
+ }
+ }
+ }
+ }
+
+ private static SettingsItem restoreRow(@NonNull final XmlPullParser parser, final int depth)
+ throws IOException {
+ final String packageName = XmlUtils.readStringAttribute(parser, ATTR_PACKAGE_NAME);
+ final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID);
+ final String targetPackageName = XmlUtils.readStringAttribute(parser,
+ ATTR_TARGET_PACKAGE_NAME);
+ final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH);
+ final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE);
+ final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
+
+ return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, state,
+ isEnabled);
+ }
+
+ public static void persist(@NonNull final ArrayList<SettingsItem> table,
+ @NonNull final OutputStream os) throws IOException, XmlPullParserException {
+ final FastXmlSerializer xml = new FastXmlSerializer();
+ xml.setOutput(os, "utf-8");
+ xml.startDocument(null, true);
+ xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ xml.startTag(null, TAG_OVERLAYS);
+ XmlUtils.writeIntAttribute(xml, ATTR_VERSION, CURRENT_VERSION);
+
+ final int N = table.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = table.get(i);
+ persistRow(xml, item);
+ }
+ xml.endTag(null, TAG_OVERLAYS);
+ xml.endDocument();
+ }
+
+ private static void persistRow(@NonNull final FastXmlSerializer xml,
+ @NonNull final SettingsItem item) throws IOException {
+ xml.startTag(null, TAG_ITEM);
+ XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.packageName);
+ XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.userId);
+ XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.targetPackageName);
+ XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.baseCodePath);
+ XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.state);
+ XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.isEnabled);
+ xml.endTag(null, TAG_ITEM);
+ }
+ }
+
+ private static final class SettingsItem {
+ private final int userId;
+ private final String packageName;
+ private final String targetPackageName;
+ private String baseCodePath;
+ private int state;
+ private boolean isEnabled;
+ private OverlayInfo cache;
+
+ SettingsItem(@NonNull final String packageName, final int userId,
+ @NonNull final String targetPackageName, @NonNull final String baseCodePath,
+ final int state, final boolean isEnabled) {
+ this.packageName = packageName;
+ this.userId = userId;
+ this.targetPackageName = targetPackageName;
+ this.baseCodePath = baseCodePath;
+ this.state = state;
+ this.isEnabled = isEnabled;
+ cache = null;
+ }
+
+ SettingsItem(@NonNull final String packageName, final int userId,
+ @NonNull final String targetPackageName, @NonNull final String baseCodePath) {
+ this(packageName, userId, targetPackageName, baseCodePath, STATE_UNKNOWN,
+ false);
+ }
+
+ private String getTargetPackageName() {
+ return targetPackageName;
+ }
+
+ private String getBaseCodePath() {
+ return baseCodePath;
+ }
+
+ private void setBaseCodePath(@NonNull final String path) {
+ if (!baseCodePath.equals(path)) {
+ baseCodePath = path;
+ invalidateCache();
+ }
+ }
+
+ private int getState() {
+ return state;
+ }
+
+ private void setState(final int state) {
+ if (this.state != state) {
+ this.state = state;
+ invalidateCache();
+ }
+ }
+
+ private boolean isEnabled() {
+ return isEnabled;
+ }
+
+ private void setEnabled(final boolean enable) {
+ if (isEnabled != enable) {
+ isEnabled = enable;
+ invalidateCache();
+ }
+ }
+
+ private OverlayInfo getOverlayInfo() {
+ if (cache == null) {
+ cache = new OverlayInfo(packageName, targetPackageName, baseCodePath,
+ state, userId);
+ }
+ return cache;
+ }
+
+ private void invalidateCache() {
+ cache = null;
+ }
+ }
+
+ private SettingsItem select(@NonNull final String packageName, final int userId) {
+ final int N = mItems.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = mItems.get(i);
+ if (item.userId == userId && item.packageName.equals(packageName)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ private List<SettingsItem> selectWhereUser(final int userId) {
+ final ArrayList<SettingsItem> items = new ArrayList<>();
+ final int N = mItems.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = mItems.get(i);
+ if (item.userId == userId) {
+ items.add(item);
+ }
+ }
+ return items;
+ }
+
+ private List<SettingsItem> selectWhereTarget(@NonNull final String targetPackageName,
+ final int userId) {
+ final ArrayList<SettingsItem> items = new ArrayList<>();
+ final int N = mItems.size();
+ for (int i = 0; i < N; i++) {
+ final SettingsItem item = mItems.get(i);
+ if (item.userId == userId && item.getTargetPackageName().equals(targetPackageName)) {
+ items.add(item);
+ }
+ }
+ return items;
+ }
+
+ private void assertNotNull(@Nullable final Object o) {
+ if (o == null) {
+ throw new AndroidRuntimeException("object must not be null");
+ }
+ }
+
+ void addChangeListener(@NonNull final ChangeListener listener) {
+ mListeners.add(listener);
+ }
+
+ void removeChangeListener(@NonNull final ChangeListener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifySettingsChanged() {
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener listener = mListeners.get(i);
+ listener.onSettingsChanged();
+ }
+ }
+
+ private void notifyOverlayAdded(@NonNull final OverlayInfo oi) {
+ if (DEBUG) {
+ assertNotNull(oi);
+ }
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener listener = mListeners.get(i);
+ listener.onOverlayAdded(oi);
+ }
+ }
+
+ private void notifyOverlayRemoved(@NonNull final OverlayInfo oi) {
+ if (DEBUG) {
+ assertNotNull(oi);
+ }
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener listener = mListeners.get(i);
+ listener.onOverlayRemoved(oi);
+ }
+ }
+
+ private void notifyOverlayChanged(@NonNull final OverlayInfo oi,
+ @NonNull final OverlayInfo oldOi) {
+ if (DEBUG) {
+ assertNotNull(oi);
+ assertNotNull(oldOi);
+ }
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener listener = mListeners.get(i);
+ listener.onOverlayChanged(oi, oldOi);
+ }
+ }
+
+ private void notifyOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
+ if (DEBUG) {
+ assertNotNull(oi);
+ }
+ final int N = mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final ChangeListener listener = mListeners.get(i);
+ listener.onOverlayPriorityChanged(oi);
+ }
+ }
+
+ interface ChangeListener {
+ void onSettingsChanged();
+ void onOverlayAdded(@NonNull OverlayInfo oi);
+ void onOverlayRemoved(@NonNull OverlayInfo oi);
+ void onOverlayChanged(@NonNull OverlayInfo oi, @NonNull OverlayInfo oldOi);
+ void onOverlayPriorityChanged(@NonNull OverlayInfo oi);
+ }
+
+ static final class BadKeyException extends RuntimeException {
+ BadKeyException(@NonNull final String packageName, final int userId) {
+ super("Bad key packageName=" + packageName + " userId=" + userId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
new file mode 100644
index 000000000000..29ddaf49e200
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of 'cmd overlay' commands.
+ *
+ * This class provides an interface to the OverlayManagerService via adb.
+ * Intended only for manual debugging. Execute 'adb exec-out cmd overlay help'
+ * for a list of available commands.
+ */
+final class OverlayManagerShellCommand extends ShellCommand {
+ private final IOverlayManager mInterface;
+
+ OverlayManagerShellCommand(@NonNull final IOverlayManager iom) {
+ mInterface = iom;
+ }
+
+ @Override
+ public int onCommand(@Nullable final String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter err = getErrPrintWriter();
+ try {
+ switch (cmd) {
+ case "list":
+ return runList();
+ case "enable":
+ return runEnableDisable(true);
+ case "disable":
+ return runEnableDisable(false);
+ case "set-priority":
+ return runSetPriority();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (IllegalArgumentException e) {
+ err.println("Error: " + e.getMessage());
+ } catch (RemoteException e) {
+ err.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter out = getOutPrintWriter();
+ out.println("Overlay manager (overlay) commands:");
+ out.println(" help");
+ out.println(" Print this help text.");
+ out.println(" dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
+ out.println(" Print debugging information about the overlay manager.");
+ out.println(" list [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
+ out.println(" Print information about target and overlay packages.");
+ out.println(" Overlay packages are printed in priority order. With optional");
+ out.println(" parameters PACKAGEs, limit output to the specified packages");
+ out.println(" but include more information about each package.");
+ out.println(" enable [--user USER_ID] PACKAGE");
+ out.println(" Enable overlay package PACKAGE.");
+ out.println(" disable [--user USER_ID] PACKAGE");
+ out.println(" Disable overlay package PACKAGE.");
+ out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest");
+ out.println(" Change the priority of the overlay PACKAGE to be just higher than");
+ out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword");
+ out.println(" 'lowest', change priority of PACKAGE to the lowest priority.");
+ out.println(" If PARENT is the special keyword 'highest', change priority of");
+ out.println(" PACKAGE to the highest priority.");
+ }
+
+ private int runList() throws RemoteException {
+ final PrintWriter out = getOutPrintWriter();
+ final PrintWriter err = getErrPrintWriter();
+
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ err.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId);
+ for (final String targetPackageName : allOverlays.keySet()) {
+ out.println(targetPackageName);
+ List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName);
+ final int N = overlaysForTarget.size();
+ for (int i = 0; i < N; i++) {
+ final OverlayInfo oi = overlaysForTarget.get(i);
+ String status;
+ switch (oi.state) {
+ case OverlayInfo.STATE_ENABLED:
+ status = "[x]";
+ break;
+ case OverlayInfo.STATE_DISABLED:
+ status = "[ ]";
+ break;
+ default:
+ status = "---";
+ break;
+ }
+ out.println(String.format("%s %s", status, oi.packageName));
+ }
+ out.println();
+ }
+ return 0;
+ }
+
+ private int runEnableDisable(final boolean enable) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ err.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final String packageName = getNextArgRequired();
+ return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1;
+ }
+
+ private int runSetPriority() throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ err.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final String packageName = getNextArgRequired();
+ final String newParentPackageName = getNextArgRequired();
+
+ if ("highest".equals(newParentPackageName)) {
+ return mInterface.setHighestPriority(packageName, userId) ? 0 : 1;
+ } else if ("lowest".equals(newParentPackageName)) {
+ return mInterface.setLowestPriority(packageName, userId) ? 0 : 1;
+ } else {
+ return mInterface.setPriority(packageName, newParentPackageName, userId) ? 0 : 1;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 601a2194e8f3..66977d66e0a5 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -30,10 +30,13 @@ import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Environment;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
+import com.android.server.pm.dex.DexManager;
+
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;
@@ -59,21 +62,33 @@ public class BackgroundDexOptService extends JobService {
"android",
BackgroundDexOptService.class.getName());
+ // Possible return codes of individual optimization steps.
+
+ // Optimizations finished. All packages were processed.
+ private static final int OPTIMIZE_PROCESSED = 0;
+ // Optimizations should continue. Issued after checking the scheduler, disk space or battery.
+ private static final int OPTIMIZE_CONTINUE = 1;
+ // Optimizations should be aborted. Job scheduler requested it.
+ private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2;
+ // Optimizations should be aborted. No space left on device.
+ private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3;
+
/**
* Set of failed packages remembered across job runs.
*/
- static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
+ static final ArraySet<String> sFailedPackageNamesPrimary = new ArraySet<String>();
+ static final ArraySet<String> sFailedPackageNamesSecondary = new ArraySet<String>();
/**
* Atomics set to true if the JobScheduler requests an abort.
*/
- final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
- final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
+ private final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
+ private final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
/**
* Atomic set to true if one job should exit early because another job was started.
*/
- final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
+ private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
private final File mDataDir = Environment.getDataDirectory();
@@ -104,8 +119,11 @@ public class BackgroundDexOptService extends JobService {
// The idle maintanance job skips packages which previously failed to
// compile. The given package has changed and may successfully compile
// now. Remove it from the list of known failing packages.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.remove(packageName);
+ synchronized (sFailedPackageNamesPrimary) {
+ sFailedPackageNamesPrimary.remove(packageName);
+ }
+ synchronized (sFailedPackageNamesSecondary) {
+ sFailedPackageNamesSecondary.remove(packageName);
}
}
@@ -124,9 +142,9 @@ public class BackgroundDexOptService extends JobService {
return (100 * level / scale);
}
- private long getLowStorageThreshold() {
+ private long getLowStorageThreshold(Context context) {
@SuppressWarnings("deprecation")
- final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
+ final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
if (lowThreshold == 0) {
Log.e(TAG, "Invalid low storage threshold");
}
@@ -155,7 +173,7 @@ public class BackgroundDexOptService extends JobService {
// Load low battery threshold from the system config. This is a 0-100 integer.
final int lowBatteryThreshold = getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
- final long lowThreshold = getLowStorageThreshold();
+ final long lowThreshold = getLowStorageThreshold(this);
mAbortPostBootUpdate.set(false);
@@ -206,61 +224,123 @@ public class BackgroundDexOptService extends JobService {
new Thread("BackgroundDexOptService_IdleOptimization") {
@Override
public void run() {
- idleOptimization(jobParams, pm, pkgs);
+ int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
+ if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ Log.w(TAG, "Idle optimizations aborted because of space constraints.");
+ // If we didn't abort we ran to completion (or stopped because of space).
+ // Abandon our timeslice and do not reschedule.
+ jobFinished(jobParams, /* reschedule */ false);
+ }
}
}.start();
return true;
}
- private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
- ArraySet<String> pkgs) {
+ // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
+ private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) {
Log.i(TAG, "Performing idle optimizations");
// If post-boot update is still running, request that it exits early.
mExitPostBootUpdate.set(true);
-
mAbortIdleOptimization.set(false);
- final long lowThreshold = getLowStorageThreshold();
+ long lowStorageThreshold = getLowStorageThreshold(context);
+ // Optimize primary apks.
+ int result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ true,
+ sFailedPackageNamesPrimary);
+
+ if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ return result;
+ }
+
+ if (SystemProperties.getBoolean("dalvik.vm.deopt.secondary", false)) {
+ result = reconcileSecondaryDexFiles(pm.getDexManager());
+ if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ return result;
+ }
+
+ result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ false,
+ sFailedPackageNamesSecondary);
+ }
+ return result;
+ }
+
+ private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ long lowStorageThreshold, boolean is_for_primary_dex,
+ ArraySet<String> failedPackageNames) {
for (String pkg : pkgs) {
- if (mAbortIdleOptimization.get()) {
- // JobScheduler requested an early abort.
- return;
+ int abort_code = abortIdleOptimizations(lowStorageThreshold);
+ if (abort_code != OPTIMIZE_CONTINUE) {
+ return abort_code;
}
- synchronized (sFailedPackageNames) {
- if (sFailedPackageNames.contains(pkg)) {
+ synchronized (failedPackageNames) {
+ if (failedPackageNames.contains(pkg)) {
// Skip previously failing package
continue;
+ } else {
+ // Conservatively add package to the list of failing ones in case performDexOpt
+ // never returns.
+ failedPackageNames.add(pkg);
}
}
- long usableSpace = mDataDir.getUsableSpace();
- if (usableSpace < lowThreshold) {
- // Rather bail than completely fill up the disk.
- Log.w(TAG, "Aborting background dex opt job due to low storage: " +
- usableSpace);
- break;
- }
-
- // Conservatively add package to the list of failing ones in case performDexOpt
- // never returns.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.add(pkg);
- }
// Optimize package if needed. Note that there can be no race between
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
- if (pm.performDexOpt(pkg,
- /* checkProfiles */ true,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
- /* force */ false)) {
+ boolean success = is_for_primary_dex
+ ? pm.performDexOpt(pkg,
+ /* checkProfiles */ true,
+ PackageManagerService.REASON_BACKGROUND_DEXOPT,
+ /* force */ false)
+ : pm.performDexOptSecondary(pkg,
+ PackageManagerServiceCompilerMapping.getFullCompilerFilter(),
+ /* force */ true);
+ if (success) {
// Dexopt succeeded, remove package from the list of failing ones.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.remove(pkg);
+ synchronized (failedPackageNames) {
+ failedPackageNames.remove(pkg);
}
}
}
- // Ran to completion, so we abandon our timeslice and do not reschedule.
- jobFinished(jobParams, /* reschedule */ false);
+ return OPTIMIZE_PROCESSED;
+ }
+
+ private int reconcileSecondaryDexFiles(DexManager dm) {
+ // TODO(calin): should we blacklist packages for which we fail to reconcile?
+ for (String p : dm.getAllPackagesWithSecondaryDexFiles()) {
+ if (mAbortIdleOptimization.get()) {
+ return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
+ }
+ dm.reconcileSecondaryDexFiles(p);
+ }
+ return OPTIMIZE_PROCESSED;
+ }
+
+ // Evaluate whether or not idle optimizations should continue.
+ private int abortIdleOptimizations(long lowStorageThreshold) {
+ if (mAbortIdleOptimization.get()) {
+ // JobScheduler requested an early abort.
+ return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
+ }
+ long usableSpace = mDataDir.getUsableSpace();
+ if (usableSpace < lowStorageThreshold) {
+ // Rather bail than completely fill up the disk.
+ Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
+ return OPTIMIZE_ABORT_NO_SPACE_LEFT;
+ }
+
+ return OPTIMIZE_CONTINUE;
+ }
+
+ /**
+ * Execute the idle optimizations immediately.
+ */
+ public static boolean runIdleOptimizationsNow(PackageManagerService pm, Context context) {
+ // Create a new object to make sure we don't interfere with the scheduled jobs.
+ // Note that this may still run at the same time with the job scheduled by the
+ // JobScheduler but the scheduler will not be able to cancel it.
+ BackgroundDexOptService bdos = new BackgroundDexOptService();
+ int result = bdos.idleOptimization(pm, pm.getOptimizablePackages(), context);
+ return result == OPTIMIZE_PROCESSED;
}
@Override
@@ -281,7 +361,7 @@ public class BackgroundDexOptService extends JobService {
}
final ArraySet<String> pkgs = pm.getOptimizablePackages();
- if (pkgs == null || pkgs.isEmpty()) {
+ if (pkgs.isEmpty()) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "No packages to optimize");
}
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 8948fa3f74df..07c9dec7b353 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -95,7 +95,7 @@ final class BasePermission {
&& (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
}
- public boolean isEphemeral() {
+ public boolean isInstant() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0;
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 95023daae096..9da94b3007ee 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -764,6 +764,23 @@ final class DefaultPermissionGrantPolicy {
}
}
+ public void grantDefaultPermissionsToEnabledImsServicesLPr(String[] packageNames, int userId) {
+ Log.i(TAG, "Granting permissions to enabled ImsServices for user:" + userId);
+ if (packageNames == null) {
+ return;
+ }
+ for (String packageName : packageNames) {
+ PackageParser.Package imsServicePackage = getSystemPackageLPr(packageName);
+ if (imsServicePackage != null
+ && doesPackageSupportRuntimePermissions(imsServicePackage)) {
+ grantRuntimePermissionsLPw(imsServicePackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, CAMERA_PERMISSIONS, userId);
+ }
+ }
+ }
+
public void grantDefaultPermissionsToDefaultBrowserLPr(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default browser for user:" + userId);
if (packageName == null) {
diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
deleted file mode 100644
index 3d946e02161a..000000000000
--- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.EphemeralApplicationInfo;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Binder;
-import android.os.Environment;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.util.Xml;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.XmlUtils;
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * This class is a part of the package manager service that is responsible
- * for managing data associated with ephemeral apps such as cached uninstalled
- * ephemeral apps and ephemeral apps' cookies.
- */
-class EphemeralApplicationRegistry {
- private static final boolean DEBUG = false;
-
- private static final boolean ENABLED = true;
-
- private static final String LOG_TAG = "EphemeralAppRegistry";
-
- private static final long DEFAULT_UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS =
- DEBUG ? 60 * 1000L /* one min */ : 30 * 24 * 60 * 60 * 1000L; /* one month */
-
- private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
-
- private static final String EPHEMERAL_APPS_FOLDER = "ephemeral";
- private static final String EPHEMERAL_APP_ICON_FILE = "icon.png";
- private static final String EPHEMERAL_APP_COOKIE_FILE_PREFIX = "cookie_";
- private static final String EPHEMERAL_APP_COOKIE_FILE_SIFFIX = ".dat";
- private static final String EPHEMERAL_APP_METADATA_FILE = "metadata.xml";
-
- private static final String TAG_PACKAGE = "package";
- private static final String TAG_PERMS = "perms";
- private static final String TAG_PERM = "perm";
-
- private static final String ATTR_LABEL = "label";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_GRANTED = "granted";
-
- private final PackageManagerService mService;
-
- @GuardedBy("mService.mPackages")
- private SparseArray<List<UninstalledEphemeralAppState>> mUninstalledEphemeralApps;
-
- /**
- * Automatic grants for access to instant app metadata.
- * The key is the target application UID.
- * The value is a set of instant app UIDs.
- * UserID -> TargetAppId -> InstantAppId
- */
- private SparseArray<SparseArray<SparseBooleanArray>> mEphemeralGrants;
- /** The set of all installed instant apps. UserID -> AppID */
- private SparseArray<SparseBooleanArray> mInstalledEphemeralAppUids;
-
- public EphemeralApplicationRegistry(PackageManagerService service) {
- mService = service;
- }
-
- public byte[] getEphemeralApplicationCookieLPw(String packageName, int userId) {
- if (!ENABLED) {
- return EmptyArray.BYTE;
- }
- pruneUninstalledEphemeralAppsLPw(userId);
-
- File cookieFile = peekEphemeralCookieFile(packageName, userId);
- if (cookieFile != null && cookieFile.exists()) {
- try {
- return IoUtils.readFileAsByteArray(cookieFile.toString());
- } catch (IOException e) {
- Slog.w(LOG_TAG, "Error reading cookie file: " + cookieFile);
- }
- }
- return null;
- }
-
- public boolean setEphemeralApplicationCookieLPw(String packageName,
- byte[] cookie, int userId) {
- if (!ENABLED) {
- return false;
- }
- pruneUninstalledEphemeralAppsLPw(userId);
-
- PackageParser.Package pkg = mService.mPackages.get(packageName);
- if (pkg == null) {
- return false;
- }
-
- if (!isValidCookie(mService.mContext, cookie)) {
- return false;
- }
-
- File appDir = getEphemeralApplicationDir(pkg.packageName, userId);
- if (!appDir.exists() && !appDir.mkdirs()) {
- return false;
- }
-
- File cookieFile = computeEphemeralCookieFile(pkg, userId);
- if (cookieFile.exists() && !cookieFile.delete()) {
- return false;
- }
-
- try (FileOutputStream fos = new FileOutputStream(cookieFile)) {
- fos.write(cookie, 0, cookie.length);
- } catch (IOException e) {
- Slog.w(LOG_TAG, "Error writing cookie file: " + cookieFile);
- return false;
- }
- return true;
- }
-
- public Bitmap getEphemeralApplicationIconLPw(String packageName, int userId) {
- if (!ENABLED) {
- return null;
- }
- pruneUninstalledEphemeralAppsLPw(userId);
-
- File iconFile = new File(getEphemeralApplicationDir(packageName, userId),
- EPHEMERAL_APP_ICON_FILE);
- if (iconFile.exists()) {
- return BitmapFactory.decodeFile(iconFile.toString());
- }
- return null;
- }
-
- public List<EphemeralApplicationInfo> getEphemeralApplicationsLPw(int userId) {
- if (!ENABLED) {
- return Collections.emptyList();
- }
- pruneUninstalledEphemeralAppsLPw(userId);
-
- List<EphemeralApplicationInfo> result = getInstalledEphemeralApplicationsLPr(userId);
- result.addAll(getUninstalledEphemeralApplicationsLPr(userId));
- return result;
- }
-
- public void onPackageInstalledLPw(PackageParser.Package pkg) {
- if (!ENABLED) {
- return;
- }
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- pruneUninstalledEphemeralAppsLPw(userId);
-
- // Ignore not installed apps
- if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) {
- continue;
- }
-
- // Propagate permissions before removing any state
- // TODO: Fix this later
- // propagateEphemeralAppPermissionsIfNeeded(pkg, userId);
- if (pkg.applicationInfo.isEphemeralApp()) {
- addEphemeralAppLPw(userId, ps.appId);
- }
-
- // Remove the in-memory state
- if (mUninstalledEphemeralApps != null) {
- List<UninstalledEphemeralAppState> uninstalledAppStates =
- mUninstalledEphemeralApps.get(userId);
- if (uninstalledAppStates != null) {
- final int appCount = uninstalledAppStates.size();
- for (int i = 0; i < appCount; i++) {
- UninstalledEphemeralAppState uninstalledAppState =
- uninstalledAppStates.get(i);
- if (uninstalledAppState.mEphemeralApplicationInfo
- .getPackageName().equals(pkg.packageName)) {
- uninstalledAppStates.remove(i);
- break;
- }
- }
- }
- }
-
- // Remove the on-disk state except the cookie
- File ephemeralAppDir = getEphemeralApplicationDir(pkg.packageName, userId);
- new File(ephemeralAppDir, EPHEMERAL_APP_METADATA_FILE).delete();
- new File(ephemeralAppDir, EPHEMERAL_APP_ICON_FILE).delete();
-
- // If app signature changed - wipe the cookie
- File currentCookieFile = peekEphemeralCookieFile(pkg.packageName, userId);
- if (currentCookieFile == null) {
- continue;
- }
- File expectedCookeFile = computeEphemeralCookieFile(pkg, userId);
- if (!currentCookieFile.equals(expectedCookeFile)) {
- Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
- + " changed - dropping cookie");
- currentCookieFile.delete();
- }
- }
- }
-
- public void onPackageUninstalledLPw(PackageParser.Package pkg) {
- if (!ENABLED) {
- return;
- }
- if (pkg == null) {
- return;
- }
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- pruneUninstalledEphemeralAppsLPw(userId);
-
- if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) {
- continue;
- }
-
- if (pkg.applicationInfo.isEphemeralApp()) {
- // Add a record for an uninstalled ephemeral app
- addUninstalledEphemeralAppLPw(pkg, userId);
- removeEphemeralAppLPw(userId, ps.appId);
- } else {
- // Deleting an app prunes all ephemeral state such as cookie
- deleteDir(getEphemeralApplicationDir(pkg.packageName, userId));
- removeAppLPw(userId, ps.appId);
- }
- }
- }
-
- public void onUserRemovedLPw(int userId) {
- if (!ENABLED) {
- return;
- }
- if (mUninstalledEphemeralApps != null) {
- mUninstalledEphemeralApps.remove(userId);
- }
- if (mInstalledEphemeralAppUids != null) {
- mInstalledEphemeralAppUids.remove(userId);
- }
- if (mEphemeralGrants != null) {
- mEphemeralGrants.remove(userId);
- }
- deleteDir(getEphemeralApplicationsDir(userId));
- }
-
- public boolean isEphemeralAccessGranted(int userId, int targetAppId, int ephemeralAppId) {
- if (mEphemeralGrants == null) {
- return false;
- }
- final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
- if (targetAppList == null) {
- return false;
- }
- final SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId);
- if (ephemeralGrantList == null) {
- return false;
- }
- return ephemeralGrantList.get(ephemeralAppId);
- }
-
- public void grantEphemeralAccessLPw(int userId, Intent intent,
- int targetAppId, int ephemeralAppId) {
- if (mInstalledEphemeralAppUids == null) {
- return; // no ephemeral apps installed; no need to grant
- }
- SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
- if (ephemeralAppList == null || !ephemeralAppList.get(ephemeralAppId)) {
- return; // ephemeral app id isn't installed; no need to grant
- }
- if (ephemeralAppList.get(targetAppId)) {
- return; // target app id is an ephemeral app; no need to grant
- }
- if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
- final Set<String> categories = intent.getCategories();
- if (categories != null && categories.contains(Intent.CATEGORY_BROWSABLE)) {
- return; // launched via VIEW/BROWSABLE intent; no need to grant
- }
- }
- if (mEphemeralGrants == null) {
- mEphemeralGrants = new SparseArray<>();
- }
- SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
- if (targetAppList == null) {
- targetAppList = new SparseArray<>();
- mEphemeralGrants.put(userId, targetAppList);
- }
- SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId);
- if (ephemeralGrantList == null) {
- ephemeralGrantList = new SparseBooleanArray();
- targetAppList.put(targetAppId, ephemeralGrantList);
- }
- ephemeralGrantList.put(ephemeralAppId, true /*granted*/);
- }
-
- public void addEphemeralAppLPw(int userId, int ephemeralAppId) {
- if (mInstalledEphemeralAppUids == null) {
- mInstalledEphemeralAppUids = new SparseArray<>();
- }
- SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
- if (ephemeralAppList == null) {
- ephemeralAppList = new SparseBooleanArray();
- mInstalledEphemeralAppUids.put(userId, ephemeralAppList);
- }
- ephemeralAppList.put(ephemeralAppId, true /*installed*/);
- }
-
- private void removeEphemeralAppLPw(int userId, int ephemeralAppId) {
- // remove from the installed list
- if (mInstalledEphemeralAppUids == null) {
- return; // no ephemeral apps on the system
- }
- final SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
- if (ephemeralAppList == null) {
- Slog.w(LOG_TAG, "Remove ephemeral not in install list");
- return;
- } else {
- ephemeralAppList.delete(ephemeralAppId);
- }
- // remove any grants
- if (mEphemeralGrants == null) {
- return; // no grants on the system
- }
- final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
- if (targetAppList == null) {
- return; // no grants for this user
- }
- final int numApps = targetAppList.size();
- for (int i = targetAppList.size() - 1; i >= 0; --i) {
- targetAppList.valueAt(i).delete(ephemeralAppId);
- }
- }
-
- private void removeAppLPw(int userId, int targetAppId) {
- // remove from the installed list
- if (mEphemeralGrants == null) {
- return; // no grants on the system
- }
- final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
- if (targetAppList == null) {
- return; // no grants for this user
- }
- targetAppList.delete(targetAppId);
- }
-
- private void addUninstalledEphemeralAppLPw(PackageParser.Package pkg, int userId) {
- EphemeralApplicationInfo uninstalledApp = createEphemeralAppInfoForPackage(pkg, userId);
- if (uninstalledApp == null) {
- return;
- }
- if (mUninstalledEphemeralApps == null) {
- mUninstalledEphemeralApps = new SparseArray<>();
- }
- List<UninstalledEphemeralAppState> uninstalledAppStates =
- mUninstalledEphemeralApps.get(userId);
- if (uninstalledAppStates == null) {
- uninstalledAppStates = new ArrayList<>();
- mUninstalledEphemeralApps.put(userId, uninstalledAppStates);
- }
- UninstalledEphemeralAppState uninstalledAppState = new UninstalledEphemeralAppState(
- uninstalledApp, System.currentTimeMillis());
- uninstalledAppStates.add(uninstalledAppState);
-
- writeUninstalledEphemeralAppMetadata(uninstalledApp, userId);
- writeEphemeralApplicationIconLPw(pkg, userId);
- }
-
- private void writeEphemeralApplicationIconLPw(PackageParser.Package pkg, int userId) {
- File appDir = getEphemeralApplicationDir(pkg.packageName, userId);
- if (!appDir.exists()) {
- return;
- }
-
- Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager());
-
- final Bitmap bitmap;
- if (icon instanceof BitmapDrawable) {
- bitmap = ((BitmapDrawable) icon).getBitmap();
- } else {
- bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
- icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- icon.draw(canvas);
- }
-
- File iconFile = new File(getEphemeralApplicationDir(pkg.packageName, userId),
- EPHEMERAL_APP_ICON_FILE);
-
- try (FileOutputStream out = new FileOutputStream(iconFile)) {
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- } catch (Exception e) {
- Slog.e(LOG_TAG, "Error writing ephemeral app icon", e);
- }
- }
-
- private void pruneUninstalledEphemeralAppsLPw(int userId) {
- final long maxCacheDurationMillis = Settings.Global.getLong(
- mService.mContext.getContentResolver(),
- Settings.Global.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS,
- DEFAULT_UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS);
-
- // Prune in-memory state
- if (mUninstalledEphemeralApps != null) {
- List<UninstalledEphemeralAppState> uninstalledAppStates =
- mUninstalledEphemeralApps.get(userId);
- if (uninstalledAppStates != null) {
- final int appCount = uninstalledAppStates.size();
- for (int j = appCount - 1; j >= 0; j--) {
- UninstalledEphemeralAppState uninstalledAppState = uninstalledAppStates.get(j);
- final long elapsedCachingMillis = System.currentTimeMillis()
- - uninstalledAppState.mTimestamp;
- if (elapsedCachingMillis > maxCacheDurationMillis) {
- uninstalledAppStates.remove(j);
- }
- }
- if (uninstalledAppStates.isEmpty()) {
- mUninstalledEphemeralApps.remove(userId);
- }
- }
- }
-
- // Prune on-disk state
- File ephemeralAppsDir = getEphemeralApplicationsDir(userId);
- if (!ephemeralAppsDir.exists()) {
- return;
- }
- File[] files = ephemeralAppsDir.listFiles();
- if (files == null) {
- return;
- }
- for (File ephemeralDir : files) {
- if (!ephemeralDir.isDirectory()) {
- continue;
- }
-
- File metadataFile = new File(ephemeralDir, EPHEMERAL_APP_METADATA_FILE);
- if (!metadataFile.exists()) {
- continue;
- }
-
- final long elapsedCachingMillis = System.currentTimeMillis()
- - metadataFile.lastModified();
- if (elapsedCachingMillis > maxCacheDurationMillis) {
- deleteDir(ephemeralDir);
- }
- }
- }
-
- private List<EphemeralApplicationInfo> getInstalledEphemeralApplicationsLPr(int userId) {
- List<EphemeralApplicationInfo> result = null;
-
- final int packageCount = mService.mPackages.size();
- for (int i = 0; i < packageCount; i++) {
- PackageParser.Package pkg = mService.mPackages.valueAt(i);
- if (!pkg.applicationInfo.isEphemeralApp()) {
- continue;
- }
- EphemeralApplicationInfo info = createEphemeralAppInfoForPackage(pkg, userId);
- if (info == null) {
- continue;
- }
- if (result == null) {
- result = new ArrayList<>();
- }
- result.add(info);
- }
-
- return result;
- }
-
- private EphemeralApplicationInfo createEphemeralAppInfoForPackage(
- PackageParser.Package pkg, int userId) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return null;
- }
- PackageUserState userState = ps.readUserState(userId);
- if (userState == null || !userState.installed || userState.hidden) {
- return null;
- }
-
- String[] requestedPermissions = new String[pkg.requestedPermissions.size()];
- pkg.requestedPermissions.toArray(requestedPermissions);
-
- Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
- String[] grantedPermissions = new String[permissions.size()];
- permissions.toArray(grantedPermissions);
-
- return new EphemeralApplicationInfo(pkg.applicationInfo,
- requestedPermissions, grantedPermissions);
- }
-
- private List<EphemeralApplicationInfo> getUninstalledEphemeralApplicationsLPr(int userId) {
- List<UninstalledEphemeralAppState> uninstalledAppStates =
- getUninstalledEphemeralAppStatesLPr(userId);
- if (uninstalledAppStates == null || uninstalledAppStates.isEmpty()) {
- return Collections.emptyList();
- }
-
- List<EphemeralApplicationInfo> uninstalledApps = new ArrayList<>();
- final int stateCount = uninstalledAppStates.size();
- for (int i = 0; i < stateCount; i++) {
- UninstalledEphemeralAppState uninstalledAppState = uninstalledAppStates.get(i);
- uninstalledApps.add(uninstalledAppState.mEphemeralApplicationInfo);
- }
- return uninstalledApps;
- }
-
- private void propagateEphemeralAppPermissionsIfNeeded(PackageParser.Package pkg, int userId) {
- EphemeralApplicationInfo appInfo = getOrParseUninstalledEphemeralAppInfo(pkg.packageName, userId);
- if (appInfo == null) {
- return;
- }
- if (ArrayUtils.isEmpty(appInfo.getGrantedPermissions())) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- for (String grantedPermission : appInfo.getGrantedPermissions()) {
- mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- private EphemeralApplicationInfo getOrParseUninstalledEphemeralAppInfo(String packageName,
- int userId) {
- if (mUninstalledEphemeralApps != null) {
- List<UninstalledEphemeralAppState> uninstalledAppStates =
- mUninstalledEphemeralApps.get(userId);
- if (uninstalledAppStates != null) {
- final int appCount = uninstalledAppStates.size();
- for (int i = 0; i < appCount; i++) {
- UninstalledEphemeralAppState uninstalledAppState = uninstalledAppStates.get(i);
- if (uninstalledAppState.mEphemeralApplicationInfo
- .getPackageName().equals(packageName)) {
- return uninstalledAppState.mEphemeralApplicationInfo;
- }
- }
- }
- }
-
- File metadataFile = new File(getEphemeralApplicationDir(packageName, userId),
- EPHEMERAL_APP_METADATA_FILE);
- UninstalledEphemeralAppState uninstalledAppState = parseMetadataFile(metadataFile);
- if (uninstalledAppState == null) {
- return null;
- }
-
- return uninstalledAppState.mEphemeralApplicationInfo;
- }
-
- private List<UninstalledEphemeralAppState> getUninstalledEphemeralAppStatesLPr(int userId) {
- List<UninstalledEphemeralAppState> uninstalledAppStates = null;
- if (mUninstalledEphemeralApps != null) {
- uninstalledAppStates = mUninstalledEphemeralApps.get(userId);
- if (uninstalledAppStates != null) {
- return uninstalledAppStates;
- }
- }
-
- File ephemeralAppsDir = getEphemeralApplicationsDir(userId);
- if (ephemeralAppsDir.exists()) {
- File[] files = ephemeralAppsDir.listFiles();
- if (files != null) {
- for (File ephemeralDir : files) {
- if (!ephemeralDir.isDirectory()) {
- continue;
- }
- File metadataFile = new File(ephemeralDir,
- EPHEMERAL_APP_METADATA_FILE);
- UninstalledEphemeralAppState uninstalledAppState =
- parseMetadataFile(metadataFile);
- if (uninstalledAppState == null) {
- continue;
- }
- if (uninstalledAppStates == null) {
- uninstalledAppStates = new ArrayList<>();
- }
- uninstalledAppStates.add(uninstalledAppState);
- }
- }
- }
-
- if (uninstalledAppStates != null) {
- if (mUninstalledEphemeralApps == null) {
- mUninstalledEphemeralApps = new SparseArray<>();
- }
- mUninstalledEphemeralApps.put(userId, uninstalledAppStates);
- }
-
- return uninstalledAppStates;
- }
-
- private static boolean isValidCookie(Context context, byte[] cookie) {
- if (ArrayUtils.isEmpty(cookie)) {
- return true;
- }
- return cookie.length <= context.getPackageManager().getEphemeralCookieMaxSizeBytes();
- }
-
- private static UninstalledEphemeralAppState parseMetadataFile(File metadataFile) {
- if (!metadataFile.exists()) {
- return null;
- }
- FileInputStream in;
- try {
- in = new AtomicFile(metadataFile).openRead();
- } catch (FileNotFoundException fnfe) {
- Slog.i(LOG_TAG, "No ephemeral metadata file");
- return null;
- }
-
- final File ephemeralDir = metadataFile.getParentFile();
- final long timestamp = metadataFile.lastModified();
- final String packageName = ephemeralDir.getName();
-
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, StandardCharsets.UTF_8.name());
- return new UninstalledEphemeralAppState(
- parseMetadata(parser, packageName), timestamp);
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed parsing ephemeral"
- + " metadata file: " + metadataFile, e);
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
- private static File computeEphemeralCookieFile(PackageParser.Package pkg, int userId) {
- File appDir = getEphemeralApplicationDir(pkg.packageName, userId);
- String cookieFile = EPHEMERAL_APP_COOKIE_FILE_PREFIX + computePackageCertDigest(pkg)
- + EPHEMERAL_APP_COOKIE_FILE_SIFFIX;
- return new File(appDir, cookieFile);
- }
-
- private static File peekEphemeralCookieFile(String packageName, int userId) {
- File appDir = getEphemeralApplicationDir(packageName, userId);
- if (!appDir.exists()) {
- return null;
- }
- for (File file : appDir.listFiles()) {
- if (!file.isDirectory()
- && file.getName().startsWith(EPHEMERAL_APP_COOKIE_FILE_PREFIX)
- && file.getName().endsWith(EPHEMERAL_APP_COOKIE_FILE_SIFFIX)) {
- return file;
- }
- }
- return null;
- }
-
- private static EphemeralApplicationInfo parseMetadata(XmlPullParser parser, String packageName)
- throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (TAG_PACKAGE.equals(parser.getName())) {
- return parsePackage(parser, packageName);
- }
- }
- return null;
- }
-
- private static EphemeralApplicationInfo parsePackage(XmlPullParser parser, String packageName)
- throws IOException, XmlPullParserException {
- String label = parser.getAttributeValue(null, ATTR_LABEL);
-
- List<String> outRequestedPermissions = new ArrayList<>();
- List<String> outGrantedPermissions = new ArrayList<>();
-
- final int outerDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (TAG_PERMS.equals(parser.getName())) {
- parsePermissions(parser, outRequestedPermissions, outGrantedPermissions);
- }
- }
-
- String[] requestedPermissions = new String[outRequestedPermissions.size()];
- outRequestedPermissions.toArray(requestedPermissions);
-
- String[] grantedPermissions = new String[outGrantedPermissions.size()];
- outGrantedPermissions.toArray(grantedPermissions);
-
- return new EphemeralApplicationInfo(packageName, label,
- requestedPermissions, grantedPermissions);
- }
-
- private static void parsePermissions(XmlPullParser parser, List<String> outRequestedPermissions,
- List<String> outGrantedPermissions) throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser,outerDepth)) {
- if (TAG_PERM.equals(parser.getName())) {
- String permission = XmlUtils.readStringAttribute(parser, ATTR_NAME);
- outRequestedPermissions.add(permission);
- if (XmlUtils.readBooleanAttribute(parser, ATTR_GRANTED)) {
- outGrantedPermissions.add(permission);
- }
- }
- }
- }
-
- private void writeUninstalledEphemeralAppMetadata(
- EphemeralApplicationInfo ephemeralApp, int userId) {
- File appDir = getEphemeralApplicationDir(ephemeralApp.getPackageName(), userId);
- if (!appDir.exists() && !appDir.mkdirs()) {
- return;
- }
-
- File metadataFile = new File(appDir, EPHEMERAL_APP_METADATA_FILE);
-
- AtomicFile destination = new AtomicFile(metadataFile);
- FileOutputStream out = null;
- try {
- out = destination.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startDocument(null, true);
-
- serializer.startTag(null, TAG_PACKAGE);
- serializer.attribute(null, ATTR_LABEL, ephemeralApp.loadLabel(
- mService.mContext.getPackageManager()).toString());
-
- serializer.startTag(null, TAG_PERMS);
- for (String permission : ephemeralApp.getRequestedPermissions()) {
- serializer.startTag(null, TAG_PERM);
- serializer.attribute(null, ATTR_NAME, permission);
- if (ArrayUtils.contains(ephemeralApp.getGrantedPermissions(), permission)) {
- serializer.attribute(null, ATTR_GRANTED, String.valueOf(true));
- }
- serializer.endTag(null, TAG_PERM);
- }
- serializer.endTag(null, TAG_PERMS);
-
- serializer.endTag(null, TAG_PACKAGE);
-
- serializer.endDocument();
- destination.finishWrite(out);
- } catch (Throwable t) {
- Slog.wtf(LOG_TAG, "Failed to write ephemeral state, restoring backup", t);
- destination.failWrite(out);
- } finally {
- IoUtils.closeQuietly(out);
- }
- }
-
- private static String computePackageCertDigest(PackageParser.Package pkg) {
- MessageDigest messageDigest;
- try {
- messageDigest = MessageDigest.getInstance("SHA256");
- } catch (NoSuchAlgorithmException e) {
- /* can't happen */
- return null;
- }
-
- messageDigest.update(pkg.mSignatures[0].toByteArray());
-
- final byte[] digest = messageDigest.digest();
- final int digestLength = digest.length;
- final int charCount = 2 * digestLength;
-
- final char[] chars = new char[charCount];
- for (int i = 0; i < digestLength; i++) {
- final int byteHex = digest[i] & 0xFF;
- chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
- chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
- }
- return new String(chars);
- }
-
- private static File getEphemeralApplicationsDir(int userId) {
- return new File(Environment.getUserSystemDirectory(userId),
- EPHEMERAL_APPS_FOLDER);
- }
-
- private static File getEphemeralApplicationDir(String packageName, int userId) {
- return new File (getEphemeralApplicationsDir(userId), packageName);
- }
-
- private static void deleteDir(File dir) {
- File[] files = dir.listFiles();
- if (files != null) {
- for (File file : dir.listFiles()) {
- deleteDir(file);
- }
- }
- dir.delete();
- }
-
- private static final class UninstalledEphemeralAppState {
- final EphemeralApplicationInfo mEphemeralApplicationInfo;
- final long mTimestamp;
-
- public UninstalledEphemeralAppState(EphemeralApplicationInfo ephemeralApp,
- long timestamp) {
- mEphemeralApplicationInfo = ephemeralApp;
- mTimestamp = timestamp;
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java
index 96a0d18bbc3e..3c554221e17f 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolver.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolver.java
@@ -235,7 +235,7 @@ public abstract class EphemeralResolver {
}
List<EphemeralResponse> matchedResolveInfoList = ephemeralResolver.queryIntent(
intent, resolvedType, false /*defaultOnly*/, false /*visibleToEphemeral*/,
- false /*isEphemeral*/, userId);
+ false /*isInstant*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
return matchedResolveInfoList.get(0);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 0130e300dd8b..449d8086e083 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -50,6 +50,14 @@ public class Installer extends SystemService {
public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
/** Hint that the dexopt type is profile-guided. */
public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
+ /** The compilation is for a secondary dex file. */
+ public static final int DEXOPT_SECONDARY_DEX = 1 << 6;
+ /** Ignore the result of dexoptNeeded and force compilation. */
+ public static final int DEXOPT_FORCE = 1 << 7;
+ /** Indicates that the dex file passed to dexopt in on CE storage. */
+ public static final int DEXOPT_STORAGE_CE = 1 << 8;
+ /** Indicates that the dex file passed to dexopt in on DE storage. */
+ public static final int DEXOPT_STORAGE_DE = 1 << 9;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -295,6 +303,15 @@ public class Installer extends SystemService {
}
}
+ public void removeIdmap(String overlayApkPath) throws InstallerException {
+ if (!checkBeforeRemote()) return;
+ try {
+ mInstalld.removeIdmap(overlayApkPath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public void rmdex(String codePath, String instructionSet) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
@@ -425,6 +442,20 @@ public class Installer extends SystemService {
}
}
+ public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
+ String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
+ for (int i = 0; i < isas.length; i++) {
+ assertValidInstructionSet(isas[i]);
+ }
+ if (!checkBeforeRemote()) return false;
+ try {
+ return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
+ volumeUuid, flags);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public void invalidateMounts() throws InstallerException {
if (!checkBeforeRemote()) return;
try {
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
new file mode 100644
index 000000000000..42934a43fb25
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.Intent;
+import android.content.pm.InstantAppInfo;
+import android.content.pm.PackageParser;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.PackageUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+import libcore.io.IoUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
+/**
+ * This class is a part of the package manager service that is responsible
+ * for managing data associated with instant apps such as cached uninstalled
+ * instant apps and instant apps' cookies. In addition it is responsible for
+ * pruning installed instant apps and meta-data for uninstalled instant apps
+ * when free space is needed.
+ */
+class InstantAppRegistry {
+ private static final boolean DEBUG = false;
+
+ private static final String LOG_TAG = "InstantAppRegistry";
+
+ private static final long DEFAULT_UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS =
+ DEBUG ? 60 * 1000L /* one min */ : 6 * 30 * 24 * 60 * 60 * 1000L; /* six months */
+
+ private static final String INSTANT_APPS_FOLDER = "instant";
+ private static final String INSTANT_APP_ICON_FILE = "icon.png";
+ private static final String INSTANT_APP_COOKIE_FILE_PREFIX = "cookie_";
+ private static final String INSTANT_APP_COOKIE_FILE_SIFFIX = ".dat";
+ private static final String INSTANT_APP_METADATA_FILE = "metadata.xml";
+
+ private static final String TAG_PACKAGE = "package";
+ private static final String TAG_PERMISSIONS = "permissions";
+ private static final String TAG_PERMISSION = "permission";
+
+ private static final String ATTR_LABEL = "label";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_GRANTED = "granted";
+
+ private final PackageManagerService mService;
+ private final CookiePersistence mCookiePersistence;
+
+ /** State for uninstalled instant apps */
+ @GuardedBy("mService.mPackages")
+ private SparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
+
+ /**
+ * Automatic grants for access to instant app metadata.
+ * The key is the target application UID.
+ * The value is a set of instant app UIDs.
+ * UserID -> TargetAppId -> InstantAppId
+ */
+ @GuardedBy("mService.mPackages")
+ private SparseArray<SparseArray<SparseBooleanArray>> mInstantGrants;
+
+ /** The set of all installed instant apps. UserID -> AppID */
+ @GuardedBy("mService.mPackages")
+ private SparseArray<SparseBooleanArray> mInstalledInstantAppUids;
+
+ public InstantAppRegistry(PackageManagerService service) {
+ mService = service;
+ mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
+ }
+
+ public byte[] getInstantAppCookieLPw(@NonNull String packageName,
+ @UserIdInt int userId) {
+ byte[] pendingCookie = mCookiePersistence.getPendingPersistCookie(userId, packageName);
+ if (pendingCookie != null) {
+ return pendingCookie;
+ }
+ File cookieFile = peekInstantCookieFile(packageName, userId);
+ if (cookieFile != null && cookieFile.exists()) {
+ try {
+ return IoUtils.readFileAsByteArray(cookieFile.toString());
+ } catch (IOException e) {
+ Slog.w(LOG_TAG, "Error reading cookie file: " + cookieFile);
+ }
+ }
+ return null;
+ }
+
+ public boolean setInstantAppCookieLPw(@NonNull String packageName,
+ @Nullable byte[] cookie, @UserIdInt int userId) {
+ if (cookie != null && cookie.length > 0) {
+ final int maxCookieSize = mService.mContext.getPackageManager()
+ .getInstantAppCookieMaxSize();
+ if (cookie.length > maxCookieSize) {
+ Slog.e(LOG_TAG, "Instant app cookie for package " + packageName + " size "
+ + cookie.length + " bytes while max size is " + maxCookieSize);
+ return false;
+ }
+ }
+
+ mCookiePersistence.schedulePersist(userId, packageName, cookie);
+ return true;
+ }
+
+ private void persistInstantApplicationCookie(@Nullable byte[] cookie,
+ @NonNull String packageName, @UserIdInt int userId) {
+ synchronized (mService.mPackages) {
+ PackageParser.Package pkg = mService.mPackages.get(packageName);
+ if (pkg == null) {
+ return;
+ }
+
+ File appDir = getInstantApplicationDir(packageName, userId);
+ if (!appDir.exists() && !appDir.mkdirs()) {
+ Slog.e(LOG_TAG, "Cannot create instant app cookie directory");
+ return;
+ }
+
+ File cookieFile = computeInstantCookieFile(pkg, userId);
+ if (cookieFile.exists() && !cookieFile.delete()) {
+ Slog.e(LOG_TAG, "Cannot delete instant app cookie file");
+ }
+
+ // No cookie or an empty one means delete - done
+ if (cookie == null || cookie.length <= 0) {
+ return;
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(cookieFile)) {
+ fos.write(cookie, 0, cookie.length);
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "Error writing instant app cookie file: " + cookieFile, e);
+ }
+ }
+ }
+
+ public Bitmap getInstantAppIconLPw(@NonNull String packageName,
+ @UserIdInt int userId) {
+ File iconFile = new File(getInstantApplicationDir(packageName, userId),
+ INSTANT_APP_ICON_FILE);
+ if (iconFile.exists()) {
+ return BitmapFactory.decodeFile(iconFile.toString());
+ }
+ return null;
+ }
+
+ public @Nullable List<InstantAppInfo> getInstantAppsLPr(@UserIdInt int userId) {
+ List<InstantAppInfo> installedApps = getInstalledInstantApplicationsLPr(userId);
+ List<InstantAppInfo> uninstalledApps = getUninstalledInstantApplicationsLPr(userId);
+ if (installedApps != null) {
+ if (uninstalledApps != null) {
+ installedApps.addAll(uninstalledApps);
+ }
+ return installedApps;
+ }
+ return uninstalledApps;
+ }
+
+ public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) {
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return;
+ }
+
+ for (int userId : userIds) {
+ // Ignore not installed apps
+ if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) {
+ continue;
+ }
+
+ // Propagate permissions before removing any state
+ propagateInstantAppPermissionsIfNeeded(pkg.packageName, userId);
+
+ // Track instant apps
+ if (pkg.applicationInfo.isInstantApp()) {
+ addInstantAppLPw(userId, ps.appId);
+ }
+
+ // Remove the in-memory state
+ removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
+ state.mInstantAppInfo.getPackageName().equals(pkg.packageName),
+ userId);
+
+ // Remove the on-disk state except the cookie
+ File instantAppDir = getInstantApplicationDir(pkg.packageName, userId);
+ new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
+ new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
+
+ // If app signature changed - wipe the cookie
+ File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+ if (currentCookieFile == null) {
+ continue;
+ }
+ File expectedCookeFile = computeInstantCookieFile(pkg, userId);
+ if (!currentCookieFile.equals(expectedCookeFile)) {
+ Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
+ + " changed - dropping cookie");
+ currentCookieFile.delete();
+ }
+ }
+ }
+
+ public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg,
+ @NonNull int[] userIds) {
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return;
+ }
+
+ for (int userId : userIds) {
+ if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) {
+ continue;
+ }
+
+ if (pkg.applicationInfo.isInstantApp()) {
+ // Add a record for an uninstalled instant app
+ addUninstalledInstantAppLPw(pkg, userId);
+ removeInstantAppLPw(userId, ps.appId);
+ } else {
+ // Deleting an app prunes all instant state such as cookie
+ deleteDir(getInstantApplicationDir(pkg.packageName, userId));
+ removeAppLPw(userId, ps.appId);
+ }
+ }
+ }
+
+ public void onUserRemovedLPw(int userId) {
+ if (mUninstalledInstantApps != null) {
+ mUninstalledInstantApps.remove(userId);
+ if (mUninstalledInstantApps.size() <= 0) {
+ mUninstalledInstantApps = null;
+ }
+ }
+ if (mInstalledInstantAppUids != null) {
+ mInstalledInstantAppUids.remove(userId);
+ if (mInstalledInstantAppUids.size() <= 0) {
+ mInstalledInstantAppUids = null;
+ }
+ }
+ if (mInstantGrants != null) {
+ mInstantGrants.remove(userId);
+ if (mInstantGrants.size() <= 0) {
+ mInstantGrants = null;
+ }
+ }
+ deleteDir(getInstantApplicationsDir(userId));
+ }
+
+ public boolean isInstantAccessGranted(@UserIdInt int userId, int targetAppId,
+ int instantAppId) {
+ if (mInstantGrants == null) {
+ return false;
+ }
+ final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ if (targetAppList == null) {
+ return false;
+ }
+ final SparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
+ if (instantGrantList == null) {
+ return false;
+ }
+ return instantGrantList.get(instantAppId);
+ }
+
+ public void grantInstantAccessLPw(@UserIdInt int userId, @Nullable Intent intent,
+ int targetAppId, int instantAppId) {
+ if (mInstalledInstantAppUids == null) {
+ return; // no instant apps installed; no need to grant
+ }
+ SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ if (instantAppList == null || !instantAppList.get(instantAppId)) {
+ return; // instant app id isn't installed; no need to grant
+ }
+ if (instantAppList.get(targetAppId)) {
+ return; // target app id is an instant app; no need to grant
+ }
+ if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
+ final Set<String> categories = intent.getCategories();
+ if (categories != null && categories.contains(Intent.CATEGORY_BROWSABLE)) {
+ return; // launched via VIEW/BROWSABLE intent; no need to grant
+ }
+ }
+ if (mInstantGrants == null) {
+ mInstantGrants = new SparseArray<>();
+ }
+ SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ if (targetAppList == null) {
+ targetAppList = new SparseArray<>();
+ mInstantGrants.put(userId, targetAppList);
+ }
+ SparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
+ if (instantGrantList == null) {
+ instantGrantList = new SparseBooleanArray();
+ targetAppList.put(targetAppId, instantGrantList);
+ }
+ instantGrantList.put(instantAppId, true /*granted*/);
+ }
+
+ public void addInstantAppLPw(@UserIdInt int userId, int instantAppId) {
+ if (mInstalledInstantAppUids == null) {
+ mInstalledInstantAppUids = new SparseArray<>();
+ }
+ SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ if (instantAppList == null) {
+ instantAppList = new SparseBooleanArray();
+ mInstalledInstantAppUids.put(userId, instantAppList);
+ }
+ instantAppList.put(instantAppId, true /*installed*/);
+ }
+
+ private void removeInstantAppLPw(@UserIdInt int userId, int instantAppId) {
+ // remove from the installed list
+ if (mInstalledInstantAppUids == null) {
+ return; // no instant apps on the system
+ }
+ final SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+ if (instantAppList == null) {
+ return;
+ }
+
+ instantAppList.delete(instantAppId);
+
+ // remove any grants
+ if (mInstantGrants == null) {
+ return; // no grants on the system
+ }
+ final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ if (targetAppList == null) {
+ return; // no grants for this user
+ }
+ for (int i = targetAppList.size() - 1; i >= 0; --i) {
+ targetAppList.valueAt(i).delete(instantAppId);
+ }
+ }
+
+ private void removeAppLPw(@UserIdInt int userId, int targetAppId) {
+ // remove from the installed list
+ if (mInstantGrants == null) {
+ return; // no grants on the system
+ }
+ final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+ if (targetAppList == null) {
+ return; // no grants for this user
+ }
+ targetAppList.delete(targetAppId);
+ }
+
+ private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg,
+ @UserIdInt int userId) {
+ InstantAppInfo uninstalledApp = createInstantAppInfoForPackage(
+ pkg, userId, false);
+ if (uninstalledApp == null) {
+ return;
+ }
+ if (mUninstalledInstantApps == null) {
+ mUninstalledInstantApps = new SparseArray<>();
+ }
+ List<UninstalledInstantAppState> uninstalledAppStates =
+ mUninstalledInstantApps.get(userId);
+ if (uninstalledAppStates == null) {
+ uninstalledAppStates = new ArrayList<>();
+ mUninstalledInstantApps.put(userId, uninstalledAppStates);
+ }
+ UninstalledInstantAppState uninstalledAppState = new UninstalledInstantAppState(
+ uninstalledApp, System.currentTimeMillis());
+ uninstalledAppStates.add(uninstalledAppState);
+
+ writeUninstalledInstantAppMetadata(uninstalledApp, userId);
+ writeInstantApplicationIconLPw(pkg, userId);
+ }
+
+ private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg,
+ @UserIdInt int userId) {
+ File appDir = getInstantApplicationDir(pkg.packageName, userId);
+ if (!appDir.exists()) {
+ return;
+ }
+
+ Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager());
+
+ final Bitmap bitmap;
+ if (icon instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) icon).getBitmap();
+ } else {
+ bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
+ icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ icon.draw(canvas);
+ }
+
+ File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId),
+ INSTANT_APP_ICON_FILE);
+
+ try (FileOutputStream out = new FileOutputStream(iconFile)) {
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+ } catch (Exception e) {
+ Slog.e(LOG_TAG, "Error writing instant app icon", e);
+ }
+ }
+
+ public void deleteInstantApplicationMetadataLPw(@NonNull String packageName,
+ @UserIdInt int userId) {
+ removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
+ state.mInstantAppInfo.getPackageName().equals(packageName),
+ userId);
+
+ File instantAppDir = getInstantApplicationDir(packageName, userId);
+ new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
+ new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
+ File cookie = peekInstantCookieFile(packageName, userId);
+ if (cookie != null) {
+ cookie.delete();
+ }
+ }
+
+ private void removeUninstalledInstantAppStateLPw(
+ @NonNull Predicate<UninstalledInstantAppState> criteria, @UserIdInt int userId) {
+ if (mUninstalledInstantApps == null) {
+ return;
+ }
+ List<UninstalledInstantAppState> uninstalledAppStates =
+ mUninstalledInstantApps.get(userId);
+ if (uninstalledAppStates == null) {
+ return;
+ }
+ final int appCount = uninstalledAppStates.size();
+ for (int i = appCount - 1; i >= 0; --i) {
+ UninstalledInstantAppState uninstalledAppState = uninstalledAppStates.get(i);
+ if (!criteria.test(uninstalledAppState)) {
+ continue;
+ }
+ uninstalledAppStates.remove(i);
+ if (uninstalledAppStates.isEmpty()) {
+ mUninstalledInstantApps.remove(userId);
+ if (mUninstalledInstantApps.size() <= 0) {
+ mUninstalledInstantApps = null;
+ }
+ return;
+ }
+ }
+ }
+
+ public void pruneInstantAppsLPw() {
+ // For now we prune only state for uninstalled instant apps
+ final long maxCacheDurationMillis = Settings.Global.getLong(
+ mService.mContext.getContentResolver(),
+ Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
+ DEFAULT_UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS);
+
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ // Prune in-memory state
+ removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) -> {
+ final long elapsedCachingMillis = System.currentTimeMillis() - state.mTimestamp;
+ return (elapsedCachingMillis > maxCacheDurationMillis);
+ }, userId);
+
+ // Prune on-disk state
+ File instantAppsDir = getInstantApplicationsDir(userId);
+ if (!instantAppsDir.exists()) {
+ continue;
+ }
+ File[] files = instantAppsDir.listFiles();
+ if (files == null) {
+ continue;
+ }
+ for (File instantDir : files) {
+ if (!instantDir.isDirectory()) {
+ continue;
+ }
+
+ File metadataFile = new File(instantDir, INSTANT_APP_METADATA_FILE);
+ if (!metadataFile.exists()) {
+ continue;
+ }
+
+ final long elapsedCachingMillis = System.currentTimeMillis()
+ - metadataFile.lastModified();
+ if (elapsedCachingMillis > maxCacheDurationMillis) {
+ deleteDir(instantDir);
+ }
+ }
+ }
+ }
+
+ private @Nullable List<InstantAppInfo> getInstalledInstantApplicationsLPr(
+ @UserIdInt int userId) {
+ List<InstantAppInfo> result = null;
+
+ final int packageCount = mService.mPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ PackageParser.Package pkg = mService.mPackages.valueAt(i);
+ if (!pkg.applicationInfo.isInstantApp()) {
+ continue;
+ }
+ InstantAppInfo info = createInstantAppInfoForPackage(
+ pkg, userId, true);
+ if (info == null) {
+ continue;
+ }
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ result.add(info);
+ }
+
+ return result;
+ }
+
+ private @NonNull
+ InstantAppInfo createInstantAppInfoForPackage(
+ @NonNull PackageParser.Package pkg, @UserIdInt int userId,
+ boolean addApplicationInfo) {
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return null;
+ }
+ if (!ps.getInstalled(userId)) {
+ return null;
+ }
+
+ String[] requestedPermissions = new String[pkg.requestedPermissions.size()];
+ pkg.requestedPermissions.toArray(requestedPermissions);
+
+ Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
+ String[] grantedPermissions = new String[permissions.size()];
+ permissions.toArray(grantedPermissions);
+
+ if (addApplicationInfo) {
+ return new InstantAppInfo(pkg.applicationInfo,
+ requestedPermissions, grantedPermissions);
+ } else {
+ return new InstantAppInfo(pkg.applicationInfo.packageName,
+ pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()),
+ requestedPermissions, grantedPermissions);
+ }
+ }
+
+ private @Nullable List<InstantAppInfo> getUninstalledInstantApplicationsLPr(
+ @UserIdInt int userId) {
+ List<UninstalledInstantAppState> uninstalledAppStates =
+ getUninstalledInstantAppStatesLPr(userId);
+ if (uninstalledAppStates == null || uninstalledAppStates.isEmpty()) {
+ return null;
+ }
+
+ List<InstantAppInfo> uninstalledApps = null;
+ final int stateCount = uninstalledAppStates.size();
+ for (int i = 0; i < stateCount; i++) {
+ UninstalledInstantAppState uninstalledAppState = uninstalledAppStates.get(i);
+ if (uninstalledApps == null) {
+ uninstalledApps = new ArrayList<>();
+ }
+ uninstalledApps.add(uninstalledAppState.mInstantAppInfo);
+ }
+ return uninstalledApps;
+ }
+
+ private void propagateInstantAppPermissionsIfNeeded(@NonNull String packageName,
+ @UserIdInt int userId) {
+ InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
+ packageName, userId);
+ if (appInfo == null) {
+ return;
+ }
+ if (ArrayUtils.isEmpty(appInfo.getGrantedPermissions())) {
+ return;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ for (String grantedPermission : appInfo.getGrantedPermissions()) {
+ BasePermission bp = mService.mSettings.mPermissions.get(grantedPermission);
+ if (bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant()) {
+ mService.grantRuntimePermission(packageName, grantedPermission, userId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private @NonNull
+ InstantAppInfo peekOrParseUninstalledInstantAppInfo(
+ @NonNull String packageName, @UserIdInt int userId) {
+ if (mUninstalledInstantApps != null) {
+ List<UninstalledInstantAppState> uninstalledAppStates =
+ mUninstalledInstantApps.get(userId);
+ if (uninstalledAppStates != null) {
+ final int appCount = uninstalledAppStates.size();
+ for (int i = 0; i < appCount; i++) {
+ UninstalledInstantAppState uninstalledAppState = uninstalledAppStates.get(i);
+ if (uninstalledAppState.mInstantAppInfo
+ .getPackageName().equals(packageName)) {
+ return uninstalledAppState.mInstantAppInfo;
+ }
+ }
+ }
+ }
+
+ File metadataFile = new File(getInstantApplicationDir(packageName, userId),
+ INSTANT_APP_METADATA_FILE);
+ UninstalledInstantAppState uninstalledAppState = parseMetadataFile(metadataFile);
+ if (uninstalledAppState == null) {
+ return null;
+ }
+
+ return uninstalledAppState.mInstantAppInfo;
+ }
+
+ private @Nullable List<UninstalledInstantAppState> getUninstalledInstantAppStatesLPr(
+ @UserIdInt int userId) {
+ List<UninstalledInstantAppState> uninstalledAppStates = null;
+ if (mUninstalledInstantApps != null) {
+ uninstalledAppStates = mUninstalledInstantApps.get(userId);
+ if (uninstalledAppStates != null) {
+ return uninstalledAppStates;
+ }
+ }
+
+ File instantAppsDir = getInstantApplicationsDir(userId);
+ if (instantAppsDir.exists()) {
+ File[] files = instantAppsDir.listFiles();
+ if (files != null) {
+ for (File instantDir : files) {
+ if (!instantDir.isDirectory()) {
+ continue;
+ }
+ File metadataFile = new File(instantDir,
+ INSTANT_APP_METADATA_FILE);
+ UninstalledInstantAppState uninstalledAppState =
+ parseMetadataFile(metadataFile);
+ if (uninstalledAppState == null) {
+ continue;
+ }
+ if (uninstalledAppStates == null) {
+ uninstalledAppStates = new ArrayList<>();
+ }
+ uninstalledAppStates.add(uninstalledAppState);
+ }
+ }
+ }
+
+ if (uninstalledAppStates != null) {
+ if (mUninstalledInstantApps == null) {
+ mUninstalledInstantApps = new SparseArray<>();
+ }
+ mUninstalledInstantApps.put(userId, uninstalledAppStates);
+ }
+
+ return uninstalledAppStates;
+ }
+
+ private static @Nullable UninstalledInstantAppState parseMetadataFile(
+ @NonNull File metadataFile) {
+ if (!metadataFile.exists()) {
+ return null;
+ }
+ FileInputStream in;
+ try {
+ in = new AtomicFile(metadataFile).openRead();
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(LOG_TAG, "No instant metadata file");
+ return null;
+ }
+
+ final File instantDir = metadataFile.getParentFile();
+ final long timestamp = metadataFile.lastModified();
+ final String packageName = instantDir.getName();
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, StandardCharsets.UTF_8.name());
+ return new UninstalledInstantAppState(
+ parseMetadata(parser, packageName), timestamp);
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed parsing instant"
+ + " metadata file: " + metadataFile, e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ private static @NonNull File computeInstantCookieFile(@NonNull PackageParser.Package pkg,
+ @UserIdInt int userId) {
+ File appDir = getInstantApplicationDir(pkg.packageName, userId);
+ String cookieFile = INSTANT_APP_COOKIE_FILE_PREFIX + PackageUtils.computeSha256Digest(
+ pkg.mSignatures[0].toByteArray()) + INSTANT_APP_COOKIE_FILE_SIFFIX;
+ return new File(appDir, cookieFile);
+ }
+
+ private static @Nullable File peekInstantCookieFile(@NonNull String packageName,
+ @UserIdInt int userId) {
+ File appDir = getInstantApplicationDir(packageName, userId);
+ if (!appDir.exists()) {
+ return null;
+ }
+ File[] files = appDir.listFiles();
+ if (files == null) {
+ return null;
+ }
+ for (File file : files) {
+ if (!file.isDirectory()
+ && file.getName().startsWith(INSTANT_APP_COOKIE_FILE_PREFIX)
+ && file.getName().endsWith(INSTANT_APP_COOKIE_FILE_SIFFIX)) {
+ return file;
+ }
+ }
+ return null;
+ }
+
+ private static @Nullable
+ InstantAppInfo parseMetadata(@NonNull XmlPullParser parser,
+ @NonNull String packageName)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_PACKAGE.equals(parser.getName())) {
+ return parsePackage(parser, packageName);
+ }
+ }
+ return null;
+ }
+
+ private static InstantAppInfo parsePackage(@NonNull XmlPullParser parser,
+ @NonNull String packageName)
+ throws IOException, XmlPullParserException {
+ String label = parser.getAttributeValue(null, ATTR_LABEL);
+
+ List<String> outRequestedPermissions = new ArrayList<>();
+ List<String> outGrantedPermissions = new ArrayList<>();
+
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_PERMISSIONS.equals(parser.getName())) {
+ parsePermissions(parser, outRequestedPermissions, outGrantedPermissions);
+ }
+ }
+
+ String[] requestedPermissions = new String[outRequestedPermissions.size()];
+ outRequestedPermissions.toArray(requestedPermissions);
+
+ String[] grantedPermissions = new String[outGrantedPermissions.size()];
+ outGrantedPermissions.toArray(grantedPermissions);
+
+ return new InstantAppInfo(packageName, label,
+ requestedPermissions, grantedPermissions);
+ }
+
+ private static void parsePermissions(@NonNull XmlPullParser parser,
+ @NonNull List<String> outRequestedPermissions,
+ @NonNull List<String> outGrantedPermissions)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser,outerDepth)) {
+ if (TAG_PERMISSION.equals(parser.getName())) {
+ String permission = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+ outRequestedPermissions.add(permission);
+ if (XmlUtils.readBooleanAttribute(parser, ATTR_GRANTED)) {
+ outGrantedPermissions.add(permission);
+ }
+ }
+ }
+ }
+
+ private void writeUninstalledInstantAppMetadata(
+ @NonNull InstantAppInfo instantApp, @UserIdInt int userId) {
+ File appDir = getInstantApplicationDir(instantApp.getPackageName(), userId);
+ if (!appDir.exists() && !appDir.mkdirs()) {
+ return;
+ }
+
+ File metadataFile = new File(appDir, INSTANT_APP_METADATA_FILE);
+
+ AtomicFile destination = new AtomicFile(metadataFile);
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, StandardCharsets.UTF_8.name());
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startDocument(null, true);
+
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_LABEL, instantApp.loadLabel(
+ mService.mContext.getPackageManager()).toString());
+
+ serializer.startTag(null, TAG_PERMISSIONS);
+ for (String permission : instantApp.getRequestedPermissions()) {
+ serializer.startTag(null, TAG_PERMISSION);
+ serializer.attribute(null, ATTR_NAME, permission);
+ if (ArrayUtils.contains(instantApp.getGrantedPermissions(), permission)) {
+ serializer.attribute(null, ATTR_GRANTED, String.valueOf(true));
+ }
+ serializer.endTag(null, TAG_PERMISSION);
+ }
+ serializer.endTag(null, TAG_PERMISSIONS);
+
+ serializer.endTag(null, TAG_PACKAGE);
+
+ serializer.endDocument();
+ destination.finishWrite(out);
+ } catch (Throwable t) {
+ Slog.wtf(LOG_TAG, "Failed to write instant state, restoring backup", t);
+ destination.failWrite(out);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private static @NonNull File getInstantApplicationsDir(int userId) {
+ return new File(Environment.getUserSystemDirectory(userId),
+ INSTANT_APPS_FOLDER);
+ }
+
+ private static @NonNull File getInstantApplicationDir(String packageName, int userId) {
+ return new File (getInstantApplicationsDir(userId), packageName);
+ }
+
+ private static void deleteDir(@NonNull File dir) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ deleteDir(file);
+ }
+ }
+ dir.delete();
+ }
+
+ private static final class UninstalledInstantAppState {
+ final InstantAppInfo mInstantAppInfo;
+ final long mTimestamp;
+
+ public UninstalledInstantAppState(InstantAppInfo instantApp,
+ long timestamp) {
+ mInstantAppInfo = instantApp;
+ mTimestamp = timestamp;
+ }
+ }
+
+ private final class CookiePersistence extends Handler {
+ private static final long PERSIST_COOKIE_DELAY_MILLIS = 1000L; /* one second */
+
+ // In case you wonder why we stash the cookies aside, we use
+ // the user id for the message id and the package for the payload.
+ // Handler allows removing messages by id and tag where the
+ // tag is is compared using ==. So to allow cancelling the
+ // pending persistence for an app under a given user we use
+ // the fact that package names are interned in the system
+ // process so the == comparison would match and we end up
+ // with a way to cancel persisting the cookie for a user
+ // and package.
+ private final SparseArray<ArrayMap<String, byte[]>> mPendingPersistCookies =
+ new SparseArray<>();
+
+ public CookiePersistence(Looper looper) {
+ super(looper);
+ }
+
+ public void schedulePersist(@UserIdInt int userId,
+ @NonNull String packageName, @NonNull byte[] cookie) {
+ cancelPendingPersist(userId, packageName);
+ addPendingPersistCookie(userId, packageName, cookie);
+ sendMessageDelayed(obtainMessage(userId, packageName),
+ PERSIST_COOKIE_DELAY_MILLIS);
+ }
+
+ public @Nullable byte[] getPendingPersistCookie(@UserIdInt int userId,
+ @NonNull String packageName) {
+ ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
+ if (pendingWorkForUser != null) {
+ return pendingWorkForUser.remove(packageName);
+ }
+ return null;
+ }
+
+ private void cancelPendingPersist(@UserIdInt int userId,
+ @NonNull String packageName) {
+ removePendingPersistCookie(userId, packageName);
+ removeMessages(userId, packageName);
+ }
+
+ private void addPendingPersistCookie(@UserIdInt int userId,
+ @NonNull String packageName, @NonNull byte[] cookie) {
+ ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
+ if (pendingWorkForUser == null) {
+ pendingWorkForUser = new ArrayMap<>();
+ mPendingPersistCookies.put(userId, pendingWorkForUser);
+ }
+ pendingWorkForUser.put(packageName, cookie);
+ }
+
+ private byte[] removePendingPersistCookie(@UserIdInt int userId,
+ @NonNull String packageName) {
+ ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
+ byte[] cookie = null;
+ if (pendingWorkForUser != null) {
+ cookie = pendingWorkForUser.remove(packageName);
+ if (pendingWorkForUser.isEmpty()) {
+ mPendingPersistCookies.remove(userId);
+ }
+ }
+ return cookie;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ int userId = message.what;
+ String packageName = (String) message.obj;
+ byte[] cookie = removePendingPersistCookie(userId, packageName);
+ persistInstantApplicationCookie(cookie, packageName, userId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 0de0c924db72..49d3c8bccdff 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -287,7 +287,7 @@ public class KeySetManagerService {
for (int i = 0; i < defMapSize; i++) {
String alias = definedMapping.keyAt(i);
ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
- if (alias != null && pubKeys != null || pubKeys.size() > 0) {
+ if (alias != null && pubKeys != null && pubKeys.size() > 0) {
KeySetHandle ks = addKeySetLPw(pubKeys);
newKeySetAliases.put(alias, ks.getId());
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 50309bedfb85..b6611eb9fcfd 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -219,11 +219,12 @@ public class LauncherAppsService extends SystemService {
/**
* Checks if the caller is in the same group as the userToCheck.
*/
- private void ensureInUserProfiles(UserHandle userToCheck, String message) {
- ensureInUserProfiles(userToCheck.getIdentifier(), message);
+ private void ensureInUserProfiles(
+ String callingPackage, UserHandle userToCheck, String message) {
+ ensureInUserProfiles(callingPackage, userToCheck.getIdentifier(), message);
}
- private void ensureInUserProfiles(int targetUserId, String message) {
+ private void ensureInUserProfiles(String callingPackage, int targetUserId, String message) {
final int callingUserId = injectCallingUserId();
if (targetUserId == callingUserId) return;
@@ -236,8 +237,8 @@ public class LauncherAppsService extends SystemService {
// throw new SecurityException(message + " for another profile " + targetUserId);
// TODO: Report caller package name.
- Slog.wtfStack(TAG, message + " for another profile " + targetUserId
- + " from " + callingUserId);
+ Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile "
+ + targetUserId + " from " + callingUserId);
}
UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -286,9 +287,10 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public ParceledListSlice<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
+ public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
+ String packageName, UserHandle user)
throws RemoteException {
- return queryActivitiesForUser(
+ return queryActivitiesForUser(callingPackage,
new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(packageName),
@@ -296,9 +298,10 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public ActivityInfo resolveActivity(ComponentName component, UserHandle user)
+ public ActivityInfo resolveActivity(
+ String callingPackage, ComponentName component, UserHandle user)
throws RemoteException {
- ensureInUserProfiles(user, "Cannot resolve activity");
+ ensureInUserProfiles(callingPackage, user, "Cannot resolve activity");
if (!isUserEnabled(user)) {
return null;
}
@@ -316,15 +319,16 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public ParceledListSlice getShortcutConfigActivities(String packageName, UserHandle user)
+ public ParceledListSlice getShortcutConfigActivities(
+ String callingPackage, String packageName, UserHandle user)
throws RemoteException {
- return queryActivitiesForUser(
+ return queryActivitiesForUser(callingPackage,
new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
}
- private ParceledListSlice<ResolveInfo> queryActivitiesForUser(Intent intent,
- UserHandle user) {
- ensureInUserProfiles(user, "Cannot retrieve activities");
+ private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
+ Intent intent, UserHandle user) {
+ ensureInUserProfiles(callingPackage, user, "Cannot retrieve activities");
if (!isUserEnabled(user)) {
return null;
}
@@ -363,9 +367,9 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public boolean isPackageEnabled(String packageName, UserHandle user)
+ public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user)
throws RemoteException {
- ensureInUserProfiles(user, "Cannot check package");
+ ensureInUserProfiles(callingPackage, user, "Cannot check package");
if (!isUserEnabled(user)) {
return false;
}
@@ -384,9 +388,10 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user)
+ public ApplicationInfo getApplicationInfo(
+ String callingPackage, String packageName, int flags, UserHandle user)
throws RemoteException {
- ensureInUserProfiles(user, "Cannot check package");
+ ensureInUserProfiles(callingPackage, user, "Cannot check package");
if (!isUserEnabled(user)) {
return null;
}
@@ -408,7 +413,7 @@ public class LauncherAppsService extends SystemService {
private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
verifyCallingPackage(callingPackage);
- ensureInUserProfiles(userId, "Cannot access shortcuts");
+ ensureInUserProfiles(callingPackage, userId, "Cannot access shortcuts");
if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
callingPackage)) {
@@ -484,7 +489,7 @@ public class LauncherAppsService extends SystemService {
public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
Rect sourceBounds, Bundle startActivityOptions, int userId) {
verifyCallingPackage(callingPackage);
- ensureInUserProfiles(userId, "Cannot start activity");
+ ensureInUserProfiles(callingPackage, userId, "Cannot start activity");
if (!isUserEnabled(userId)) {
throw new IllegalStateException("Cannot start a shortcut for disabled profile "
@@ -535,9 +540,10 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public boolean isActivityEnabled(ComponentName component, UserHandle user)
+ public boolean isActivityEnabled(
+ String callingPackage, ComponentName component, UserHandle user)
throws RemoteException {
- ensureInUserProfiles(user, "Cannot check component");
+ ensureInUserProfiles(callingPackage , user, "Cannot check component");
if (!isUserEnabled(user)) {
return false;
}
@@ -556,9 +562,10 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public void startActivityAsUser(ComponentName component, Rect sourceBounds,
+ public void startActivityAsUser(String callingPackage,
+ ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
- ensureInUserProfiles(user, "Cannot start activity");
+ ensureInUserProfiles(callingPackage, user, "Cannot start activity");
if (!isUserEnabled(user)) {
throw new IllegalStateException("Cannot start activity for disabled profile " + user);
}
@@ -609,9 +616,9 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
- Bundle opts, UserHandle user) throws RemoteException {
- ensureInUserProfiles(user, "Cannot show app details");
+ public void showAppDetailsAsUser(String callingPackage, ComponentName component,
+ Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
+ ensureInUserProfiles(callingPackage, user, "Cannot show app details");
if (!isUserEnabled(user)) {
throw new IllegalStateException("Cannot show app details for disabled profile "
+ user);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 8e201aca783f..db712aeba0cd 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -19,6 +19,7 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.os.Environment;
import android.os.PowerManager;
@@ -35,6 +36,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import dalvik.system.DexFile;
@@ -43,6 +45,10 @@ import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
+import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX;
+import static com.android.server.pm.Installer.DEXOPT_FORCE;
+import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
+import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -52,13 +58,13 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
/**
* Helper class for running dexopt command on packages.
*/
-class PackageDexOptimizer {
+public class PackageDexOptimizer {
private static final String TAG = "PackageManager.DexOptimizer";
static final String OAT_DIR_NAME = "oat";
// TODO b/19550105 Remove error codes and use exceptions
- static final int DEX_OPT_SKIPPED = 0;
- static final int DEX_OPT_PERFORMED = 1;
- static final int DEX_OPT_FAILED = -1;
+ public static final int DEX_OPT_SKIPPED = 0;
+ public static final int DEX_OPT_PERFORMED = 1;
+ public static final int DEX_OPT_FAILED = -1;
private final Installer mInstaller;
private final Object mInstallLock;
@@ -100,6 +106,9 @@ class PackageDexOptimizer {
return DEX_OPT_SKIPPED;
}
synchronized (mInstallLock) {
+ // During boot the system doesn't need to instantiate and obtain a wake lock.
+ // PowerManager might not be ready, but that doesn't mean that we can't proceed with
+ // dexopt.
final boolean useLock = mSystemReady;
if (useLock) {
mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
@@ -130,9 +139,11 @@ class PackageDexOptimizer {
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final String compilerFilter = getRealCompilerFilter(pkg, targetCompilerFilter);
+ final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
+ targetCompilerFilter, isUsedByOtherApps(pkg));
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
+
// TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
// paths (b/34169257).
final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
@@ -201,6 +212,79 @@ class PackageDexOptimizer {
}
/**
+ * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}.
+ *
+ * @return
+ * DEX_OPT_FAILED if there was any exception during dexopt
+ * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path.
+ * NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file
+ * didn't need an update. That's because at the moment we don't get more than success/failure
+ * from installd.
+ *
+ * TODO(calin): Consider adding return codes to installd dexopt invocation (rather than
+ * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though
+ * that seems wasteful.
+ */
+ public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas,
+ String compilerFilter, boolean isUsedByOtherApps) {
+ synchronized (mInstallLock) {
+ // During boot the system doesn't need to instantiate and obtain a wake lock.
+ // PowerManager might not be ready, but that doesn't mean that we can't proceed with
+ // dexopt.
+ final boolean useLock = mSystemReady;
+ if (useLock) {
+ mDexoptWakeLock.setWorkSource(new WorkSource(info.uid));
+ mDexoptWakeLock.acquire();
+ }
+ try {
+ return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter,
+ isUsedByOtherApps);
+ } finally {
+ if (useLock) {
+ mDexoptWakeLock.release();
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mInstallLock")
+ private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
+ String compilerFilter, boolean isUsedByOtherApps) {
+ int dexoptFlags = getDexFlags(info, compilerFilter) | DEXOPT_SECONDARY_DEX;
+ // Check the app storage and add the appropriate flags.
+ if (info.dataDir.equals(info.deviceProtectedDataDir)) {
+ dexoptFlags |= DEXOPT_STORAGE_DE;
+ } else if (info.dataDir.equals(info.credentialProtectedDataDir)) {
+ dexoptFlags |= DEXOPT_STORAGE_CE;
+ } else {
+ Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
+ return DEX_OPT_FAILED;
+ }
+ compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
+ Log.d(TAG, "Running dexopt on: " + path
+ + " pkg=" + info.packageName + " isa=" + isas
+ + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+ + " target-filter=" + compilerFilter);
+
+ try {
+ for (String isa : isas) {
+ // Reuse the same dexopt path as for the primary apks. We don't need all the
+ // arguments as some (dexopNeeded and oatDir) will be computed by installd because
+ // system server cannot read untrusted app content.
+ // TODO(calin): maybe add a separate call.
+ mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
+ /*oatDir*/ null, dexoptFlags,
+ compilerFilter, info.volumeUuid, /*sharedLibrariesPath*/ null);
+ }
+
+ return DEX_OPT_PERFORMED;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dexopt", e);
+ return DEX_OPT_FAILED;
+ }
+ }
+
+ /**
* Adjust the given dexopt-needed value. Can be overridden to influence the decision to
* optimize or not (and in what way).
*/
@@ -246,8 +330,9 @@ class PackageDexOptimizer {
* The target filter will be updated if the package code is used by other apps
* or if it has the safe mode flag set.
*/
- private String getRealCompilerFilter(PackageParser.Package pkg, String targetCompilerFilter) {
- int flags = pkg.applicationInfo.flags;
+ private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
+ boolean isUsedByOtherApps) {
+ int flags = info.flags;
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
if (vmSafeMode) {
// For the compilation, it doesn't really matter what we return here because installd
@@ -259,7 +344,7 @@ class PackageDexOptimizer {
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
}
- if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps(pkg)) {
+ if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
// If the dex files is used by other apps, we cannot use profile-guided compilation.
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
}
@@ -272,12 +357,16 @@ class PackageDexOptimizer {
* filter.
*/
private int getDexFlags(PackageParser.Package pkg, String compilerFilter) {
- int flags = pkg.applicationInfo.flags;
+ return getDexFlags(pkg.applicationInfo, compilerFilter);
+ }
+
+ private int getDexFlags(ApplicationInfo info, String compilerFilter) {
+ int flags = info.flags;
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
// Profile guide compiled oat files should not be public.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
- boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
+ boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
@@ -437,6 +526,19 @@ class PackageDexOptimizer {
if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
flagsList.add("safemode");
}
+ if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) {
+ flagsList.add("secondary");
+ }
+ if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) {
+ flagsList.add("force");
+ }
+ if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) {
+ flagsList.add("storage_ce");
+ }
+ if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) {
+ flagsList.add("storage_de");
+ }
+
return String.join(",", flagsList);
}
@@ -461,5 +563,12 @@ class PackageDexOptimizer {
// TODO: The return value is wrong when patchoat is needed.
return DexFile.DEX2OAT_FROM_SCRATCH;
}
+
+ @Override
+ protected int adjustDexoptFlags(int flags) {
+ // Add DEXOPT_FORCE flag to signal installd that it should force compilation
+ // and discard dexoptanalyzer result.
+ return flags | DEXOPT_FORCE;
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index da6a67e830b7..efd313237acf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -225,8 +225,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
synchronized (mSessions) {
readSessionsLocked();
- reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isEphemeral*/);
- reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isEphemeral*/);
+ reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
+ reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
final ArraySet<File> unclaimedIcons = newArraySet(
mSessionsDir.listFiles());
@@ -271,7 +271,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
public void onPrivateVolumeMounted(String volumeUuid) {
synchronized (mSessions) {
- reconcileStagesLocked(volumeUuid, false /*isEphemeral*/);
+ reconcileStagesLocked(volumeUuid, false /*isInstant*/);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d1aed3e3018a..067a13642781 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -894,7 +894,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// This is kind of hacky; we're creating a half-parsed package that is
// straddled between the inherited and staged APKs.
- final PackageLite pkg = new PackageLite(null, baseApk, null,
+ final PackageLite pkg = new PackageLite(null, baseApk, null, null,
splitPaths.toArray(new String[splitPaths.size()]), null);
final boolean isForwardLocked =
(params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 63a5d145fe62..4207998c9dcc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -127,7 +127,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AppsQueryHelper;
import android.content.pm.ComponentInfo;
-import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.InstantAppInfo;
import android.content.pm.EphemeralRequest;
import android.content.pm.EphemeralResolveInfo;
import android.content.pm.EphemeralResponse;
@@ -255,6 +255,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
+import com.android.server.BackgroundDexOptJobService;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.IntentResolver;
@@ -375,7 +376,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
// user, but by default initialize to this.
- static final boolean DEBUG_DEXOPT = false;
+ public static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_EPHEMERAL = Build.IS_DEBUGGABLE;
@@ -386,7 +387,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
private static final boolean DISABLE_EPHEMERAL_APPS = false;
- private static final boolean HIDE_EPHEMERAL_APIS = true;
+ private static final boolean HIDE_EPHEMERAL_APIS = false;
private static final boolean ENABLE_QUOTA =
SystemProperties.getBoolean("persist.fw.quota", false);
@@ -706,15 +707,18 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean mFirstBoot;
+ PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
+
// System configuration read by SystemConfig.
final int[] mGlobalGids;
final SparseArray<ArraySet<String>> mSystemPermissions;
+ @GuardedBy("mAvailableFeatures")
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
// If mac_permissions.xml was found for seinfo labeling.
boolean mFoundPolicyFile;
- private final EphemeralApplicationRegistry mEphemeralApplicationRegistry;
+ private final InstantAppRegistry mInstantAppRegistry;
public static final class SharedLibraryEntry {
public final String path;
@@ -1748,7 +1752,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
- mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
+ mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
final String packageName = res.pkg.applicationInfo.packageName;
@@ -1864,6 +1868,18 @@ public class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.args.doPostDeleteLI(true);
}
}
+
+ if (!isEphemeral(res.pkg)) {
+ // Notify DexManager that the package was installed for new users.
+ // The updated users should already be indexed and the package code paths
+ // should not change.
+ // Don't notify the manager for ephemeral apps as they are not expected to
+ // survive long enough to benefit of background optimizations.
+ for (int userId : firstUsers) {
+ PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
+ mDexManager.notifyPackageInstalled(info, userId);
+ }
+ }
}
// If someone is watching installs - notify them
@@ -1920,7 +1936,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Clean up any users or apps that were removed or recreated
// while this volume was missing
- reconcileUsers(volumeUuid);
+ sUserManager.reconcileUsers(volumeUuid);
reconcileApps(volumeUuid);
// Clean up any install sessions that expired or were
@@ -2144,19 +2160,24 @@ public class PackageManagerService extends IPackageManager.Stub {
if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
// We will wait for up to 100 seconds.
- final long timeEnd = SystemClock.uptimeMillis() + 100 * 1000;
+ final long timeStart = SystemClock.uptimeMillis();
+ final long timeEnd = timeStart + 100 * 1000;
+ long timeNow = timeStart;
while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
try {
Thread.sleep(WAIT_TIME_MS);
} catch (InterruptedException e) {
// Do nothing
}
- if (SystemClock.uptimeMillis() > timeEnd) {
+ timeNow = SystemClock.uptimeMillis();
+ if (timeNow > timeEnd) {
SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
Slog.wtf(TAG, "cppreopt did not finish!");
break;
}
}
+
+ Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
}
}
@@ -2212,7 +2233,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstaller = installer;
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
- mDexManager = new DexManager();
+ mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
@@ -2240,7 +2261,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
- mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
+ mInstantAppRegistry = new InstantAppRegistry(this);
File dataDir = Environment.getDataDirectory();
mAppInstallDir = new File(dataDir, "app");
@@ -2248,8 +2269,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
-
- sUserManager = new UserManagerService(context, this, mPackages);
+ sUserManager = new UserManagerService(context, this,
+ new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
// Propagate permission configuration in to package manager.
ArrayMap<String, SystemConfig.PermissionEntry> permConfig
@@ -3288,10 +3309,13 @@ public class PackageManagerService extends IPackageManager.Stub {
// * An installed app can see metadata for 1) other installed apps
// and 2) ephemeral apps that have explicitly interacted with it
// * Ephemeral apps can only see their own metadata
+ // * Holding a signature permission allows seeing instant apps
final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
if (callingAppId != Process.SYSTEM_UID
&& callingAppId != Process.SHELL_UID
- && callingAppId != Process.ROOT_UID) {
+ && callingAppId != Process.ROOT_UID
+ && checkUidPermission(Manifest.permission.ACCESS_INSTANT_APPS,
+ Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) {
final String ephemeralPackageName = getEphemeralPackageName(Binder.getCallingUid());
if (ephemeralPackageName != null) {
// ephemeral apps can only get information on themselves
@@ -3299,9 +3323,9 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
} else {
- if (p.applicationInfo.isEphemeralApp()) {
+ if (p.applicationInfo.isInstantApp()) {
// only get access to the ephemeral app if we've been granted access
- if (!mEphemeralApplicationRegistry.isEphemeralAccessGranted(
+ if (!mInstantAppRegistry.isInstantAccessGranted(
userId, callingAppId, ps.appId)) {
return null;
}
@@ -4196,21 +4220,22 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
- synchronized (mPackages) {
- final ArrayList<FeatureInfo> res = new ArrayList<>(mAvailableFeatures.values());
-
- final FeatureInfo fi = new FeatureInfo();
- fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
- FeatureInfo.GL_ES_VERSION_UNDEFINED);
- res.add(fi);
-
- return new ParceledListSlice<>(res);
+ ArrayList<FeatureInfo> res;
+ synchronized (mAvailableFeatures) {
+ res = new ArrayList<>(mAvailableFeatures.size() + 1);
+ res.addAll(mAvailableFeatures.values());
}
+ final FeatureInfo fi = new FeatureInfo();
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ res.add(fi);
+
+ return new ParceledListSlice<>(res);
}
@Override
public boolean hasSystemFeature(String name, int version) {
- synchronized (mPackages) {
+ synchronized (mAvailableFeatures) {
final FeatureInfo feat = mAvailableFeatures.get(name);
if (feat == null) {
return false;
@@ -4602,7 +4627,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
- if (pkg.applicationInfo.isEphemeralApp() && !bp.isEphemeral()) {
+ if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
throw new SecurityException("Cannot grant non-ephemeral permission"
+ name + " for package " + packageName);
}
@@ -5897,7 +5922,7 @@ public class PackageManagerService extends IPackageManager.Stub {
CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
if (resolver != null) {
return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/,
- false /*visibleToEphemeral*/, false /*isEphemeral*/, userId);
+ false /*visibleToEphemeral*/, false /*isInstant*/, userId);
}
return null;
}
@@ -5925,7 +5950,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final Object obj = mSettings.getUserIdLPr(appId);
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- return ps.pkg.applicationInfo.isEphemeralApp() ? ps.pkg.packageName : null;
+ return ps.pkg.applicationInfo.isInstantApp() ? ps.pkg.packageName : null;
}
}
return null;
@@ -6203,7 +6228,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
ResolveInfo info = resolveInfos.get(i);
- final boolean isEphemeralApp = info.activityInfo.applicationInfo.isEphemeralApp();
+ final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
// allow activities that are defined in the provided package
if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) {
continue;
@@ -7019,31 +7044,31 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
+ public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
return null;
}
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getEphemeralApplications");
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getEphemeralApplications");
synchronized (mPackages) {
- List<EphemeralApplicationInfo> ephemeralApps = mEphemeralApplicationRegistry
- .getEphemeralApplicationsLPw(userId);
- if (ephemeralApps != null) {
- return new ParceledListSlice<>(ephemeralApps);
+ List<InstantAppInfo> instantApps = mInstantAppRegistry
+ .getInstantAppsLPr(userId);
+ if (instantApps != null) {
+ return new ParceledListSlice<>(instantApps);
}
}
return null;
}
@Override
- public boolean isEphemeralApplication(String packageName, int userId) {
+ public boolean isInstantApp(String packageName, int userId) {
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
- "isEphemeral");
+ "isInstantApp");
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
return false;
}
@@ -7054,62 +7079,63 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
- return pkg.applicationInfo.isEphemeralApp();
+ return pkg.applicationInfo.isInstantApp();
}
}
return false;
}
@Override
- public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
+ public byte[] getInstantAppCookie(String packageName, int userId) {
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
return null;
}
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
- "getCookie");
+ "getInstantAppCookie");
if (!isCallerSameApp(packageName)) {
return null;
}
synchronized (mPackages) {
- return mEphemeralApplicationRegistry.getEphemeralApplicationCookieLPw(
+ return mInstantAppRegistry.getInstantAppCookieLPw(
packageName, userId);
}
}
@Override
- public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
+ public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
return true;
}
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, true /* checkShell */,
- "setCookie");
+ "setInstantAppCookie");
if (!isCallerSameApp(packageName)) {
return false;
}
synchronized (mPackages) {
- return mEphemeralApplicationRegistry.setEphemeralApplicationCookieLPw(
+ return mInstantAppRegistry.setInstantAppCookieLPw(
packageName, cookie, userId);
}
}
@Override
- public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
+ public Bitmap getInstantAppIcon(String packageName, int userId) {
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
return null;
}
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
- "getEphemeralApplicationIcon");
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
+ "getInstantAppIcon");
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
- "getEphemeralApplicationIcon");
+ "getInstantAppIcon");
+
synchronized (mPackages) {
- return mEphemeralApplicationRegistry.getEphemeralApplicationIconLPw(
+ return mInstantAppRegistry.getInstantAppIconLPw(
packageName, userId);
}
}
@@ -8211,6 +8237,39 @@ public class PackageManagerService extends IPackageManager.Stub {
targetCompilerFilter, getOrCreateCompilerPackageStats(p));
}
+ // Performs dexopt on the used secondary dex files belonging to the given package.
+ // Returns true if all dex files were process successfully (which could mean either dexopt or
+ // skip). Returns false if any of the files caused errors.
+ @Override
+ public boolean performDexOptSecondary(String packageName, String compilerFilter,
+ boolean force) {
+ return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
+ }
+
+ /**
+ * Reconcile the information we have about the secondary dex files belonging to
+ * {@code packagName} and the actual dex files. For all dex files that were
+ * deleted, update the internal records and delete the generated oat files.
+ */
+ @Override
+ public void reconcileSecondaryDexFiles(String packageName) {
+ mDexManager.reconcileSecondaryDexFiles(packageName);
+ }
+
+ // TODO(calin): this is only needed for BackgroundDexOptService. Find a cleaner way to inject
+ // a reference there.
+ /*package*/ DexManager getDexManager() {
+ return mDexManager;
+ }
+
+ /**
+ * Execute the background dexopt job immediately.
+ */
+ @Override
+ public boolean runBackgroundDexoptJob() {
+ return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext);
+ }
+
List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
if (p.usesLibraries != null || p.usesOptionalLibraries != null
|| p.usesStaticLibraries != null) {
@@ -9297,7 +9356,7 @@ public class PackageManagerService extends IPackageManager.Stub {
(policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
if (isEphemeral(pkg)) {
final int userId = user == null ? 0 : user.getIdentifier();
- mEphemeralApplicationRegistry.addEphemeralAppLPw(userId, pkgSetting.appId);
+ mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
}
return pkg;
@@ -9412,7 +9471,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Package declaring static a shared lib cannot be ephemeral
- if (pkg.applicationInfo.isEphemeralApp()) {
+ if (pkg.applicationInfo.isInstantApp()) {
throw new PackageManagerException(
"Packages declaring static-shared libs cannot be ephemeral");
}
@@ -9946,7 +10005,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
final String curPackageName = cur == null ? null : cur.info.packageName;
// Dont allow ephemeral apps to define new permission groups.
- if (pkg.applicationInfo.isEphemeralApp()) {
+ if (pkg.applicationInfo.isInstantApp()) {
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName
+ " ignored: ephemeral apps cannot define new permission groups.");
@@ -9991,7 +10050,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Permission p = pkg.permissions.get(i);
// Dont allow ephemeral apps to define new permissions.
- if (pkg.applicationInfo.isEphemeralApp()) {
+ if (pkg.applicationInfo.isInstantApp()) {
Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName
+ " ignored: ephemeral apps cannot define new permissions.");
@@ -10101,8 +10160,10 @@ public class PackageManagerService extends IPackageManager.Stub {
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
+ a.info.splitNames = pkg.splitNames;
a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
+ a.info.splitDependencies = pkg.applicationInfo.splitDependencies;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
@@ -11192,7 +11253,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Limit ephemeral apps to ephemeral allowed permissions.
- if (pkg.applicationInfo.isEphemeralApp() && !bp.isEphemeral()) {
+ if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
+ pkg.packageName);
continue;
@@ -15702,7 +15763,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// don't allow an upgrade from full to ephemeral
- final boolean oldIsEphemeral = oldPackage.applicationInfo.isEphemeralApp();
+ final boolean oldIsEphemeral = oldPackage.applicationInfo.isInstantApp();
if (isEphemeral && !oldIsEphemeral) {
// can't downgrade from full to ephemeral
Slog.w(TAG, "Can't replace app with ephemeral: " + pkgName);
@@ -16429,13 +16490,13 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- // Ephemeral apps must have target SDK >= O.
- // TODO: Update conditional and error message when O gets locked down
- if (ephemeral && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- res.setError(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID,
- "Ephemeral apps must have target SDK version of at least O");
- return;
- }
+// // Ephemeral apps must have target SDK >= O.
+// // TODO: Update conditional and error message when O gets locked down
+// if (ephemeral && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+// res.setError(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID,
+// "Ephemeral apps must have target SDK version of at least O");
+// return;
+// }
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
@@ -16726,10 +16787,11 @@ public class PackageManagerService extends IPackageManager.Stub {
getOrCreateCompilerPackageStats(pkg));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- // Notify BackgroundDexOptService that the package has been changed.
+ // Notify BackgroundDexOptJobService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BDOS will remove it from its blacklist.
- BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+ // TODO: Layering violation
+ BackgroundDexOptJobService.notifyPackageChanged(pkg.packageName);
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
@@ -16920,7 +16982,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private static boolean isEphemeral(PackageParser.Package pkg) {
- return pkg.applicationInfo.isEphemeralApp();
+ return pkg.applicationInfo.isInstantApp();
}
private static boolean isEphemeral(PackageSetting ps) {
@@ -17357,7 +17419,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
if (res) {
- mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPs.pkg);
+ mInstantAppRegistry.onPackageUninstalledLPw(uninstalledPs.pkg,
+ info.removedUsers);
}
}
}
@@ -18210,6 +18273,10 @@ public class PackageManagerService extends IPackageManager.Stub {
succeeded = clearApplicationUserDataLIF(packageName, userId);
}
clearExternalStorageDataSync(packageName, userId, true);
+ synchronized (mPackages) {
+ mInstantAppRegistry.deleteInstantApplicationMetadataLPw(
+ packageName, userId);
+ }
}
if (succeeded) {
// invoke DeviceStorageMonitor's update method to clear any notifications
@@ -19903,7 +19970,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
});
// Now that we're mostly running, clean up stale users and apps
- reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
+ sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
}
@@ -20318,20 +20385,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
pw.println("Features:");
}
- for (FeatureInfo feat : mAvailableFeatures.values()) {
- if (checkin) {
- pw.print("feat,");
- pw.print(feat.name);
- pw.print(",");
- pw.println(feat.version);
- } else {
- pw.print(" ");
- pw.print(feat.name);
- if (feat.version > 0) {
- pw.print(" version=");
- pw.print(feat.version);
+ synchronized (mAvailableFeatures) {
+ for (FeatureInfo feat : mAvailableFeatures.values()) {
+ if (checkin) {
+ pw.print("feat,");
+ pw.print(feat.name);
+ pw.print(",");
+ pw.println(feat.version);
+ } else {
+ pw.print(" ");
+ pw.print(feat.name);
+ if (feat.version > 0) {
+ pw.print(" version=");
+ pw.print(feat.version);
+ }
+ pw.println();
}
- pw.println();
}
}
}
@@ -21239,151 +21308,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
- /**
- * Prepare storage areas for given user on all mounted devices.
- */
- void prepareUserData(int userId, int userSerial, int flags) {
- synchronized (mInstallLock) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
- final String volumeUuid = vol.getFsUuid();
- prepareUserDataLI(volumeUuid, userId, userSerial, flags, true);
- }
- }
- }
-
- private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags,
- boolean allowRecover) {
- // Prepare storage and verify that serial numbers are consistent; if
- // there's a mismatch we need to destroy to avoid leaking data
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- try {
- storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
-
- if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
- UserManagerService.enforceSerialNumber(
- Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial);
- if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
- UserManagerService.enforceSerialNumber(
- Environment.getDataSystemDeDirectory(userId), userSerial);
- }
- }
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
- UserManagerService.enforceSerialNumber(
- Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial);
- if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
- UserManagerService.enforceSerialNumber(
- Environment.getDataSystemCeDirectory(userId), userSerial);
- }
- }
-
- synchronized (mInstallLock) {
- mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
- }
- } catch (Exception e) {
- logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
- + " because we failed to prepare: " + e);
- destroyUserDataLI(volumeUuid, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-
- if (allowRecover) {
- // Try one last time; if we fail again we're really in trouble
- prepareUserDataLI(volumeUuid, userId, userSerial, flags, false);
- }
- }
- }
-
- /**
- * Destroy storage areas for given user on all mounted devices.
- */
- void destroyUserData(int userId, int flags) {
- synchronized (mInstallLock) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
- final String volumeUuid = vol.getFsUuid();
- destroyUserDataLI(volumeUuid, userId, flags);
- }
- }
- }
-
- private void destroyUserDataLI(String volumeUuid, int userId, int flags) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- try {
- // Clean up app data, profile data, and media data
- mInstaller.destroyUserData(volumeUuid, userId, flags);
-
- // Clean up system data
- if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
- if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
- FileUtils.deleteContentsAndDir(Environment.getUserSystemDirectory(userId));
- FileUtils.deleteContentsAndDir(Environment.getDataSystemDeDirectory(userId));
- }
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(userId));
- }
- }
-
- // Data with special labels is now gone, so finish the job
- storage.destroyUserStorage(volumeUuid, userId, flags);
-
- } catch (Exception e) {
- logCriticalInfo(Log.WARN,
- "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e);
- }
- }
-
- /**
- * Examine all users present on given mounted volume, and destroy data
- * belonging to users that are no longer valid, or whose user ID has been
- * recycled.
- */
- private void reconcileUsers(String volumeUuid) {
- final List<File> files = new ArrayList<>();
- Collections.addAll(files, FileUtils
- .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
- Collections.addAll(files, FileUtils
- .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
- Collections.addAll(files, FileUtils
- .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
- Collections.addAll(files, FileUtils
- .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
- for (File file : files) {
- if (!file.isDirectory()) continue;
-
- final int userId;
- final UserInfo info;
- try {
- userId = Integer.parseInt(file.getName());
- info = sUserManager.getUserInfo(userId);
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Invalid user directory " + file);
- continue;
- }
-
- boolean destroyUser = false;
- if (info == null) {
- logCriticalInfo(Log.WARN, "Destroying user directory " + file
- + " because no matching user was found");
- destroyUser = true;
- } else if (!mOnlyCore) {
- try {
- UserManagerService.enforceSerialNumber(file, info.serialNumber);
- } catch (IOException e) {
- logCriticalInfo(Log.WARN, "Destroying user directory " + file
- + " because we failed to enforce serial number: " + e);
- destroyUser = true;
- }
- }
-
- if (destroyUser) {
- synchronized (mInstallLock) {
- destroyUserDataLI(volumeUuid, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- }
- }
- }
- }
-
private void assertPackageKnown(String volumeUuid, String packageName)
throws PackageManagerException {
synchronized (mPackages) {
@@ -22206,7 +22130,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
mUserNeedsBadging.delete(userHandle);
mSettings.removeUserLPw(userHandle);
mPendingBroadcasts.remove(userHandle);
- mEphemeralApplicationRegistry.onUserRemovedLPw(userHandle);
+ mInstantAppRegistry.onUserRemovedLPw(userHandle);
removeUnusedPackagesLPw(userManager, userHandle);
}
}
@@ -22787,7 +22711,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
public boolean isPackageEphemeral(int userId, String packageName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
- return p != null ? p.applicationInfo.isEphemeralApp() : false;
+ return p != null ? p.applicationInfo.isInstantApp() : false;
}
}
@@ -22829,14 +22753,65 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
public void grantEphemeralAccess(int userId, Intent intent,
int targetAppId, int ephemeralAppId) {
synchronized (mPackages) {
- mEphemeralApplicationRegistry.grantEphemeralAccessLPw(userId, intent,
+ mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
targetAppId, ephemeralAppId);
}
}
+ @Override
+ public void pruneInstantApps() {
+ synchronized (mPackages) {
+ mInstantAppRegistry.pruneInstantAppsLPw();
+ }
+ }
+
+ @Override
public String getSetupWizardPackageName() {
return mSetupWizardPackage;
}
+
+ public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
+ if (policy != null) {
+ mExternalSourcesPolicy = policy;
+ }
+ }
+
+ @Override
+ public List<PackageInfo> getOverlayPackages(int userId) {
+ final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayTarget != null) {
+ PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
+ if (pkg != null) {
+ overlayPackages.add(pkg);
+ }
+ }
+ }
+ }
+ return overlayPackages;
+ }
+
+ @Override
+ public List<String> getTargetPackageNames(int userId) {
+ List<String> targetPackages = new ArrayList<>();
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayTarget == null) {
+ targetPackages.add(p.packageName);
+ }
+ }
+ }
+ return targetPackages;
+ }
+
+
+ @Override
+ public boolean setEnabledOverlayPackages(int userId, String targetPackageName,
+ List<String> overlayPackageNames) {
+ // TODO: implement when we integrate OMS properly
+ return false;
+ }
}
@Override
@@ -22853,6 +22828,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
+ @Override
+ public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledImsServices");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServicesLPr(
+ packageNames, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
private static void enforceSystemOrPhoneCaller(String tag) {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
@@ -22926,4 +22915,38 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
return PackageManager.INSTALL_REASON_UNKNOWN;
}
+
+ @Override
+ public boolean canRequestPackageInstalls(String packageName, int userId) {
+ int callingUid = Binder.getCallingUid();
+ int uid = getPackageUid(packageName, 0, userId);
+ if (callingUid != uid && callingUid != Process.ROOT_UID
+ && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "Caller uid " + callingUid + " does not own package " + packageName);
+ }
+ ApplicationInfo info = getApplicationInfo(packageName, 0, userId);
+ if (info == null) {
+ return false;
+ }
+ if (info.targetSdkVersion < Build.VERSION_CODES.O) {
+ throw new UnsupportedOperationException(
+ "Operation only supported on apps targeting Android O or higher");
+ }
+ String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
+ String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
+ if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
+ throw new SecurityException("Need to declare " + appOpPermission + " to call this api");
+ }
+ if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)) {
+ return false;
+ }
+ if (mExternalSourcesPolicy != null) {
+ int isTrusted = mExternalSourcesPolicy.getPackageTrustedToInstallApps(packageName, uid);
+ if (isTrusted != PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT) {
+ return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
+ }
+ }
+ return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 8a3f48efb504..9c9a6711c581 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -23,7 +23,7 @@ import dalvik.system.DexFile;
/**
* Manage (retrieve) mappings from compilation reason to compilation filter.
*/
-class PackageManagerServiceCompilerMapping {
+public class PackageManagerServiceCompilerMapping {
// Names for compilation reasons.
static final String REASON_STRINGS[] = {
"first-boot", "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk",
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 49b96b0b55fe..1203e4d58c00 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -118,6 +118,10 @@ class PackageManagerShellCommand extends ShellCommand {
return runInstallWrite();
case "compile":
return runCompile();
+ case "reconcile-secondary-dex-files":
+ return runreconcileSecondaryDexFiles();
+ case "bg-dexopt-job":
+ return runDexoptJob();
case "dump-profiles":
return runDumpProfiles();
case "list":
@@ -162,7 +166,7 @@ class PackageManagerShellCommand extends ShellCommand {
if (file.isFile()) {
try {
ApkLite baseApk = PackageParser.parseApkLite(file, 0);
- PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
+ PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null);
params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
pkgLite, false, params.sessionParams.abiOverride));
} catch (PackageParserException | IOException e) {
@@ -306,6 +310,7 @@ class PackageManagerShellCommand extends ShellCommand {
String compilerFilter = null;
String compilationReason = null;
String checkProfilesRaw = null;
+ boolean secondaryDex = false;
String opt;
while ((opt = getNextOption()) != null) {
@@ -333,6 +338,9 @@ class PackageManagerShellCommand extends ShellCommand {
clearProfileData = true;
compilationReason = "install";
break;
+ case "--secondary-dex":
+ secondaryDex = true;
+ break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
@@ -405,8 +413,11 @@ class PackageManagerShellCommand extends ShellCommand {
mInterface.clearApplicationProfileData(packageName);
}
- boolean result = mInterface.performDexOptMode(packageName,
- checkProfiles, targetCompilerFilter, forceCompilation);
+ boolean result = secondaryDex
+ ? mInterface.performDexOptSecondary(packageName,
+ targetCompilerFilter, forceCompilation)
+ : mInterface.performDexOptMode(packageName,
+ checkProfiles, targetCompilerFilter, forceCompilation);
if (!result) {
failedPackages.add(packageName);
}
@@ -434,6 +445,17 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
+ private int runreconcileSecondaryDexFiles() throws RemoteException {
+ String packageName = getNextArg();
+ mInterface.reconcileSecondaryDexFiles(packageName);
+ return 0;
+ }
+
+ private int runDexoptJob() throws RemoteException {
+ boolean result = mInterface.runBackgroundDexoptJob();
+ return result ? 0 : -1;
+ }
+
private int runDumpProfiles() throws RemoteException {
String packageName = getNextArg();
mInterface.dumpProfiles(packageName);
@@ -1515,6 +1537,13 @@ class PackageManagerShellCommand extends ShellCommand {
}
pw.println(" --reset: restore package to its post-install state");
pw.println(" --check-prof (true | false): look at profiles when doing dexopt?");
+ pw.println(" --secondary-dex: compile app secondary dex files");
+ pw.println(" bg-dexopt-job");
+ pw.println(" Execute the background optimizations immediately.");
+ pw.println(" Note that the command only runs the background optimizer logic. It may");
+ pw.println(" overlap with the actual job but the job scheduler will not be able to");
+ pw.println(" cancel it. It will also run even if the device is not in the idle");
+ pw.println(" maintenance mode.");
pw.println(" list features");
pw.println(" Prints all features of the system.");
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");
@@ -1539,6 +1568,8 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" -u: also include uninstalled packages");
pw.println(" --uid UID: filter to only show packages with the given UID");
pw.println(" --user USER_ID: only list packages belonging to the given user");
+ pw.println(" reconcile-secondary-dex-files TARGET-PACKAGE");
+ pw.println(" Reconciles the package secondary dex files with the generated oat files.");
pw.println(" list permission-groups");
pw.println(" Prints all known permission groups.");
pw.println(" list permissions [-g] [-f] [-d] [-u] [GROUP]");
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 922291790271..27811508d573 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -66,6 +66,9 @@ public final class SELinuxMMAC {
// Append privapp to existing seinfo label
private static final String PRIVILEGED_APP_STR = ":privapp";
+ // Append v2 to existing seinfo label
+ private static final String SANDBOX_V2_STR = ":v2";
+
// Append ephemeral to existing seinfo label
private static final String EPHEMERAL_APP_STR = ":ephemeralapp";
@@ -284,9 +287,12 @@ public final class SELinuxMMAC {
}
}
- if (pkg.applicationInfo.isEphemeralApp())
+ if (pkg.applicationInfo.isInstantApp())
pkg.applicationInfo.seinfo += EPHEMERAL_APP_STR;
+ if (pkg.applicationInfo.targetSandboxVersion == 2)
+ pkg.applicationInfo.seinfo += SANDBOX_V2_STR;
+
if (pkg.applicationInfo.isPrivilegedApp())
pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 6e967267e51d..6eac5e39cc63 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -25,7 +25,6 @@ import android.content.pm.IPinItemRequest;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.ShortcutInfo;
-import android.os.Binder;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
@@ -168,8 +167,8 @@ class ShortcutRequestPinProcessor {
mLock = lock;
}
- public boolean isRequestPinnedShortcutSupported(int callingUserId) {
- return getRequestPinShortcutConfirmationActivity(callingUserId) != null;
+ public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
+ return getRequestPinConfirmationActivity(callingUserId, requestType) != null;
}
/**
@@ -185,8 +184,10 @@ class ShortcutRequestPinProcessor {
// First, make sure the launcher supports it.
// Find the confirmation activity in the default launcher.
+ final int requestType = inShortcut != null ?
+ PinItemRequest.REQUEST_TYPE_SHORTCUT : PinItemRequest.REQUEST_TYPE_APPWIDGET;
final Pair<ComponentName, Integer> confirmActivity =
- getRequestPinShortcutConfirmationActivity(userId);
+ getRequestPinConfirmationActivity(userId, requestType);
// If the launcher doesn't support it, just return a rejected result and finish.
if (confirmActivity == null) {
@@ -210,7 +211,8 @@ class ShortcutRequestPinProcessor {
request = new PinItemRequest(inAppWidget,
new PinItemRequestInner(this, resultIntent, launcherUid));
}
- return startRequestConfirmActivity(confirmActivity.first, launcherUserId, request);
+ return startRequestConfirmActivity(confirmActivity.first, launcherUserId, request,
+ requestType);
}
/**
@@ -330,9 +332,13 @@ class ShortcutRequestPinProcessor {
}
private boolean startRequestConfirmActivity(ComponentName activity, int launcherUserId,
- PinItemRequest request) {
+ PinItemRequest request, int requestType) {
+ final String action = requestType == LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT ?
+ LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT :
+ LauncherApps.ACTION_CONFIRM_PIN_APPWIDGET;
+
// Start the activity.
- final Intent confirmIntent = new Intent(LauncherApps.ACTION_CONFIRM_PIN_ITEM);
+ final Intent confirmIntent = new Intent(action);
confirmIntent.setComponent(activity);
confirmIntent.putExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST, request);
confirmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -351,13 +357,13 @@ class ShortcutRequestPinProcessor {
}
/**
- * Find the activity that handles {@link LauncherApps#ACTION_CONFIRM_PIN_ITEM} in the
+ * Find the activity that handles {@link LauncherApps#ACTION_CONFIRM_PIN_SHORTCUT} in the
* default launcher.
*/
@Nullable
@VisibleForTesting
- Pair<ComponentName, Integer> getRequestPinShortcutConfirmationActivity(
- int callingUserId) {
+ Pair<ComponentName, Integer> getRequestPinConfirmationActivity(
+ int callingUserId, int requestType) {
// Find the default launcher.
final int launcherUserId = mService.getParentOrSelfUserId(callingUserId);
final ComponentName defaultLauncher = mService.getDefaultLauncher(launcherUserId);
@@ -367,7 +373,7 @@ class ShortcutRequestPinProcessor {
return null;
}
final ComponentName activity = mService.injectGetPinConfirmationActivity(
- defaultLauncher.getPackageName(), launcherUserId);
+ defaultLauncher.getPackageName(), launcherUserId, requestType);
return (activity == null) ? null : Pair.create(activity, launcherUserId);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 56d679ef4fa4..d8857b77d961 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2117,10 +2117,11 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
- public boolean isRequestPinShortcutSupported(int callingUserId) {
+ public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
final long token = injectClearCallingIdentity();
try {
- return mShortcutRequestPinProcessor.isRequestPinnedShortcutSupported(callingUserId);
+ return mShortcutRequestPinProcessor
+ .isRequestPinItemSupported(callingUserId, requestType);
} finally {
injectRestoreCallingIdentity(token);
}
@@ -2621,6 +2622,11 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkNotNull(appWidget);
return requestPinItem(callingPackage, userId, null, appWidget, resultIntent);
}
+
+ @Override
+ public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
+ return ShortcutService.this.isRequestPinItemSupported(callingUserId, requestType);
+ }
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -3075,7 +3081,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
private static boolean isEphemeralApp(@Nullable ApplicationInfo ai) {
- return (ai != null) && ai.isEphemeralApp();
+ return (ai != null) && ai.isInstantApp();
}
private static boolean isInstalled(@Nullable PackageInfo pi) {
@@ -3250,16 +3256,19 @@ public class ShortcutService extends IShortcutService.Stub {
}
/**
- * Get the {@link LauncherApps#ACTION_CONFIRM_PIN_ITEM} activity in a given package.
+ * Get the {@link LauncherApps#ACTION_CONFIRM_PIN_SHORTCUT} or
+ * {@link LauncherApps#ACTION_CONFIRM_PIN_APPWIDGET} activity in a given package depending on
+ * the requestType.
*/
@Nullable
ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
- int launcherUserId) {
+ int launcherUserId, int requestType) {
Preconditions.checkNotNull(launcherPackageName);
+ String action = requestType == LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT ?
+ LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT :
+ LauncherApps.ACTION_CONFIRM_PIN_APPWIDGET;
- final Intent confirmIntent = new Intent(LauncherApps.ACTION_CONFIRM_PIN_ITEM);
- confirmIntent.setPackage(launcherPackageName);
-
+ final Intent confirmIntent = new Intent(action).setPackage(launcherPackageName);
final List<ResolveInfo> candidates = queryActivities(
confirmIntent, launcherUserId, /* exportedOnly =*/ false);
for (ResolveInfo ri : candidates) {
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
new file mode 100644
index 000000000000..fc00acc8a281
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import static com.android.server.pm.PackageManagerService.logCriticalInfo;
+
+/**
+ * Helper class for preparing and destroying user storage
+ */
+class UserDataPreparer {
+ private static final String TAG = "UserDataPreparer";
+ private static final String XATTR_SERIAL = "user.serial";
+
+ private final Object mInstallLock;
+ private final Context mContext;
+ private final boolean mOnlyCore;
+ private final Installer mInstaller;
+
+ UserDataPreparer(Installer installer, Object installLock, Context context, boolean onlyCore) {
+ mInstallLock = installLock;
+ mContext = context;
+ mOnlyCore = onlyCore;
+ mInstaller = installer;
+ }
+
+ /**
+ * Prepare storage areas for given user on all mounted devices.
+ */
+ void prepareUserData(int userId, int userSerial, int flags) {
+ synchronized (mInstallLock) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+ final String volumeUuid = vol.getFsUuid();
+ prepareUserDataLI(volumeUuid, userId, userSerial, flags, true);
+ }
+ }
+ }
+
+ private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags,
+ boolean allowRecover) {
+ // Prepare storage and verify that serial numbers are consistent; if
+ // there's a mismatch we need to destroy to avoid leaking data
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ try {
+ storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
+
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
+ enforceSerialNumber(getDataUserDeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ enforceSerialNumber(getDataSystemDeDirectory(userId), userSerial);
+ }
+ }
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
+ enforceSerialNumber(getDataUserCeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ enforceSerialNumber(getDataSystemCeDirectory(userId), userSerial);
+ }
+ }
+
+ mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
+ } catch (Exception e) {
+ logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
+ + " because we failed to prepare: " + e);
+ destroyUserDataLI(volumeUuid, userId,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+
+ if (allowRecover) {
+ // Try one last time; if we fail again we're really in trouble
+ prepareUserDataLI(volumeUuid, userId, userSerial, flags, false);
+ }
+ }
+ }
+
+ /**
+ * Destroy storage areas for given user on all mounted devices.
+ */
+ void destroyUserData(int userId, int flags) {
+ synchronized (mInstallLock) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+ final String volumeUuid = vol.getFsUuid();
+ destroyUserDataLI(volumeUuid, userId, flags);
+ }
+ }
+ }
+
+ void destroyUserDataLI(String volumeUuid, int userId, int flags) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ try {
+ // Clean up app data, profile data, and media data
+ mInstaller.destroyUserData(volumeUuid, userId, flags);
+
+ // Clean up system data
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
+ FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
+ FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
+ FileUtils.deleteContentsAndDir(getDataMiscDeDirectory(userId));
+ }
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
+ FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
+ FileUtils.deleteContentsAndDir(getDataMiscCeDirectory(userId));
+ }
+ }
+
+ // Data with special labels is now gone, so finish the job
+ storage.destroyUserStorage(volumeUuid, userId, flags);
+
+ } catch (Exception e) {
+ logCriticalInfo(Log.WARN,
+ "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e);
+ }
+ }
+
+ /**
+ * Examine all users present on given mounted volume, and destroy data
+ * belonging to users that are no longer valid, or whose user ID has been
+ * recycled.
+ */
+ void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList) {
+ final List<File> files = new ArrayList<>();
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataMiscCeDirectory()));
+ reconcileUsers(volumeUuid, validUsersList, files);
+ }
+
+ @VisibleForTesting
+ void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList, List<File> files) {
+ final int userCount = validUsersList.size();
+ SparseArray<UserInfo> users = new SparseArray<>(userCount);
+ for (int i = 0; i < userCount; i++) {
+ UserInfo user = validUsersList.get(i);
+ users.put(user.id, user);
+ }
+ for (File file : files) {
+ if (!file.isDirectory()) {
+ continue;
+ }
+
+ final int userId;
+ final UserInfo info;
+ try {
+ userId = Integer.parseInt(file.getName());
+ info = users.get(userId);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Invalid user directory " + file);
+ continue;
+ }
+
+ boolean destroyUser = false;
+ if (info == null) {
+ logCriticalInfo(Log.WARN, "Destroying user directory " + file
+ + " because no matching user was found");
+ destroyUser = true;
+ } else if (!mOnlyCore) {
+ try {
+ enforceSerialNumber(file, info.serialNumber);
+ } catch (IOException e) {
+ logCriticalInfo(Log.WARN, "Destroying user directory " + file
+ + " because we failed to enforce serial number: " + e);
+ destroyUser = true;
+ }
+ }
+
+ if (destroyUser) {
+ synchronized (mInstallLock) {
+ destroyUserDataLI(volumeUuid, userId,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ protected File getDataMiscCeDirectory(int userId) {
+ return Environment.getDataMiscCeDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataSystemCeDirectory(int userId) {
+ return Environment.getDataSystemCeDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataMiscDeDirectory(int userId) {
+ return Environment.getDataMiscDeDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getUserSystemDirectory(int userId) {
+ return Environment.getUserSystemDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataUserCeDirectory(String volumeUuid, int userId) {
+ return Environment.getDataUserCeDirectory(volumeUuid, userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataSystemDeDirectory(int userId) {
+ return Environment.getDataSystemDeDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataUserDeDirectory(String volumeUuid, int userId) {
+ return Environment.getDataUserDeDirectory(volumeUuid, userId);
+ }
+
+ @VisibleForTesting
+ protected boolean isFileEncryptedEmulatedOnly() {
+ return StorageManager.isFileEncryptedEmulatedOnly();
+ }
+
+ /**
+ * Enforce that serial number stored in user directory inode matches the
+ * given expected value. Gracefully sets the serial number if currently
+ * undefined.
+ *
+ * @throws IOException when problem extracting serial number, or serial
+ * number is mismatched.
+ */
+ void enforceSerialNumber(File file, int serialNumber) throws IOException {
+ if (isFileEncryptedEmulatedOnly()) {
+ // When we're emulating FBE, the directory may have been chmod
+ // 000'ed, meaning we can't read the serial number to enforce it;
+ // instead of destroying the user, just log a warning.
+ Slog.w(TAG, "Device is emulating FBE; assuming current serial number is valid");
+ return;
+ }
+
+ final int foundSerial = getSerialNumber(file);
+ Slog.v(TAG, "Found " + file + " with serial number " + foundSerial);
+
+ if (foundSerial == -1) {
+ Slog.d(TAG, "Serial number missing on " + file + "; assuming current is valid");
+ try {
+ setSerialNumber(file, serialNumber);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to set serial number on " + file, e);
+ }
+
+ } else if (foundSerial != serialNumber) {
+ throw new IOException("Found serial number " + foundSerial
+ + " doesn't match expected " + serialNumber);
+ }
+ }
+
+ /**
+ * Set serial number stored in user directory inode.
+ *
+ * @throws IOException if serial number was already set
+ */
+ private static void setSerialNumber(File file, int serialNumber) throws IOException {
+ try {
+ final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8);
+ Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ /**
+ * Return serial number stored in user directory inode.
+ *
+ * @return parsed serial number, or -1 if not set
+ */
+ @VisibleForTesting
+ static int getSerialNumber(File file) throws IOException {
+ try {
+ final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
+ final String serial = new String(buf);
+ try {
+ return Integer.parseInt(serial);
+ } catch (NumberFormatException e) {
+ throw new IOException("Bad serial number: " + serial);
+ }
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENODATA) {
+ return -1;
+ } else {
+ throw e.rethrowAsIOException();
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1eb8b943de9a..627fa545bf58 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -33,12 +33,10 @@ import android.app.IStopUserCallback;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
@@ -220,8 +218,6 @@ public class UserManagerService extends IUserManager.Stub {
static final int WRITE_USER_MSG = 1;
static final int WRITE_USER_DELAY = 2*1000; // 2 seconds
- private static final String XATTR_SERIAL = "user.serial";
-
// Tron counters
private static final String TRON_GUEST_CREATED = "users_guest_created";
private static final String TRON_USER_CREATED = "users_user_created";
@@ -229,6 +225,7 @@ public class UserManagerService extends IUserManager.Stub {
private final Context mContext;
private final PackageManagerService mPm;
private final Object mPackagesLock;
+ private final UserDataPreparer mUserDataPreparer;
// Short-term lock for internal state, when interaction/sync with PM is not required
private final Object mUsersLock = new Object();
private final Object mRestrictionsLock = new Object();
@@ -435,7 +432,7 @@ public class UserManagerService extends IUserManager.Stub {
// TODO b/28848102 Add support for test dependencies injection
@VisibleForTesting
UserManagerService(Context context) {
- this(context, null, new Object(), context.getCacheDir());
+ this(context, null, null, new Object(), context.getCacheDir());
}
/**
@@ -443,16 +440,18 @@ public class UserManagerService extends IUserManager.Stub {
* associated with the package manager, and the given lock is the
* package manager's own lock.
*/
- UserManagerService(Context context, PackageManagerService pm, Object packagesLock) {
- this(context, pm, packagesLock, Environment.getDataDirectory());
+ UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer,
+ Object packagesLock) {
+ this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory());
}
private UserManagerService(Context context, PackageManagerService pm,
- Object packagesLock, File dataDir) {
+ UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) {
mContext = context;
mPm = pm;
mPackagesLock = packagesLock;
mHandler = new MainHandler();
+ mUserDataPreparer = userDataPreparer;
synchronized (mPackagesLock) {
mUsersDir = new File(dataDir, USER_INFO_DIR);
mUsersDir.mkdirs();
@@ -718,7 +717,7 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
int parentUserId = profile.profileGroupId;
- if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
+ if (parentUserId == userHandle || parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
return null;
} else {
return getUserInfoLU(parentUserId);
@@ -2347,6 +2346,12 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
+ public boolean removeUserEvenWhenDisallowed(@UserIdInt int userHandle) {
+ checkManageOrCreateUsersPermission("Only the system can remove users");
+ return removeUserUnchecked(userHandle);
+ }
+
+ @Override
public UserInfo createUser(String name, int flags) {
checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, UserHandle.USER_NULL);
@@ -2490,7 +2495,7 @@ public class UserManagerService extends IUserManager.Stub {
}
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
- mPm.prepareUserData(userId, userInfo.serialNumber,
+ mUserDataPreparer.prepareUserData(userId, userInfo.serialNumber,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
mPm.createNewUser(userId, disallowedPackages);
userInfo.partial = false;
@@ -2784,7 +2789,7 @@ public class UserManagerService extends IUserManager.Stub {
mPm.cleanUpUser(this, userHandle);
// Clean up all data before removing metadata
- mPm.destroyUserData(userHandle,
+ mUserDataPreparer.destroyUserData(userHandle,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
// Remove this user from the list
@@ -3125,7 +3130,7 @@ public class UserManagerService extends IUserManager.Stub {
final int userSerial = userInfo.serialNumber;
// Migrate only if build fingerprints mismatch
boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
- mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
+ mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData);
if (userId != UserHandle.USER_SYSTEM) {
@@ -3133,8 +3138,6 @@ public class UserManagerService extends IUserManager.Stub {
applyUserRestrictionsLR(userId);
}
}
-
- maybeInitializeDemoMode(userId);
}
/**
@@ -3149,11 +3152,20 @@ public class UserManagerService extends IUserManager.Stub {
final int userSerial = userInfo.serialNumber;
// Migrate only if build fingerprints mismatch
boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
- mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
+ mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData);
}
/**
+ * Examine all users present on given mounted volume, and destroy data
+ * belonging to users that are no longer valid, or whose user ID has been
+ * recycled.
+ */
+ void reconcileUsers(String volumeUuid) {
+ mUserDataPreparer.reconcileUsers(volumeUuid, getUsers(true /* excludeDying */));
+ }
+
+ /**
* Make a note of the last started time of a user and do some cleanup.
* This is called with ActivityManagerService lock held.
* @param userId the user that was just foregrounded
@@ -3173,29 +3185,6 @@ public class UserManagerService extends IUserManager.Stub {
scheduleWriteUser(userData);
}
- private void maybeInitializeDemoMode(int userId) {
- if (UserManager.isDeviceInDemoMode(mContext) && userId != UserHandle.USER_SYSTEM) {
- String demoLauncher =
- mContext.getResources().getString(
- com.android.internal.R.string.config_demoModeLauncherComponent);
- if (!TextUtils.isEmpty(demoLauncher)) {
- ComponentName componentToEnable = ComponentName.unflattenFromString(demoLauncher);
- String demoLauncherPkg = componentToEnable.getPackageName();
- try {
- final IPackageManager iPm = AppGlobals.getPackageManager();
- iPm.setComponentEnabledSetting(componentToEnable,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
- /* userId= */ userId);
- iPm.setApplicationEnabledSetting(demoLauncherPkg,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
- /* userId= */ userId, null);
- } catch (RemoteException re) {
- // Internal, shouldn't happen
- }
- }
- }
- }
-
/**
* Returns the next available user id, filling in any holes in the ids.
*/
@@ -3237,78 +3226,6 @@ public class UserManagerService extends IUserManager.Stub {
return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX;
}
- /**
- * Enforce that serial number stored in user directory inode matches the
- * given expected value. Gracefully sets the serial number if currently
- * undefined.
- *
- * @throws IOException when problem extracting serial number, or serial
- * number is mismatched.
- */
- public static void enforceSerialNumber(File file, int serialNumber) throws IOException {
- if (StorageManager.isFileEncryptedEmulatedOnly()) {
- // When we're emulating FBE, the directory may have been chmod
- // 000'ed, meaning we can't read the serial number to enforce it;
- // instead of destroying the user, just log a warning.
- Slog.w(LOG_TAG, "Device is emulating FBE; assuming current serial number is valid");
- return;
- }
-
- final int foundSerial = getSerialNumber(file);
- Slog.v(LOG_TAG, "Found " + file + " with serial number " + foundSerial);
-
- if (foundSerial == -1) {
- Slog.d(LOG_TAG, "Serial number missing on " + file + "; assuming current is valid");
- try {
- setSerialNumber(file, serialNumber);
- } catch (IOException e) {
- Slog.w(LOG_TAG, "Failed to set serial number on " + file, e);
- }
-
- } else if (foundSerial != serialNumber) {
- throw new IOException("Found serial number " + foundSerial
- + " doesn't match expected " + serialNumber);
- }
- }
-
- /**
- * Set serial number stored in user directory inode.
- *
- * @throws IOException if serial number was already set
- */
- private static void setSerialNumber(File file, int serialNumber)
- throws IOException {
- try {
- final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8);
- Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE);
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
- }
- }
-
- /**
- * Return serial number stored in user directory inode.
- *
- * @return parsed serial number, or -1 if not set
- */
- private static int getSerialNumber(File file) throws IOException {
- try {
- final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
- final String serial = new String(buf);
- try {
- return Integer.parseInt(serial);
- } catch (NumberFormatException e) {
- throw new IOException("Bad serial number: " + serial);
- }
- } catch (ErrnoException e) {
- if (e.errno == OsConstants.ENODATA) {
- return -1;
- } else {
- throw e.rethrowAsIOException();
- }
- }
- }
-
@Override
public void setSeedAccountData(int userId, String accountName, String accountType,
PersistableBundle accountOptions, boolean persist) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d301463db164..0a1574b730a9 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -474,11 +474,12 @@ public class UserRestrictionsUtils {
}
break;
case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES:
- if (newValue) {
- android.provider.Settings.Secure.putIntForUser(cr,
- android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
- userId);
- }
+ // Since Android O, the secure setting is not available to be changed by the
+ // user. Hence, when the restriction is cleared, we need to reset the state of
+ // the setting to its default value which is now 1.
+ android.provider.Settings.Secure.putIntForUser(cr,
+ android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
+ newValue ? 0 : 1, userId);
break;
case UserManager.DISALLOW_RUN_IN_BACKGROUND:
if (newValue) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 6d06838cd24f..00f3711c7038 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,13 +16,21 @@
package com.android.server.pm.dex;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
-import android.content.pm.ApplicationInfo;
+import android.os.RemoteException;
+import android.os.storage.StorageManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.PackageDexOptimizer;
import com.android.server.pm.PackageManagerServiceUtils;
+import com.android.server.pm.PackageManagerServiceCompilerMapping;
import java.io.File;
import java.io.IOException;
@@ -32,6 +40,9 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
+
/**
* This class keeps track of how dex files are used.
* Every time it gets a notification about a dex file being loaded it tracks
@@ -54,15 +65,26 @@ public class DexManager {
// encode and save the dex usage data.
private final PackageDexUsage mPackageDexUsage;
+ private final IPackageManager mPackageManager;
+ private final PackageDexOptimizer mPackageDexOptimizer;
+ private final Object mInstallLock;
+ @GuardedBy("mInstallLock")
+ private final Installer mInstaller;
+
// Possible outcomes of a dex search.
private static int DEX_SEARCH_NOT_FOUND = 0; // dex file not found
private static int DEX_SEARCH_FOUND_PRIMARY = 1; // dex file is the primary/base apk
private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
- public DexManager() {
+ public DexManager(IPackageManager pms, PackageDexOptimizer pdo,
+ Installer installer, Object installLock) {
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
+ mPackageManager = pms;
+ mPackageDexOptimizer = pdo;
+ mInstaller = installer;
+ mInstallLock = installLock;
}
/**
@@ -132,8 +154,8 @@ public class DexManager {
// - new installed splits
// If we can't find the owner of the dex we simply do not track it. The impact is
// that the dex file will not be considered for offline optimizations.
- // TODO(calin): add hooks for install/uninstall notifications to
- // capture new or obsolete packages.
+ // TODO(calin): add hooks for move/uninstall notifications to
+ // capture package moves or obsolete packages.
if (DEBUG) {
Slog.i(TAG, "Could not find owning package for dex file: " + dexPath);
}
@@ -157,6 +179,20 @@ public class DexManager {
}
}
+ public void notifyPackageInstalled(PackageInfo info, int userId) {
+ cachePackageCodeLocation(info, userId);
+ }
+
+ private void cachePackageCodeLocation(PackageInfo info, int userId) {
+ PackageCodeLocations pcl = mPackageCodeLocationsCache.get(info.packageName);
+ if (pcl != null) {
+ pcl.mergeAppDataDirs(info.applicationInfo, userId);
+ } else {
+ mPackageCodeLocationsCache.put(info.packageName,
+ new PackageCodeLocations(info.applicationInfo, userId));
+ }
+ }
+
private void loadInternal(Map<Integer, List<PackageInfo>> existingPackages) {
Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
// Cache the code locations for the installed packages. This allows for
@@ -166,13 +202,8 @@ public class DexManager {
int userId = entry.getKey();
for (PackageInfo pi : packageInfoList) {
// Cache the code locations.
- PackageCodeLocations pcl = mPackageCodeLocationsCache.get(pi.packageName);
- if (pcl != null) {
- pcl.mergeAppDataDirs(pi.applicationInfo, userId);
- } else {
- mPackageCodeLocationsCache.put(pi.packageName,
- new PackageCodeLocations(pi.applicationInfo, userId));
- }
+ cachePackageCodeLocation(pi, userId);
+
// Cache a map from package name to the set of user ids who installed the package.
// We will use it to sync the data and remove obsolete entries from
// mPackageDexUsage.
@@ -190,11 +221,144 @@ public class DexManager {
* Get the package dex usage for the given package name.
* @return the package data or null if there is no data available for this package.
*/
- public PackageDexUsage.PackageUseInfo getPackageUseInfo(String packageName) {
+ public PackageUseInfo getPackageUseInfo(String packageName) {
return mPackageDexUsage.getPackageUseInfo(packageName);
}
/**
+ * Perform dexopt on the package {@code packageName} secondary dex files.
+ * @return true if all secondary dex files were processed successfully (compiled or skipped
+ * because they don't need to be compiled)..
+ */
+ public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force) {
+ // Select the dex optimizer based on the force parameter.
+ // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
+ // the necessary dexopt flags to make sure that compilation is not skipped. This avoid
+ // passing the force flag through the multitude of layers.
+ // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
+ // allocate an object here.
+ PackageDexOptimizer pdo = force
+ ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
+ : mPackageDexOptimizer;
+ PackageUseInfo useInfo = getPackageUseInfo(packageName);
+ if (useInfo == null || useInfo.getDexUseInfoMap().isEmpty()) {
+ if (DEBUG) {
+ Slog.d(TAG, "No secondary dex use for package:" + packageName);
+ }
+ // Nothing to compile, return true.
+ return true;
+ }
+ boolean success = true;
+ for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
+ String dexPath = entry.getKey();
+ DexUseInfo dexUseInfo = entry.getValue();
+ PackageInfo pkg = null;
+ try {
+ pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ dexUseInfo.getOwnerUserId());
+ } catch (RemoteException e) {
+ throw new AssertionError(e);
+ }
+ // It may be that the package gets uninstalled while we try to compile its
+ // secondary dex files. If that's the case, just ignore.
+ // Note that we don't break the entire loop because the package might still be
+ // installed for other users.
+ if (pkg == null) {
+ Slog.d(TAG, "Could not find package when compiling secondary dex " + packageName
+ + " for user " + dexUseInfo.getOwnerUserId());
+ mPackageDexUsage.removeUserPackage(packageName, dexUseInfo.getOwnerUserId());
+ continue;
+ }
+ int result = pdo.dexOptSecondaryDexPath(pkg.applicationInfo, dexPath,
+ dexUseInfo.getLoaderIsas(), compilerFilter, dexUseInfo.isUsedByOtherApps());
+ success = success && (result != PackageDexOptimizer.DEX_OPT_FAILED);
+ }
+ return success;
+ }
+
+ /**
+ * Reconcile the information we have about the secondary dex files belonging to
+ * {@code packagName} and the actual dex files. For all dex files that were
+ * deleted, update the internal records and delete any generated oat files.
+ */
+ public void reconcileSecondaryDexFiles(String packageName) {
+ PackageUseInfo useInfo = getPackageUseInfo(packageName);
+ if (useInfo == null || useInfo.getDexUseInfoMap().isEmpty()) {
+ if (DEBUG) {
+ Slog.d(TAG, "No secondary dex use for package:" + packageName);
+ }
+ // Nothing to reconcile.
+ return;
+ }
+ Set<String> dexFilesToRemove = new HashSet<>();
+ boolean updated = false;
+ for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
+ String dexPath = entry.getKey();
+ DexUseInfo dexUseInfo = entry.getValue();
+ PackageInfo pkg = null;
+ try {
+ // Note that we look for the package in the PackageManager just to be able
+ // to get back the real app uid and its storage kind. These are only used
+ // to perform extra validation in installd.
+ // TODO(calin): maybe a bit overkill.
+ pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ dexUseInfo.getOwnerUserId());
+ } catch (RemoteException ignore) {
+ // Can't happen, DexManager is local.
+ }
+ if (pkg == null) {
+ // It may be that the package was uninstalled while we process the secondary
+ // dex files.
+ Slog.d(TAG, "Could not find package when compiling secondary dex " + packageName
+ + " for user " + dexUseInfo.getOwnerUserId());
+ // Update the usage and continue, another user might still have the package.
+ updated = mPackageDexUsage.removeUserPackage(
+ packageName, dexUseInfo.getOwnerUserId()) || updated;
+ continue;
+ }
+ ApplicationInfo info = pkg.applicationInfo;
+ int flags = 0;
+ if (info.dataDir.equals(info.deviceProtectedDataDir)) {
+ flags |= StorageManager.FLAG_STORAGE_DE;
+ } else if (info.dataDir.equals(info.credentialProtectedDataDir)) {
+ flags |= StorageManager.FLAG_STORAGE_CE;
+ } else {
+ Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
+ updated = mPackageDexUsage.removeUserPackage(
+ packageName, dexUseInfo.getOwnerUserId()) || updated;
+ continue;
+ }
+
+ boolean dexStillExists = true;
+ synchronized(mInstallLock) {
+ try {
+ String[] isas = dexUseInfo.getLoaderIsas().toArray(new String[0]);
+ dexStillExists = mInstaller.reconcileSecondaryDexFile(dexPath, packageName,
+ pkg.applicationInfo.uid, isas, pkg.applicationInfo.volumeUuid, flags);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Got InstallerException when reconciling dex " + dexPath +
+ " : " + e.getMessage());
+ }
+ }
+ if (!dexStillExists) {
+ updated = mPackageDexUsage.removeDexFile(
+ packageName, dexPath, dexUseInfo.getOwnerUserId()) || updated;
+ }
+
+ }
+ if (updated) {
+ mPackageDexUsage.maybeWriteAsync();
+ }
+ }
+
+ /**
+ * Return all packages that contain records of secondary dex files.
+ */
+ public Set<String> getAllPackagesWithSecondaryDexFiles() {
+ return mPackageDexUsage.getAllPackagesWithSecondaryDexFiles();
+ }
+
+ /**
* Retrieves the package which owns the given dexPath.
*/
private DexSearchResult getDexPackage(
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 10384a2749e8..3693bce04eb1 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -376,10 +376,84 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
}
}
+ /**
+ * Remove all the records about package {@code packageName} belonging to user {@code userId}.
+ * @return true if the record was found and actually deleted,
+ * false if the record doesn't exist
+ */
+ public boolean removeUserPackage(String packageName, int userId) {
+ synchronized (mPackageUseInfoMap) {
+ PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
+ if (packageUseInfo == null) {
+ return false;
+ }
+ boolean updated = false;
+ Iterator<Map.Entry<String, DexUseInfo>> dIt =
+ packageUseInfo.mDexUseInfoMap.entrySet().iterator();
+ while (dIt.hasNext()) {
+ DexUseInfo dexUseInfo = dIt.next().getValue();
+ if (dexUseInfo.mOwnerUserId == userId) {
+ dIt.remove();
+ updated = true;
+ }
+ }
+ return updated;
+ }
+ }
+
+ /**
+ * Remove the secondary dex file record belonging to the package {@code packageName}
+ * and user {@code userId}.
+ * @return true if the record was found and actually deleted,
+ * false if the record doesn't exist
+ */
+ public boolean removeDexFile(String packageName, String dexFile, int userId) {
+ synchronized (mPackageUseInfoMap) {
+ PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
+ if (packageUseInfo == null) {
+ return false;
+ }
+ return removeDexFile(packageUseInfo, dexFile, userId);
+ }
+ }
+
+ private boolean removeDexFile(PackageUseInfo packageUseInfo, String dexFile, int userId) {
+ DexUseInfo dexUseInfo = packageUseInfo.mDexUseInfoMap.get(dexFile);
+ if (dexUseInfo == null) {
+ return false;
+ }
+ if (dexUseInfo.mOwnerUserId == userId) {
+ packageUseInfo.mDexUseInfoMap.remove(dexFile);
+ return true;
+ }
+ return false;
+ }
+
public PackageUseInfo getPackageUseInfo(String packageName) {
synchronized (mPackageUseInfoMap) {
- return mPackageUseInfoMap.get(packageName);
+ PackageUseInfo useInfo = mPackageUseInfoMap.get(packageName);
+ // The useInfo contains a map for secondary dex files which could be modified
+ // concurrently after this method returns and thus outside the locking we do here.
+ // (i.e. the map is updated when new class loaders are created, which can happen anytime
+ // after this method returns)
+ // Make a defensive copy to be sure we don't get concurrent modifications.
+ return useInfo == null ? null : new PackageUseInfo(useInfo);
+ }
+ }
+
+ /**
+ * Return all packages that contain records of secondary dex files.
+ */
+ public Set<String> getAllPackagesWithSecondaryDexFiles() {
+ Set<String> packages = new HashSet<>();
+ synchronized (mPackageUseInfoMap) {
+ for (Map.Entry<String, PackageUseInfo> entry : mPackageUseInfoMap.entrySet()) {
+ if (!entry.getValue().mDexUseInfoMap.isEmpty()) {
+ packages.add(entry.getKey());
+ }
+ }
}
+ return packages;
}
public void clear() {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 6edb4d2d2ac1..7a2808146f62 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -18,6 +18,7 @@ package com.android.server.policy;
import android.app.StatusBarManager;
import android.os.Handler;
+import android.os.Message;
import android.os.SystemClock;
import android.util.Slog;
import android.view.View;
@@ -43,6 +44,8 @@ public class BarController {
private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
+ private static final int MSG_NAV_BAR_VISIBILITY_CHANGED = 1;
+
protected final String mTag;
private final int mTransientFlag;
private final int mUnhideFlag;
@@ -63,6 +66,8 @@ public class BarController {
private boolean mSetUnHideFlagWhenNextTransparent;
private boolean mNoAnimationOnNextShow;
+ private OnBarVisibilityChangedListener mVisibilityChangeListener;
+
public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
int statusBarManagerId, int translucentWmFlag, int transparentFlag) {
mTag = "BarController." + tag;
@@ -72,7 +77,7 @@ public class BarController {
mStatusBarManagerId = statusBarManagerId;
mTranslucentWmFlag = translucentWmFlag;
mTransparentFlag = transparentFlag;
- mHandler = new Handler();
+ mHandler = new BarHandler();
}
public void setWindow(WindowState win) {
@@ -153,9 +158,18 @@ public class BarController {
mNoAnimationOnNextShow = false;
final int state = computeStateLw(wasVis, wasAnim, mWin, change);
final boolean stateChanged = updateStateLw(state);
+
+ if (change && (mVisibilityChangeListener != null)) {
+ mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED, show ? 1 : 0, 0).sendToTarget();
+ }
+
return change || stateChanged;
}
+ void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener) {
+ mVisibilityChangeListener = listener;
+ }
+
protected boolean skipAnimation() {
return false;
}
@@ -300,4 +314,22 @@ public class BarController {
pw.println(transientBarStateToString(mTransientBarState));
}
}
+
+ private class BarHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_NAV_BAR_VISIBILITY_CHANGED:
+ final boolean visible = msg.arg1 != 0;
+ if (mVisibilityChangeListener != null) {
+ mVisibilityChangeListener.onBarVisibilityChanged(visible);
+ }
+ break;
+ }
+ }
+ }
+
+ interface OnBarVisibilityChangedListener {
+ void onBarVisibilityChanged(boolean visible);
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c25ad468cf09..3e051571aab0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -16,17 +16,24 @@
package com.android.server.policy;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.AppOpsManager.OP_TOAST_WINDOW;
import static android.content.Context.DISPLAY_SERVICE;
import static android.content.Context.WINDOW_SERVICE;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.os.Build.VERSION_CODES.M;
+import static android.os.Build.VERSION_CODES.O;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
@@ -63,21 +70,14 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -103,8 +103,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
+import static android.view.WindowManagerGlobal.ADD_OKAY;
+import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -146,6 +149,7 @@ import android.hardware.display.DisplayManager;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
import android.hardware.power.V1_0.PowerHint;
import android.media.AudioAttributes;
@@ -156,7 +160,6 @@ import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
@@ -201,6 +204,7 @@ import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.FallbackAction;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
@@ -261,6 +265,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// No longer recommended for desk docks;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+ // Whether to allow devices placed in vr headset viewers to have an alternative Home intent.
+ static final boolean ENABLE_VR_HEADSET_HOME_CAPTURE = true;
+
static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
static final int SHORT_PRESS_POWER_NOTHING = 0;
@@ -311,12 +318,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
- static final int APPLICATION_MEDIA_SUBLAYER = -2;
- static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
- static final int APPLICATION_PANEL_SUBLAYER = 1;
- static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
- static final int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
-
static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -684,6 +685,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Intent mHomeIntent;
Intent mCarDockIntent;
Intent mDeskDockIntent;
+ Intent mVrHeadsetHomeIntent;
boolean mSearchKeyShortcutPending;
boolean mConsumeSearchKeyUp;
boolean mAssistKeyLongPressed;
@@ -990,6 +992,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
View.NAVIGATION_BAR_TRANSPARENT);
+ private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
+ new BarController.OnBarVisibilityChangedListener() {
+ @Override
+ public void onBarVisibilityChanged(boolean visible) {
+ mAccessibilityManager.notifyAccessibilityButtonAvailabilityChanged(visible);
+ }
+ };
+
private ImmersiveModeConfirmation mImmersiveModeConfirmation;
private SystemGesturesPointerEventListener mSystemGestures;
@@ -1791,6 +1801,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mVrHeadsetHomeIntent = new Intent(Intent.ACTION_MAIN, null);
+ mVrHeadsetHomeIntent.addCategory(Intent.CATEGORY_VR_HOME);
+ mVrHeadsetHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -2307,86 +2321,82 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
// Window manager will make sure these are okay.
- return WindowManagerGlobal.ADD_OKAY;
- }
- String permission = null;
- switch (type) {
- case TYPE_TOAST:
- // XXX right now the app process has complete control over
- // this... should introduce a token to let the system
- // monitor/control what they are doing.
- outAppOp[0] = AppOpsManager.OP_TOAST_WINDOW;
- break;
- case TYPE_DREAM:
- case TYPE_INPUT_METHOD:
- case TYPE_WALLPAPER:
- case TYPE_PRESENTATION:
- case TYPE_PRIVATE_PRESENTATION:
- case TYPE_VOICE_INTERACTION:
- case TYPE_ACCESSIBILITY_OVERLAY:
- case TYPE_QS_DIALOG:
- // The window manager will check these.
- break;
- case TYPE_PHONE:
- case TYPE_PRIORITY_PHONE:
- case TYPE_SYSTEM_ALERT:
- case TYPE_SYSTEM_ERROR:
- case TYPE_SYSTEM_OVERLAY:
- permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
- outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
- break;
- default:
- permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
- }
- if (permission != null) {
- if (android.Manifest.permission.SYSTEM_ALERT_WINDOW.equals(permission)) {
- final int callingUid = Binder.getCallingUid();
- // system processes will be automatically allowed privilege to draw
- if (callingUid == Process.SYSTEM_UID) {
- return WindowManagerGlobal.ADD_OKAY;
- }
-
- // check if user has enabled this operation. SecurityException will be thrown if
- // this app has not been allowed by the user
- final int mode = mAppOpsManager.checkOpNoThrow(outAppOp[0], callingUid,
- attrs.packageName);
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- case AppOpsManager.MODE_IGNORED:
- // although we return ADD_OKAY for MODE_IGNORED, the added window will
- // actually be hidden in WindowManagerService
- return WindowManagerGlobal.ADD_OKAY;
- case AppOpsManager.MODE_ERRORED:
- try {
- ApplicationInfo appInfo = mContext.getPackageManager()
- .getApplicationInfo(attrs.packageName,
- UserHandle.getUserId(callingUid));
- // Don't crash legacy apps
- if (appInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- return WindowManagerGlobal.ADD_OKAY;
- }
- } catch (PackageManager.NameNotFoundException e) {
- /* ignore */
- }
- return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- default:
- // in the default mode, we will make a decision here based on
- // checkCallingPermission()
- if (mContext.checkCallingPermission(permission) !=
- PackageManager.PERMISSION_GRANTED) {
- return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- } else {
- return WindowManagerGlobal.ADD_OKAY;
- }
+ return ADD_OKAY;
+ }
+
+ if (!isSystemAlertWindowType(type)) {
+ switch (type) {
+ case TYPE_TOAST:
+ // Only apps that target older than O SDK can add window without a token, after
+ // that we require a token so apps cannot add toasts directly as the token is
+ // added by the notification system.
+ // Window manager does the checking for this.
+ outAppOp[0] = OP_TOAST_WINDOW;
+ return ADD_OKAY;
+ case TYPE_DREAM:
+ case TYPE_INPUT_METHOD:
+ case TYPE_WALLPAPER:
+ case TYPE_PRESENTATION:
+ case TYPE_PRIVATE_PRESENTATION:
+ case TYPE_VOICE_INTERACTION:
+ case TYPE_ACCESSIBILITY_OVERLAY:
+ case TYPE_QS_DIALOG:
+ // The window manager will check these.
+ return ADD_OKAY;
+ }
+ return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
+ == PERMISSION_GRANTED ? ADD_OKAY : ADD_PERMISSION_DENIED;
+ }
+
+ // Things get a little more interesting for alert windows...
+ outAppOp[0] = OP_SYSTEM_ALERT_WINDOW;
+
+ final int callingUid = Binder.getCallingUid();
+ // system processes will be automatically granted privilege to draw
+ if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+ return ADD_OKAY;
+ }
+
+ ApplicationInfo appInfo;
+ try {
+ appInfo = mContext.getPackageManager().getApplicationInfo(attrs.packageName,
+ UserHandle.getUserId(callingUid));
+ } catch (PackageManager.NameNotFoundException e) {
+ appInfo = null;
+ }
+
+ if (appInfo == null || (type != TYPE_APPLICATION_OVERLAY && appInfo.targetSdkVersion >= O)) {
+ /**
+ * Apps targeting >= {@link Build.VERSION_CODES#O} are required to hold
+ * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} (system signature apps)
+ * permission to add alert windows that aren't
+ * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}.
+ */
+ return (mContext.checkCallingPermission(INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED)
+ ? ADD_OKAY : ADD_PERMISSION_DENIED;
+ }
+
+ // check if user has enabled this operation. SecurityException will be thrown if this app
+ // has not been allowed by the user
+ final int mode = mAppOpsManager.checkOpNoThrow(outAppOp[0], callingUid, attrs.packageName);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ case AppOpsManager.MODE_IGNORED:
+ // although we return ADD_OKAY for MODE_IGNORED, the added window will
+ // actually be hidden in WindowManagerService
+ return ADD_OKAY;
+ case AppOpsManager.MODE_ERRORED:
+ // Don't crash legacy apps
+ if (appInfo.targetSdkVersion < M) {
+ return ADD_OKAY;
}
- }
-
- if (mContext.checkCallingOrSelfPermission(permission)
- != PackageManager.PERMISSION_GRANTED) {
- return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- }
+ return ADD_PERMISSION_DENIED;
+ default:
+ // in the default mode, we will make a decision here based on
+ // checkCallingPermission()
+ return (mContext.checkCallingPermission(SYSTEM_ALERT_WINDOW) == PERMISSION_GRANTED)
+ ? ADD_OKAY : ADD_PERMISSION_DENIED;
}
- return WindowManagerGlobal.ADD_OKAY;
}
@Override
@@ -2432,9 +2442,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
// Check if third party app has set window to system window type.
- return mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
- != PackageManager.PERMISSION_GRANTED;
+ return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW) != PERMISSION_GRANTED;
}
@Override
@@ -2583,130 +2591,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- /** {@inheritDoc} */
- @Override
- public int windowTypeToLayerLw(int type) {
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return 2;
- }
- switch (type) {
- case TYPE_WALLPAPER:
- // wallpaper is at the bottom, though the window manager may move it.
- return 1;
- case TYPE_PRESENTATION:
- case TYPE_PRIVATE_PRESENTATION:
- return 2;
- case TYPE_DOCK_DIVIDER:
- return 2;
- case TYPE_QS_DIALOG:
- return 2;
- case TYPE_PHONE:
- return 3;
- case TYPE_SEARCH_BAR:
- case TYPE_VOICE_INTERACTION_STARTING:
- return 4;
- case TYPE_VOICE_INTERACTION:
- // voice interaction layer is almost immediately above apps.
- return 5;
- case TYPE_INPUT_CONSUMER:
- return 6;
- case TYPE_SYSTEM_DIALOG:
- return 7;
- case TYPE_TOAST:
- // toasts and the plugged-in battery thing
- return 8;
- case TYPE_PRIORITY_PHONE:
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- return 9;
- case TYPE_DREAM:
- // used for Dreams (screensavers with TYPE_DREAM windows)
- return 10;
- case TYPE_SYSTEM_ALERT:
- // like the ANR / app crashed dialogs
- return 11;
- case TYPE_INPUT_METHOD:
- // on-screen keyboards and other such input method user interfaces go here.
- return 12;
- case TYPE_INPUT_METHOD_DIALOG:
- // on-screen keyboards and other such input method user interfaces go here.
- return 13;
- case TYPE_STATUS_BAR_SUB_PANEL:
- return 15;
- case TYPE_STATUS_BAR:
- return 16;
- case TYPE_STATUS_BAR_PANEL:
- return 17;
- case TYPE_KEYGUARD_DIALOG:
- return 18;
- case TYPE_VOLUME_OVERLAY:
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- return 19;
- case TYPE_SYSTEM_OVERLAY:
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- return 20;
- case TYPE_NAVIGATION_BAR:
- // the navigation bar, if available, shows atop most things
- return 21;
- case TYPE_NAVIGATION_BAR_PANEL:
- // some panels (e.g. search) need to show on top of the navigation bar
- return 22;
- case TYPE_SCREENSHOT:
- // screenshot selection layer shouldn't go above system error, but it should cover
- // navigation bars at the very least.
- return 23;
- case TYPE_SYSTEM_ERROR:
- // system-level error dialogs
- return 24;
- case TYPE_MAGNIFICATION_OVERLAY:
- // used to highlight the magnified portion of a display
- return 25;
- case TYPE_DISPLAY_OVERLAY:
- // used to simulate secondary display devices
- return 26;
- case TYPE_DRAG:
- // the drag layer: input for drag-and-drop is associated with this window,
- // which sits above all other focusable windows
- return 27;
- case TYPE_ACCESSIBILITY_OVERLAY:
- // overlay put by accessibility services to intercept user interaction
- return 28;
- case TYPE_SECURE_SYSTEM_OVERLAY:
- return 29;
- case TYPE_BOOT_PROGRESS:
- return 30;
- case TYPE_POINTER:
- // the (mouse) pointer layer
- return 31;
- }
- Log.e(TAG, "Unknown window type: " + type);
- return 2;
- }
-
- /** {@inheritDoc} */
- @Override
- public int subWindowTypeToLayerLw(int type) {
- switch (type) {
- case TYPE_APPLICATION_PANEL:
- case TYPE_APPLICATION_ATTACHED_DIALOG:
- return APPLICATION_PANEL_SUBLAYER;
- case TYPE_APPLICATION_MEDIA:
- return APPLICATION_MEDIA_SUBLAYER;
- case TYPE_APPLICATION_MEDIA_OVERLAY:
- return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
- case TYPE_APPLICATION_SUB_PANEL:
- return APPLICATION_SUB_PANEL_SUBLAYER;
- case TYPE_APPLICATION_ABOVE_SUB_PANEL:
- return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
- }
- Log.e(TAG, "Unknown sub-window type: " + type);
- return 0;
- }
-
@Override
public int getMaxWallpaperLayer() {
- return windowTypeToLayerLw(TYPE_STATUS_BAR);
+ return getWindowLayerFromTypeLw(TYPE_STATUS_BAR);
}
private int getNavigationBarWidth(int rotation, int uiMode) {
@@ -2789,8 +2676,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return false;
default:
// Hide only windows below the keyguard host window.
- return windowTypeToLayerLw(win.getBaseType())
- < windowTypeToLayerLw(TYPE_STATUS_BAR);
+ return getWindowLayerLw(win) < getWindowLayerFromTypeLw(TYPE_STATUS_BAR);
}
}
@@ -3024,6 +2910,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
mNavigationBar = win;
mNavigationBarController.setWindow(win);
+ mNavigationBarController.setOnBarVisibilityChangedListener(
+ mNavBarVisibilityListener);
if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
break;
case TYPE_NAVIGATION_BAR_PANEL:
@@ -3035,7 +2923,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
"PhoneWindowManager");
break;
}
- return WindowManagerGlobal.ADD_OKAY;
+ return ADD_OKAY;
}
/** {@inheritDoc} */
@@ -3563,6 +3451,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
dispatchDirectAudioEvent(event);
return -1;
}
+ } else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
+ // Pass through keyboard navigation keys.
+ return 0;
}
// Toggle Caps Lock on META-ALT.
@@ -4357,6 +4248,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mInputConsumer = mWindowManagerFuncs.createInputConsumer(mHandler.getLooper(),
INPUT_CONSUMER_NAVIGATION,
(channel, looper) -> new HideNavInputEventReceiver(channel, looper));
+ // As long as mInputConsumer is active, hover events are not dispatched to the app
+ // and the pointer icon is likely to become stale. Hide it to avoid confusion.
+ InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
}
// For purposes of positioning and showing the nav bar, if we have
@@ -5896,9 +5790,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& (result & ACTION_PASS_TO_USER) == 0) {
// If we are in call but we decided not to pass the key to
// the application, just pass it to the session service.
-
- MediaSessionLegacyHelper.getHelper(mContext)
- .sendVolumeKeyEvent(event, false);
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
break;
}
}
@@ -5911,8 +5804,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If we aren't passing to the user and no one else
// handled it send it to the session manager to
// figure out.
- MediaSessionLegacyHelper.getHelper(mContext)
- .sendVolumeKeyEvent(event, true);
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
}
break;
}
@@ -6104,13 +5997,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param event
*/
private void interceptSystemNavigationKey(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_UP && areSystemNavigationKeysEnabled()) {
- IStatusBarService sbar = getStatusBarService();
- if (sbar != null) {
- try {
- sbar.handleSystemNavigationKey(event.getKeyCode());
- } catch (RemoteException e1) {
- // oops, no statusbar. Ignore event.
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (!mAccessibilityManager.isEnabled()
+ || !mAccessibilityManager.sendFingerprintGesture(event.getKeyCode())) {
+ if (areSystemNavigationKeysEnabled()) {
+ IStatusBarService sbar = getStatusBarService();
+ if (sbar != null) {
+ try {
+ sbar.handleSystemNavigationKey(event.getKeyCode());
+ } catch (RemoteException e1) {
+ // oops, no statusbar. Ignore event.
+ }
+ }
}
}
}
@@ -7390,6 +7288,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|| mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK)) {
// Always launch dock home from home when watch is docked, if it exists.
intent = mDeskDockIntent;
+ } else if (mUiMode == Configuration.UI_MODE_TYPE_VR_HEADSET) {
+ if (ENABLE_VR_HEADSET_HOME_CAPTURE) {
+ intent = mVrHeadsetHomeIntent;
+ }
}
if (intent == null) {
@@ -7818,8 +7720,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
final boolean navAllowedHidden = immersive || immersiveSticky;
- if (hideNavBarSysui && !navAllowedHidden && windowTypeToLayerLw(win.getBaseType())
- > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
+ if (hideNavBarSysui && !navAllowedHidden
+ && getWindowLayerLw(win) > getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
// We can't hide the navbar from this window otherwise the input consumer would not get
// the input events.
vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index b215998de222..c31369e0c282 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -22,6 +22,8 @@ import android.app.RetailDemoModeServiceInternal;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -32,6 +34,7 @@ import android.hardware.input.InputManagerInternal;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.Handler;
@@ -401,6 +404,10 @@ final class Notifier {
mHandler.post(new Runnable() {
@Override
public void run() {
+ LogMaker log = new LogMaker(MetricsEvent.SCREEN);
+ log.setType(MetricsEvent.TYPE_OPEN);
+ log.setSubtype(0); // not user initiated
+ MetricsLogger.action(log);
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.startedWakingUp();
}
@@ -457,6 +464,10 @@ final class Notifier {
mHandler.post(new Runnable() {
@Override
public void run() {
+ LogMaker log = new LogMaker(MetricsEvent.SCREEN);
+ log.setType(MetricsEvent.TYPE_CLOSE);
+ log.setSubtype(why);
+ MetricsLogger.action(log);
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
mPolicy.finishedGoingToSleep(why);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index e1b6c87a7049..91a5f4fec61e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -57,6 +57,7 @@ import android.service.dreams.DreamManagerInternal;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.EventLog;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -516,12 +517,68 @@ public final class PowerManagerService extends SystemService
private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
= new ArrayList<PowerManagerInternal.LowPowerModeListener>();
- // True if brightness should be affected by twilight.
- private boolean mBrightnessUseTwilight;
-
// True if we are currently in VR Mode.
private boolean mIsVrModeEnabled;
+ /**
+ * All times are in milliseconds. These constants are kept synchronized with the system
+ * global Settings. Any access to this class or its fields should be done while
+ * holding the PowerManagerService.mLock lock.
+ */
+ private final class Constants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_NO_CACHED_WAKE_LOCKS = "no_cached_wake_locks";
+
+ private static final boolean DEFAULT_NO_CACHED_WAKE_LOCKS = true;
+
+ // Prevent processes that are cached from holding wake locks?
+ public boolean NO_CACHED_WAKE_LOCKS = DEFAULT_NO_CACHED_WAKE_LOCKS;
+
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ public Constants(Handler handler) {
+ super(handler);
+ }
+
+ public void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.POWER_MANAGER_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (mLock) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.POWER_MANAGER_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad alarm manager settings", e);
+ }
+
+ NO_CACHED_WAKE_LOCKS = mParser.getBoolean(KEY_NO_CACHED_WAKE_LOCKS,
+ DEFAULT_NO_CACHED_WAKE_LOCKS);
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" Settings " + Settings.Global.POWER_MANAGER_CONSTANTS + ":");
+
+ pw.print(" "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
+ pw.println(NO_CACHED_WAKE_LOCKS);
+ }
+ }
+
+ final Constants mConstants;
+
private native void nativeInit();
private static native void nativeAcquireSuspendBlocker(String name);
@@ -538,6 +595,7 @@ public final class PowerManagerService extends SystemService
Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
mHandlerThread.start();
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
+ mConstants = new Constants(mHandler);
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -616,6 +674,9 @@ public final class PowerManagerService extends SystemService
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy);
+ final ContentResolver resolver = mContext.getContentResolver();
+ mConstants.start(resolver);
+
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
@@ -629,7 +690,6 @@ public final class PowerManagerService extends SystemService
mDisplayPowerCallbacks, mHandler, sensorManager);
// Register for settings changes.
- final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -672,9 +732,6 @@ public final class PowerManagerService extends SystemService
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOUBLE_TAP_TO_WAKE),
false, mSettingsObserver, UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Secure.BRIGHTNESS_USE_TWILIGHT),
- false, mSettingsObserver, UserHandle.USER_ALL);
IVrManager vrManager =
(IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
if (vrManager != null) {
@@ -815,9 +872,6 @@ public final class PowerManagerService extends SystemService
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
- mBrightnessUseTwilight = Settings.Secure.getIntForUser(resolver,
- Secure.BRIGHTNESS_USE_TWILIGHT, 0, UserHandle.USER_CURRENT) != 0;
-
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
@@ -2191,7 +2245,6 @@ public final class PowerManagerService extends SystemService
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
- mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
@@ -2795,7 +2848,7 @@ public final class PowerManagerService extends SystemService
state.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
disabled = true;
}
- } else {
+ } else if (mConstants.NO_CACHED_WAKE_LOCKS) {
disabled = !wakeLock.mUidState.mActive &&
wakeLock.mUidState.mProcState
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
@@ -3005,6 +3058,7 @@ public final class PowerManagerService extends SystemService
final WirelessChargerDetector wcd;
synchronized (mLock) {
pw.println("Power Manager State:");
+ mConstants.dump(pw);
pw.println(" mDirty=0x" + Integer.toHexString(mDirty));
pw.println(" mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness));
pw.println(" mWakefulnessChanging=" + mWakefulnessChanging);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index fb0dd2aba556..b4467af5aa0e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -23,9 +23,6 @@ import com.android.server.notification.NotificationDelegate;
public interface StatusBarManagerInternal {
void setNotificationDelegate(NotificationDelegate delegate);
- void buzzBeepBlinked();
- void notificationLightPulse(int argb, int onMillis, int offMillis);
- void notificationLightOff();
void showScreenPinningRequest(int taskId);
void showAssistDisclosure();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7b7db0e1440b..2dfe20a8e674 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -120,40 +120,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
@Override
- public void buzzBeepBlinked() {
- if (mBar != null) {
- try {
- mBar.buzzBeepBlinked();
- } catch (RemoteException ex) {
- }
- }
- }
-
- @Override
- public void notificationLightPulse(int argb, int onMillis, int offMillis) {
- mNotificationLightOn = true;
- if (mBar != null) {
- try {
- mBar.notificationLightPulse(argb, onMillis, offMillis);
- } catch (RemoteException ex) {
- }
- }
- }
-
- @Override
- public void notificationLightOff() {
- if (mNotificationLightOn) {
- mNotificationLightOn = false;
- if (mBar != null) {
- try {
- mBar.notificationLightOff();
- } catch (RemoteException ex) {
- }
- }
- }
- }
-
- @Override
public void showScreenPinningRequest(int taskId) {
if (mBar != null) {
try {
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index a3837b28b168..afdec9ffddc3 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -16,6 +16,7 @@
package com.android.server.storage;
+import android.app.NotificationChannel;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
import com.android.server.pm.InstructionSets;
@@ -140,6 +141,8 @@ public class DeviceStorageMonitorService extends SystemService {
*/
static final String SERVICE = "devicestoragemonitor";
+ private static final String NOTIFICATION_CHANNEL_ID = SERVICE;
+
/**
* Handler that checks the amount of disk space on the device and sends a
* notification if the device runs low on disk space
@@ -365,7 +368,8 @@ public class DeviceStorageMonitorService extends SystemService {
@Override
public void onStart() {
// cache storage thresholds
- final StorageManager sm = StorageManager.from(getContext());
+ Context context = getContext();
+ final StorageManager sm = StorageManager.from(context);
mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
@@ -378,6 +382,21 @@ public class DeviceStorageMonitorService extends SystemService {
mCacheFileDeletedObserver = new CacheFileDeletedObserver();
mCacheFileDeletedObserver.startWatching();
+ // Ensure that the notification channel is set up
+ NotificationManager notificationMgr =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ PackageManager packageManager = context.getPackageManager();
+ boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+
+ int importance = isTv
+ ? NotificationManager.IMPORTANCE_HIGH // Do not change: this is TV-specific
+ : NotificationManager.IMPORTANCE_LOW;
+ notificationMgr.createNotificationChannel(
+ new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+ context.getString(
+ com.android.internal.R.string.device_storage_monitor_notification_channel),
+ importance));
+
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
}
@@ -466,7 +485,7 @@ public class DeviceStorageMonitorService extends SystemService {
Intent lowMemIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
lowMemIntent.putExtra("memory", mFreeMem);
lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- NotificationManager mNotificationMgr =
+ NotificationManager notificationMgr =
(NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
CharSequence title = context.getText(
@@ -488,9 +507,11 @@ public class DeviceStorageMonitorService extends SystemService {
.bigText(details))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_SYSTEM)
+ .setChannel(NOTIFICATION_CHANNEL_ID)
+ .extend(new Notification.TvExtender())
.build();
notification.flags |= Notification.FLAG_NO_CLEAR;
- mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
+ notificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
}
diff --git a/services/core/java/com/android/server/storage/DiskStatsFileLogger.java b/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
index 22299df93ef5..0094ab5559d8 100644
--- a/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
+++ b/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
@@ -18,6 +18,7 @@ package com.android.server.storage;
import android.content.pm.PackageStats;
import android.os.Environment;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
@@ -118,7 +119,7 @@ public class DiskStatsFileLogger {
long appSizeSum = 0L;
long cacheSizeSum = 0L;
boolean isExternal = Environment.isExternalStorageEmulated();
- for (Map.Entry<String, PackageStats> entry : mergePackagesAcrossUsers().entrySet()) {
+ for (Map.Entry<String, PackageStats> entry : filterOnlyPrimaryUser().entrySet()) {
PackageStats stat = entry.getValue();
long appSize = stat.codeSize + stat.dataSize;
long cacheSize = stat.cacheSize;
@@ -141,14 +142,17 @@ public class DiskStatsFileLogger {
}
/**
- * A given package may exist for multiple users with distinct sizes. This function merges
- * the duplicated packages together and sums up their sizes to get the actual totals for the
- * package.
+ * A given package may exist for multiple users with distinct sizes. This function filters
+ * the packages that do not belong to user 0 out to ensure that we get good stats for a subset.
* @return A mapping of package name to merged package stats.
*/
- private ArrayMap<String, PackageStats> mergePackagesAcrossUsers() {
+ private ArrayMap<String, PackageStats> filterOnlyPrimaryUser() {
ArrayMap<String, PackageStats> packageMap = new ArrayMap<>();
for (PackageStats stat : mPackageStats) {
+ if (stat.userHandle != UserHandle.USER_SYSTEM) {
+ continue;
+ }
+
PackageStats existingStats = packageMap.get(stat.packageName);
if (existingStats != null) {
existingStats.cacheSize += stat.cacheSize;
diff --git a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
index 0a3abf31ff15..7c43162ec692 100644
--- a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
+++ b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
@@ -21,6 +21,7 @@ import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.AsyncTask;
@@ -28,6 +29,7 @@ import android.os.BatteryManager;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -54,7 +56,7 @@ public class DiskStatsLoggingService extends JobService {
public boolean onStartJob(JobParameters params) {
// We need to check the preconditions again because they may not be enforced for
// subsequent runs.
- if (!isCharging(this)) {
+ if (!isCharging(this) || !isDumpsysTaskEnabled(getContentResolver())) {
jobFinished(params, true);
return false;
}
@@ -105,6 +107,12 @@ public class DiskStatsLoggingService extends JobService {
}
@VisibleForTesting
+ static boolean isDumpsysTaskEnabled(ContentResolver resolver) {
+ // The default is to treat the task as enabled.
+ return Settings.Global.getInt(resolver, Settings.Global.ENABLE_DISKSTATS_LOGGING, 1) != 0;
+ }
+
+ @VisibleForTesting
static class LogRunnable implements Runnable {
private static final long TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10);
diff --git a/services/core/java/com/android/server/text/TextClassificationService.java b/services/core/java/com/android/server/text/TextClassificationService.java
new file mode 100644
index 000000000000..9358238dd2f4
--- /dev/null
+++ b/services/core/java/com/android/server/text/TextClassificationService.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.text;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.text.ITextClassificationService;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Text classification service.
+ * This is used to provide access to the text classification LSTM model file.
+ */
+public class TextClassificationService extends ITextClassificationService.Stub {
+
+ private static final String LOG_TAG = "TextClassificationService";
+
+ public static final class Lifecycle extends SystemService {
+
+ private TextClassificationService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ mService = new TextClassificationService();
+ }
+
+ @Override
+ public void onStart() {
+ try {
+ publishBinderService(Context.TEXT_CLASSIFICATION_SERVICE, mService);
+ } catch (Throwable t) {
+ // Starting this service is not critical to the running of this device and should
+ // therefore not crash the device. If it fails, log the error and continue.
+ Slog.e(LOG_TAG, "Could not start the TextClassificationService.", t);
+ }
+ }
+ }
+
+ @Override
+ public synchronized ParcelFileDescriptor getModelFileFd() throws RemoteException {
+ try {
+ return ParcelFileDescriptor.open(
+ new File("/etc/assistant/smart-selection.model"),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (Throwable t) {
+ Slog.e(LOG_TAG, "Error retrieving an fd to the text classification model file.", t);
+ throw new RemoteException(t.getMessage());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8cc53f070fbd..e0261304f0f0 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -23,15 +23,12 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.OperationApplicationException;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -84,12 +81,9 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.SystemService;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -241,44 +235,6 @@ public final class TvInputManagerService extends SystemService {
// the update can be handled in {@link #onSomePackagesChanged}.
return true;
}
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(getChangingUserId());
- if (!userState.packageSet.contains(packageName)) {
- // Not a TV input package.
- return;
- }
- }
-
- ArrayList<ContentProviderOperation> operations = new ArrayList<>();
-
- String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
- String[] selectionArgs = { packageName };
-
- operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
- .withSelection(selection, selectionArgs).build());
- operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
- .withSelection(selection, selectionArgs).build());
- operations.add(ContentProviderOperation
- .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
- .withSelection(selection, selectionArgs).build());
-
- ContentProviderResult[] results = null;
- try {
- ContentResolver cr = getContentResolverForUser(getChangingUserId());
- results = cr.applyBatch(TvContract.AUTHORITY, operations);
- } catch (RemoteException | OperationApplicationException e) {
- Slog.e(TAG, "error in applyBatch", e);
- }
-
- if (DEBUG) {
- Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
- + ")");
- Slog.d(TAG, "results=" + results);
- }
- }
};
monitor.register(mContext, null, UserHandle.ALL, true);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 0fc1900166e2..45b7baf8e8f5 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -79,4 +79,13 @@ public abstract class VrManagerInternal {
* given in {@link android.service.vr.VrModeException} on failure.
*/
public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
+
+ /**
+ * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+ * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
+ * by VR viewers to indicate that a device is placed in a VR viewer.
+ *
+ * @param enabled true if the device should be placed in persistent VR mode.
+ */
+ public abstract void setPersistentVrModeEnabled(boolean enabled);
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 57587b08c26b..51c4ce310801 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -20,18 +20,12 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -54,7 +48,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.R;
-import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -70,8 +63,6 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
-import java.util.List;
-import java.util.Map;
import java.util.Objects;
/**
@@ -88,9 +79,9 @@ import java.util.Objects;
* {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to
* be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
*
- * @see {@link android.service.vr.VrListenerService}
- * @see {@link com.android.server.vr.VrManagerInternal}
- * @see {@link com.android.server.vr.VrStateListener}
+ * @see android.service.vr.VrListenerService
+ * @see com.android.server.vr.VrManagerInternal
+ * @see com.android.server.vr.VrStateListener
*
* @hide
*/
@@ -122,8 +113,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
// State protected by mLock
private boolean mVrModeAllowed;
private boolean mVrModeEnabled;
+ private boolean mPersistentVrModeEnabled;
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
+ private ComponentName mDefaultVrService;
private Context mContext;
private ComponentName mCurrentVrModeComponent;
private int mCurrentVrModeUser;
@@ -138,7 +131,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
/** Tracks the state of the screen and keyguard UI.*/
private int mSystemSleepFlags = FLAG_NONE;
- private CompatibilityDisplay mCompatibilityDisplay;
private static final int MSG_VR_STATE_CHANGE = 0;
private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
@@ -159,6 +151,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (mVrModeAllowed) {
consumeAndApplyPendingStateLocked();
} else {
+ // Disable persistent mode when VR mode isn't allowed, allows an escape hatch to
+ // exit persistent VR mode when screen is turned off.
+ mPersistentVrModeEnabled = false;
+
// Set pending state to current state.
mPendingState = (mVrModeEnabled && mCurrentVrService != null)
? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
@@ -380,6 +376,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
@Override
+ public void setPersistentVrModeEnabled(boolean enabled) {
+ enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+ VrManagerService.this.setPersistentVrModeEnabled(enabled);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -389,6 +391,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
pw.println("********* Dump of VrManagerService *********");
pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
+ pw.println("Persistent VR mode is currently: " +
+ ((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
pw.println("Previous state transitions:\n");
String tab = " ";
dumpStateTransitions(pw);
@@ -464,6 +468,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC
public int hasVrPackage(ComponentName packageName, int userId) {
return VrManagerService.this.hasVrPackage(packageName, userId);
}
+
+ @Override
+ public void setPersistentVrModeEnabled(boolean enabled) {
+ VrManagerService.this.setPersistentVrModeEnabled(enabled);
+ }
}
public VrManagerService(Context context) {
@@ -497,10 +506,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mComponentObserver.rebuildAll();
}
- DisplayManager dm =
- (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
- mCompatibilityDisplay = new CompatibilityDisplay(dm, mVrManager);
- mCompatibilityDisplay.init();
+ //TODO: something more robust than picking the first one
+ ArraySet<ComponentName> defaultVrComponents =
+ SystemConfig.getInstance().getDefaultVrComponents();
+ if (defaultVrComponents.size() > 0) {
+ mDefaultVrService = defaultVrComponents.valueAt(0);
+ } else {
+ Slog.i(TAG, "No default vr listener service found.");
+ }
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
mVrModeAllowed = true;
@@ -644,8 +657,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
}
+ mCurrentVrModeComponent = calling;
if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
- mCurrentVrModeComponent = calling;
sendUpdatedCaller = true;
}
@@ -954,7 +967,25 @@ public class VrManagerService extends SystemService implements EnabledComponentC
int userId, @NonNull ComponentName callingPackage) {
synchronized (mLock) {
- VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
+ VrState pending;
+ ComponentName targetListener;
+ ComponentName foregroundVrComponent;
+
+ // If the device is in persistent VR mode, then calls to disable VR mode are ignored,
+ // and the system default VR listener is used.
+ boolean targetEnabledState = enabled || mPersistentVrModeEnabled;
+ if (!enabled && mPersistentVrModeEnabled) {
+ targetListener = mDefaultVrService;
+
+ // Current foreground component isn't a VR one (in 2D app case)
+ foregroundVrComponent = null;
+ } else {
+ targetListener = targetPackageName;
+ foregroundVrComponent = callingPackage;
+ }
+ pending = new VrState(
+ targetEnabledState, targetListener, userId, foregroundVrComponent);
+
if (!mVrModeAllowed) {
// We're not allowed to be in VR mode. Make this state pending. This will be
// applied the next time we are allowed to enter VR mode unless it is superseded by
@@ -963,7 +994,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return;
}
- if (!enabled && mCurrentVrService != null) {
+ if (!targetEnabledState && mCurrentVrService != null) {
// If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
// and service bind/unbind in case we are immediately switching to another VR app.
if (mPendingState == null) {
@@ -978,7 +1009,19 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mPendingState = null;
}
- updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
+ updateCurrentVrServiceLocked(
+ targetEnabledState, targetListener, userId, foregroundVrComponent);
+ }
+ }
+
+ private void setPersistentVrModeEnabled(boolean enabled) {
+ synchronized (mLock) {
+ mPersistentVrModeEnabled = enabled;
+
+ // Disabling persistent mode when not showing a VR should disable the overall vr mode.
+ if (!enabled && mCurrentVrModeComponent == null) {
+ setVrMode(false, null, 0, null);
+ }
}
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 4fd51b2274df..a0381f774c35 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -294,6 +294,11 @@ public class SystemImpl implements SystemInterface {
WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
}
+ @Override
+ public boolean isMultiProcessDefaultEnabled() {
+ return true;
+ }
+
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index b06f82971247..d57edcd4c44c 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -64,4 +64,5 @@ public interface SystemInterface {
public int getMultiProcessSetting(Context context);
public void setMultiProcessSetting(Context context, int value);
public void notifyZygote(boolean enableMultiProcess);
+ public boolean isMultiProcessDefaultEnabled();
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index f016830a2673..83e77ec3f9ae 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -240,12 +240,31 @@ public class WebViewUpdateServiceImpl {
}
boolean isMultiProcessEnabled() {
- return mSystemInterface.getMultiProcessSetting(mContext) != 0;
+ PackageInfo current = getCurrentWebViewPackage();
+ if (current == null) return false;
+ int currentVersion = current.versionCode;
+ int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
+ if (mSystemInterface.isMultiProcessDefaultEnabled()) {
+ // Multiprocess should be enabled unless the user has turned it off manually for this
+ // version or newer, as we want to re-enable it when it's updated to get fresh
+ // bug reports.
+ return settingValue > -currentVersion;
+ } else {
+ // Multiprocess should not be enabled, unless the user has turned it on manually for
+ // any version.
+ return settingValue > 0;
+ }
}
void enableMultiProcess(boolean enable) {
+ // The value we store for the setting is the version code of the current package, if it's
+ // enabled, or the negation of the version code of the current package, if it's disabled.
+ // Users who have a setting from before this scheme was implemented will have it set to 0 or
+ // 1 instead.
PackageInfo current = getCurrentWebViewPackage();
- mSystemInterface.setMultiProcessSetting(mContext, enable ? 1 : 0);
+ int currentVersion = current != null ? current.versionCode : 1;
+ mSystemInterface.setMultiProcessSetting(mContext,
+ enable ? currentVersion : -currentVersion);
mSystemInterface.notifyZygote(enable);
if (current != null) {
mSystemInterface.killPackageDependents(current.packageName);
@@ -611,6 +630,10 @@ public class WebViewUpdateServiceImpl {
*/
public boolean isValidProvider(WebViewProviderInfo configInfo,
PackageInfo packageInfo) {
+ // Ensure the provider targets this framework release (or a later one).
+ if (!UserPackage.hasCorrectTargetSdkVersion(packageInfo)) {
+ return false;
+ }
if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
&& !mSystemInterface.systemIsDebuggable()) {
// Webview providers may be downgraded arbitrarily low, prevent that by enforcing
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 49ffa22b53e3..f7a9e41ba706 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -369,6 +369,7 @@ final class AccessibilityController {
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_TOAST:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
@@ -687,7 +688,7 @@ final class AccessibilityController {
mSurfaceControl = surfaceControl;
mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
.getLayerStack());
- mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
+ mSurfaceControl.setLayer(mWindowManagerService.mPolicy.getWindowLayerFromTypeLw(
WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
* WindowManagerService.TYPE_LAYER_MULTIPLIER);
mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 915951381ac7..4eb8e0291d0c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -951,9 +951,9 @@ public class AppTransition implements Dump {
float scaleW = appWidth / thumbWidth;
getNextAppTransitionStartRect(taskId, mTmpRect);
final float fromX;
- final float fromY;
+ float fromY;
final float toX;
- final float toY;
+ float toY;
final float pivotX;
final float pivotY;
if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
@@ -966,6 +966,12 @@ public class AppTransition implements Dump {
toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
pivotX = mTmpRect.width() / 2;
pivotY = appRect.height() / 2 / scaleW;
+ if (mGridLayoutRecentsEnabled) {
+ // In the grid layout, the header is displayed above the thumbnail instead of
+ // overlapping it.
+ fromY -= thumbHeightI;
+ toY -= thumbHeightI * scaleW;
+ }
} else {
pivotX = 0;
pivotY = 0;
@@ -1014,7 +1020,10 @@ public class AppTransition implements Dump {
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
set.addAnimation(scale);
- set.addAnimation(alpha);
+ if (!mGridLayoutRecentsEnabled) {
+ // In the grid layout, the header should be shown for the whole animation.
+ set.addAnimation(alpha);
+ }
set.addAnimation(translate);
set.addAnimation(clipAnim);
a = set;
@@ -1033,7 +1042,10 @@ public class AppTransition implements Dump {
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
set.addAnimation(scale);
- set.addAnimation(alpha);
+ if (!mGridLayoutRecentsEnabled) {
+ // In the grid layout, the header should be shown for the whole animation.
+ set.addAnimation(alpha);
+ }
set.addAnimation(translate);
a = set;
@@ -1131,8 +1143,10 @@ public class AppTransition implements Dump {
// We scale the width and clip to the top/left square
float scale = thumbWidth /
(appWidth - contentInsets.left - contentInsets.right);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
+ if (!mGridLayoutRecentsEnabled) {
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
+ }
mNextAppTransitionInsets.set(contentInsets);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 27e0f292fb65..3a86874b1f4e 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -41,6 +41,7 @@ import android.util.Slog;
import android.view.IApplicationToken;
import android.view.WindowManagerPolicy.StartingSurface;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.AttributeCache;
/**
* Controller for the app window token container. This is created by activity manager to link
@@ -202,7 +203,7 @@ public class AppWindowContainerController
+ " controller=" + taskController);
}
- atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
+ atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);
@@ -212,6 +213,18 @@ public class AppWindowContainerController
}
}
+ @VisibleForTesting
+ AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
+ boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+ boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+ int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ boolean alwaysFocusable, AppWindowContainerController controller) {
+ return new AppWindowToken(service, token, voiceInteraction, dc,
+ inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
+ rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+ controller);
+ }
+
public void removeContainer(int displayId) {
synchronized(mWindowMap) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
@@ -230,6 +243,25 @@ public class AppWindowContainerController
throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
}
+ public void reparent(TaskWindowContainerController taskController, int position) {
+ synchronized (mWindowMap) {
+ if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
+ + " to task=" + taskController + " at " + position);
+ if (mContainer == null) {
+ if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
+ "reparent: could not find app token=" + mToken);
+ return;
+ }
+ final Task task = taskController.mContainer;
+ if (task == null) {
+ throw new IllegalArgumentException("reparent: could not find task="
+ + taskController);
+ }
+ mContainer.reparent(task, position);
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+ }
+
public Configuration setOrientation(int requestedOrientation, int displayId,
Configuration displayConfig, boolean freezeScreenIfNeeded) {
synchronized(mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 079dc8f2b0ad..061aa832086a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -192,7 +192,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
DisplayContent dc) {
- super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc);
+ super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
+ false /* ownerCanManageAppTokens */);
appToken = token;
mVoiceInteraction = voiceInteraction;
mInputApplicationHandle = new InputApplicationHandle(this);
@@ -850,6 +851,27 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
+ void reparent(Task task, int position) {
+ if (task == mTask) {
+ throw new IllegalArgumentException(
+ "window token=" + this + " already child of task=" + mTask);
+ }
+ if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
+ + " from task=" + mTask);
+ final DisplayContent prevDisplayContent = getDisplayContent();
+
+ getParent().removeChild(this);
+ task.addChild(this, position);
+
+ // Relayout display(s).
+ final DisplayContent displayContent = task.getDisplayContent();
+ displayContent.setLayoutNeeded();
+ if (prevDisplayContent != displayContent) {
+ onDisplayChanged(displayContent);
+ prevDisplayContent.setLayoutNeeded();
+ }
+ }
+
private boolean canFreezeBounds() {
// For freeform windows, we can't freeze the bounds at the moment because this would make
// the resizing unresponsive.
@@ -1130,10 +1152,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
*/
@Override
int getOrientation() {
- if (hidden || hiddenRequested) {
- return SCREEN_ORIENTATION_UNSET;
+ if (fillsParent() && (isVisible() || mService.mOpeningApps.contains(this))) {
+ return mOrientation;
}
- return mOrientation;
+
+ return SCREEN_ORIENTATION_UNSET;
}
/** Returns the app's preferred orientation regardless of its currently visibility state. */
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 2ec2dba88888..3a6e3280a161 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -322,6 +322,9 @@ class DimLayerController {
}
mState.remove(dimLayerUser);
}
+ if (mState.isEmpty()) {
+ mSharedFullScreenDimLayer = null;
+ }
}
@VisibleForTesting
@@ -329,6 +332,11 @@ class DimLayerController {
return mState.containsKey(dimLayerUser);
}
+ @VisibleForTesting
+ boolean hasSharedFullScreenDimLayer() {
+ return mSharedFullScreenDimLayer != null;
+ }
+
void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
applyDim(dimLayerUser, animator, false /* aboveApp */);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 914cc8de37ed..c45136ca2472 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -57,6 +57,7 @@ import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
@@ -69,6 +70,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
@@ -625,6 +627,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
};
/**
+ * Create new {@link DisplayContent} instance, add itself to the root window container and
+ * initialize direct children.
* @param display May not be null.
* @param service You know.
* @param layersController window layer controller used to assign layer to the windows on this
@@ -634,6 +638,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
DisplayContent(Display display, WindowManagerService service,
WindowLayersController layersController, WallpaperController wallpaperController) {
+
+ if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
+ throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
+ + " new=" + display);
+ }
+
mDisplay = display;
mDisplayId = display.getDisplayId();
mLayersController = layersController;
@@ -652,6 +663,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
super.addChild(mTaskStackContainers, null);
super.addChild(mAboveAppWindowsContainers, null);
super.addChild(mImeWindowsContainers, null);
+
+ // Add itself as a child to the root container.
+ mService.mRoot.addChild(this, null);
}
int getDisplayId() {
@@ -957,75 +971,43 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
out.set(mContentRect);
}
- /**
- * Adds the stack to this display.
- * @see WindowManagerService#addStackToDisplay(int, int, boolean)
- */
- Rect addStackToDisplay(int stackId, boolean onTop) {
- boolean attachedToDisplay = false;
- TaskStack stack = mService.mStackIdToStack.get(stackId);
- if (stack == null) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
- + mDisplayId);
-
- stack = getStackById(stackId);
- if (stack != null) {
- // It's already attached to the display...clear mDeferRemoval and move stack to
- // appropriate z-order on display as needed.
- stack.mDeferRemoval = false;
- // We're not moving the display to front when we're adding stacks, only when
- // requested to change the position of stack explicitly.
- mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
- false /* includingParents */);
- attachedToDisplay = true;
- } else {
- stack = new TaskStack(mService, stackId);
- }
+ TaskStack addStackToDisplay(int stackId, boolean onTop) {
+ if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
+ + mDisplayId);
- mService.mStackIdToStack.put(stackId, stack);
- if (stackId == DOCKED_STACK_ID) {
- mDividerControllerLocked.notifyDockedStackExistsChanged(true);
- }
+ TaskStack stack = getStackById(stackId);
+ if (stack != null) {
+ // It's already attached to the display...clear mDeferRemoval and move stack to
+ // appropriate z-order on display as needed.
+ stack.mDeferRemoval = false;
+ // We're not moving the display to front when we're adding stacks, only when
+ // requested to change the position of stack explicitly.
+ mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
+ false /* includingParents */);
} else {
- final DisplayContent currentDC = stack.getDisplayContent();
- if (currentDC != null) {
- throw new IllegalStateException("Trying to add stackId=" + stackId
- + "to displayId=" + mDisplayId + ", but it's already attached to displayId="
- + currentDC.getDisplayId());
- }
- }
-
- if (!attachedToDisplay) {
+ stack = new TaskStack(mService, stackId);
mTaskStackContainers.addStackToDisplay(stack, onTop);
}
- if (stack.getRawFullscreen()) {
- return null;
+ if (stackId == DOCKED_STACK_ID) {
+ mDividerControllerLocked.notifyDockedStackExistsChanged(true);
}
- final Rect bounds = new Rect();
- stack.getRawBounds(bounds);
- return bounds;
+ return stack;
}
- /** Removes the stack from the display and prepares for changing the parent. */
- private void removeStackFromDisplay(TaskStack stack) {
- mTaskStackContainers.removeStackFromDisplay(stack);
- }
-
- /** Moves the stack to this display and returns the updated bounds. */
- Rect moveStackToDisplay(TaskStack stack) {
- final DisplayContent currentDisplayContent = stack.getDisplayContent();
- if (currentDisplayContent == null) {
+ void moveStackToDisplay(TaskStack stack) {
+ final DisplayContent prevDc = stack.getDisplayContent();
+ if (prevDc == null) {
throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
+ " which is not currently attached to any display");
}
- if (stack.getDisplayContent().getDisplayId() == mDisplayId) {
+ if (prevDc.getDisplayId() == mDisplayId) {
throw new IllegalArgumentException("Trying to move stackId=" + stack.mStackId
+ " to its current displayId=" + mDisplayId);
}
- currentDisplayContent.removeStackFromDisplay(stack);
- return addStackToDisplay(stack.mStackId, true /* onTop */);
+ prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
+ mTaskStackContainers.addStackToDisplay(stack, true /* onTop */);
}
@Override
@@ -1172,7 +1154,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
super.removeImmediately();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
mDimLayerController.close();
- if (mDisplayId == DEFAULT_DISPLAY) {
+ if (mDisplayId == DEFAULT_DISPLAY && mService.canDispatchPointerEvents()) {
mService.unregisterPointerEventListener(mTapDetector);
mService.unregisterPointerEventListener(mService.mMousePositionTracker);
}
@@ -1250,7 +1232,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final WindowState imeWin = mService.mInputMethodWindow;
final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
&& !mDividerControllerLocked.isImeHideRequested();
- final boolean dockVisible = mService.isStackVisibleLocked(DOCKED_STACK_ID);
+ final boolean dockVisible = isStackVisible(DOCKED_STACK_ID);
final TaskStack imeTargetStack = mService.getImeFocusStackLocked();
final int imeDockSide = (dockVisible && imeTargetStack != null) ?
imeTargetStack.getDockSide() : DOCKED_INVALID;
@@ -1447,7 +1429,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @return The docked stack, but only if it is visible, and {@code null} otherwise.
*/
TaskStack getDockedStackLocked() {
- final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ final TaskStack stack = getStackById(DOCKED_STACK_ID);
return (stack != null && stack.isVisible()) ? stack : null;
}
@@ -1456,7 +1438,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* visible.
*/
TaskStack getDockedStackIgnoringVisibility() {
- return mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ return getStackById(DOCKED_STACK_ID);
}
/** Find the visible, touch-deliverable window under the given point */
@@ -1532,6 +1514,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ // TODO: This should probably be called any time a visual change is made to the hierarchy like
+ // moving containers or resizing them. Need to investigate the best way to have it automatically
+ // happen so we don't run into issues with programmers forgetting to do it.
void layoutAndAssignWindowLayersIfNeeded() {
mService.mWindowsChanged = true;
setLayoutNeeded();
@@ -2200,7 +2185,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
&& !mService.mInputMethodTarget.isInMultiWindowMode();
}
- final int aboveAppLayer = (mService.mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1)
+ final int aboveAppLayer = (mService.mPolicy.getWindowLayerFromTypeLw(TYPE_APPLICATION) + 1)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
synchronized(mService.mWindowMap) {
@@ -2441,6 +2426,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ void setExitingTokensHasVisible(boolean hasVisible) {
+ for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
+ mExitingTokens.get(i).hasVisible = hasVisible;
+ }
+
+ // Initialize state of exiting applications.
+ mTaskStackContainers.setExitingTokensHasVisible(hasVisible);
+ }
+
+ void removeExistingTokensIfPossible() {
+ for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
+ final WindowToken token = mExitingTokens.get(i);
+ if (!token.hasVisible) {
+ mExitingTokens.remove(i);
+ }
+ }
+
+ // Time to remove any exiting applications?
+ mTaskStackContainers.removeExistingAppTokensIfPossible();
+ }
+
static final class TaskForResizePointSearchResult {
boolean searchDone;
Task taskForResize;
@@ -2650,10 +2656,38 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return false;
}
+ void setExitingTokensHasVisible(boolean hasVisible) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+ for (int j = appTokens.size() - 1; j >= 0; --j) {
+ appTokens.get(j).hasVisible = hasVisible;
+ }
+ }
+ }
+
+ void removeExistingAppTokensIfPossible() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+ for (int j = appTokens.size() - 1; j >= 0; --j) {
+ final AppWindowToken token = appTokens.get(j);
+ if (!token.hasVisible && !mService.mClosingApps.contains(token)
+ && (!token.mIsExiting || token.isEmpty())) {
+ // Make sure there is no animation running on this token, so any windows
+ // associated with it will be removed as soon as their animations are
+ // complete.
+ token.mAppAnimator.clearAnimation();
+ token.mAppAnimator.animating = false;
+ if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
+ "performLayout: App token exiting now removed" + token);
+ token.removeIfPossible();
+ }
+ }
+ }
+ }
+
@Override
int getOrientation() {
- if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
- || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
+ if (isStackVisible(DOCKED_STACK_ID) || isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) {
// Apps and their containers are not allowed to specify an orientation while the
// docked or freeform stack is visible...except for the home stack/task if the
// docked stack is minimized and it actually set something.
@@ -2694,8 +2728,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
private final Comparator<WindowToken> mWindowComparator = (token1, token2) ->
// Tokens with higher base layer are z-ordered on-top.
- mService.mPolicy.windowTypeToLayerLw(token1.windowType)
- < mService.mPolicy.windowTypeToLayerLw(token2.windowType) ? -1 : 1;
+ mService.mPolicy.getWindowLayerFromTypeLw(token1.windowType,
+ token1.mOwnerCanManageAppTokens)
+ < mService.mPolicy.getWindowLayerFromTypeLw(token2.windowType,
+ token2.mOwnerCanManageAppTokens) ? -1 : 1;
private final Predicate<WindowState> mGetOrientingWindow = w -> {
if (!w.isVisibleLw() || !w.mPolicyVisibilityAfterAnim) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ed1e2d998d63..0a92a8198a52 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -102,12 +102,14 @@ public class DockedStackDividerController implements DimLayerUser {
private int mDividerWindowWidth;
private int mDividerWindowWidthInactive;
private int mDividerInsets;
+ private int mTaskHeightInMinimizedMode;
private boolean mResizing;
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
private final Rect mTmpRect3 = new Rect();
private final Rect mLastRect = new Rect();
+ private final Rect mMiddlePositionDockedStackRect = new Rect();
private boolean mLastVisibility = false;
private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
= new RemoteCallbackList<>();
@@ -189,6 +191,40 @@ public class DockedStackDividerController implements DimLayerUser {
return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
}
+ /**
+ * The middlePositionDockedStackRect is half the screen area that sits at the top (portrait) or
+ * left (landscape).
+ *
+ * @return fixed rect for temp stack
+ */
+ Rect getMiddlePositionDockedStackRect() {
+ return mMinimizedDock && isHomeStackResizable() ? mMiddlePositionDockedStackRect : null;
+ }
+
+ void getHomeStackBoundsInDockedMode(Rect outBounds) {
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ mTmpRect);
+ int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
+ Configuration configuration = mDisplayContent.getConfiguration();
+ if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
+ di.logicalWidth, di.logicalHeight);
+ } else {
+ outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left, 0,
+ di.logicalWidth, di.logicalHeight);
+ }
+ }
+
+ boolean isHomeStackResizable() {
+ final TaskStack homeStack = mDisplayContent.getHomeStack();
+ if (homeStack == null) {
+ return false;
+ }
+ final Task homeTask = homeStack.findHomeTask();
+ return homeTask != null && homeTask.isResizeable();
+ }
+
private void initSnapAlgorithmForRotations() {
final Configuration baseConfig = mDisplayContent.getConfiguration();
@@ -228,11 +264,34 @@ public class DockedStackDividerController implements DimLayerUser {
com.android.internal.R.dimen.docked_stack_divider_insets);
mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
+ mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.task_height_of_minimized_mode);
initSnapAlgorithmForRotations();
}
+ /**
+ * Calculates the constant rects {@link mMiddlePositionDockedStackRect} based on orientation,
+ * stable insets and display size.
+ */
+ private void updateConstantRects() {
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ mTmpRect);
+ int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
+ Configuration configuration = mDisplayContent.getConfiguration();
+ boolean isHorizontal = configuration.orientation == Configuration.ORIENTATION_PORTRAIT;
+ int middlePosition = DockedDividerUtils.calculateMiddlePosition(isHorizontal, mTmpRect,
+ di.logicalWidth, di.logicalHeight, dividerSize);
+ if (isHorizontal) {
+ mMiddlePositionDockedStackRect.set(0, 0, di.logicalWidth, middlePosition);
+ } else {
+ mMiddlePositionDockedStackRect.set(0, 0, middlePosition, di.logicalHeight);
+ }
+ }
+
void onConfigurationChanged() {
loadDimens();
+ updateConstantRects();
}
boolean isResizing() {
@@ -412,7 +471,19 @@ public class DockedStackDividerController implements DimLayerUser {
return mImeHideRequested;
}
- private void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
+ private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
+ boolean isHomeStackResizable) {
+ long animDuration = 0;
+ if (animate) {
+ final TaskStack stack = mDisplayContent.getStackById(DOCKED_STACK_ID);
+ final long transitionDuration = isAnimationMaximizing()
+ ? mService.mAppTransition.getLastClipRevealTransitionDuration()
+ : DEFAULT_APP_TRANSITION_DURATION;
+ mAnimationDuration = (long)
+ (transitionDuration * mService.getTransitionAnimationScaleLocked());
+ mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
+ animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
+ }
mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
minimizedDock ? 1 : 0, 0).sendToTarget();
@@ -420,7 +491,8 @@ public class DockedStackDividerController implements DimLayerUser {
for (int i = 0; i < size; ++i) {
final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
try {
- listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
+ listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
+ isHomeStackResizable);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
}
@@ -457,16 +529,16 @@ public class DockedStackDividerController implements DimLayerUser {
void registerDockedStackListener(IDockedStackListener listener) {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
- notifyDockedStackExistsChanged(
- mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
- notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
+ notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null);
+ notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
+ isHomeStackResizable());
notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
}
void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
mService.openSurfaceTransaction();
- final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+ final TaskStack stack = mDisplayContent.getStackById(targetStackId);
final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
boolean visibleAndValid = visible && stack != null && dockedStack != null;
if (visibleAndValid) {
@@ -544,16 +616,12 @@ public class DockedStackDividerController implements DimLayerUser {
if (homeTask == null || !isWithinDisplay(homeTask)) {
return;
}
- final TaskStack fullscreenStack
- = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
+ final TaskStack fullscreenStack =
+ mDisplayContent.getStackById(FULLSCREEN_WORKSPACE_STACK_ID);
final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
|| (homeStack.hasMultipleTaskWithHomeTaskNotTop());
- // If the home task is an on-top launcher, we don't want to minimize the docked stack.
- // Instead we want everything underneath that was visible to remain visible.
- // See android.R.attr#onTopLauncher.
- final boolean isOnTopLauncher = homeStack.topTaskIsOnTopLauncher();
- setMinimizedDockedStack(homeVisible && !homeBehind && !isOnTopLauncher, animate);
+ setMinimizedDockedStack(homeVisible && !homeBehind, animate);
}
private boolean isWithinDisplay(Task task) {
@@ -578,17 +646,23 @@ public class DockedStackDividerController implements DimLayerUser {
final boolean imeChanged = clearImeAdjustAnimation();
boolean minimizedChange = false;
- if (minimizedDock) {
- if (animate) {
- startAdjustAnimation(0f, 1f);
- } else {
- minimizedChange |= setMinimizedDockedStack(true);
- }
+ if (isHomeStackResizable()) {
+ notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
+ true /* isHomeStackResizable */);
+ minimizedChange = true;
} else {
- if (animate) {
- startAdjustAnimation(1f, 0f);
+ if (minimizedDock) {
+ if (animate) {
+ startAdjustAnimation(0f, 1f);
+ } else {
+ minimizedChange |= setMinimizedDockedStack(true);
+ }
} else {
- minimizedChange |= setMinimizedDockedStack(false);
+ if (animate) {
+ startAdjustAnimation(1f, 0f);
+ } else {
+ minimizedChange |= setMinimizedDockedStack(false);
+ }
}
}
if (imeChanged || minimizedChange) {
@@ -689,7 +763,7 @@ public class DockedStackDividerController implements DimLayerUser {
private boolean setMinimizedDockedStack(boolean minimized) {
final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
- notifyDockedStackMinimizedChanged(minimized, 0);
+ notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
}
@@ -739,18 +813,12 @@ public class DockedStackDividerController implements DimLayerUser {
}
private boolean animateForMinimizedDockedStack(long now) {
- final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ final TaskStack stack = mDisplayContent.getStackById(DOCKED_STACK_ID);
if (!mAnimationStarted) {
mAnimationStarted = true;
mAnimationStartTime = now;
- final long transitionDuration = isAnimationMaximizing()
- ? mService.mAppTransition.getLastClipRevealTransitionDuration()
- : DEFAULT_APP_TRANSITION_DURATION;
- mAnimationDuration = (long)
- (transitionDuration * mService.getTransitionAnimationScaleLocked());
- mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
- notifyDockedStackMinimizedChanged(mMinimizedDock,
- (long) (mAnimationDuration * mMaximizeMeetFraction));
+ notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
+ isHomeStackResizable() /* isHomeStackResizable */);
}
float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 36520a9642a1..3fdafc7bebdf 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -148,7 +148,7 @@ class DragState {
mDragApplicationHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null,
display.getDisplayId());
mDragWindowHandle.name = "drag";
mDragWindowHandle.inputChannel = mServerChannel;
@@ -239,7 +239,7 @@ class DragState {
}
int getDragLayerLw() {
- return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
+ return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 24783bccf3d5..36753b7d5e04 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -48,7 +48,8 @@ class InputConsumerImpl {
mApplicationHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- mWindowHandle = new InputWindowHandle(mApplicationHandle, null, Display.DEFAULT_DISPLAY);
+ mWindowHandle = new InputWindowHandle(mApplicationHandle, null, null,
+ Display.DEFAULT_DISPLAY);
mWindowHandle.name = name;
mWindowHandle.inputChannel = mServerChannel;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
@@ -76,7 +77,7 @@ class InputConsumerImpl {
}
private int getLayerLw(int windowType) {
- return mService.mPolicy.windowTypeToLayerLw(windowType)
+ return mService.mPolicy.getWindowLayerFromTypeLw(windowType)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index f754775e286a..37b8deb0a24f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -77,6 +78,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
// Array of window handles to provide to the input dispatcher.
private InputWindowHandle[] mInputWindowHandles;
private int mInputWindowHandleCount;
+ private InputWindowHandle mFocusedInputWindowHandle;
+
private boolean mAddInputConsumerHandle;
private boolean mAddPipInputConsumerHandle;
private boolean mAddWallpaperInputConsumerHandle;
@@ -235,8 +238,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
// Figure out whether this window is layered above system windows.
// We need to do this here to help the activity manager know how to
// layer its ANR dialog.
- int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw(
- WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw(
+ TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow);
aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(TAG_WM, "Input event dispatching timed out "
@@ -327,12 +330,16 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
+ child + ", " + inputWindowHandle);
}
addInputWindowHandle(inputWindowHandle);
+ if (hasFocus) {
+ mFocusedInputWindowHandle = inputWindowHandle;
+ }
}
private void clearInputWindowHandlesLw() {
while (mInputWindowHandleCount != 0) {
mInputWindowHandles[--mInputWindowHandleCount] = null;
}
+ mFocusedInputWindowHandle = null;
}
void setUpdateInputWindowsNeededLw() {
@@ -465,7 +472,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
/* Callback to get pointer layer. */
@Override
public int getPointerLayer() {
- return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_POINTER)
+ return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
@@ -609,7 +616,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
}
// Send windows to native code.
- mService.mInputManager.setInputWindows(mInputWindowHandles);
+ mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
clearInputWindowHandlesLw();
}
@@ -619,7 +626,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
final InputChannel inputChannel = w.mInputChannel;
final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
- || w.isAdjustedForMinimizedDock()) {
+ || w.canReceiveTouchInput()) {
// Skip this window because it cannot possibly receive input.
return;
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 08f9b4585e98..a872ea4602bb 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -22,7 +22,6 @@ import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.animation.ValueAnimator;
import android.app.RemoteAction;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
@@ -42,7 +41,6 @@ import android.view.Gravity;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
-import com.android.internal.policy.PipMotionHelper;
import com.android.internal.policy.PipSnapAlgorithm;
import com.android.server.UiThread;
@@ -51,7 +49,20 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Holds the common state of the pinned stack between the system and SystemUI.
+ * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
+ * needs to be restarted, it will be notified with the last known state.
+ *
+ * Changes to the pinned stack also flow through this controller, and generally, the system only
+ * changes the pinned stack bounds through this controller in two ways:
+ *
+ * 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
+ * and IME state into account.
+ * 2) When rotating the device: the controller calculates the new bounds in the new orientation,
+ * taking the minimized and IME state into account. In this case, we currently ignore the
+ * SystemUI adjustments (ie. expanded for menu, interaction, etc).
+ *
+ * Other changes in the system, including adjustment of IME, configuration change, and more are
+ * handled by SystemUI (similar to the docked stack divider).
*/
class PinnedStackController {
@@ -67,18 +78,15 @@ class PinnedStackController {
private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
private final PipSnapAlgorithm mSnapAlgorithm;
- private final PipMotionHelper mMotionHelper;
// States that affect how the PIP can be manipulated
- private boolean mInInteractiveMode;
private boolean mIsMinimized;
- private boolean mIsSnappingToEdge;
private boolean mIsImeShowing;
private int mImeHeight;
- private ValueAnimator mBoundsAnimator = null;
- // The set of actions that are currently allowed on the PiP activity
+ // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
private ArrayList<RemoteAction> mActions = new ArrayList<>();
+ private float mAspectRatio = -1f;
// Used to calculate stack bounds across rotations
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -89,6 +97,10 @@ class PinnedStackController {
private Size mDefaultStackSize;
private Point mScreenEdgeInsets;
+ // The aspect ratio bounds of the PIP.
+ private float mMinAspectRatio;
+ private float mMaxAspectRatio;
+
// Temp vars for calculation
private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
private final Rect mTmpInsets = new Rect();
@@ -100,28 +112,10 @@ class PinnedStackController {
private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
@Override
- public void setInInteractiveMode(final boolean inInteractiveMode) {
- mHandler.post(() -> {
- // Cancel any existing animations on the PIP once the user starts dragging it
- if (mBoundsAnimator != null && inInteractiveMode) {
- mBoundsAnimator.cancel();
- }
- mInInteractiveMode = inInteractiveMode;
- });
- }
-
- @Override
public void setIsMinimized(final boolean isMinimized) {
mHandler.post(() -> {
mIsMinimized = isMinimized;
- });
- }
-
- @Override
- public void setSnapToEdge(final boolean snapToEdge) {
- mHandler.post(() -> {
- mIsSnappingToEdge = snapToEdge;
- mSnapAlgorithm.setSnapToEdge(snapToEdge);
+ mSnapAlgorithm.setMinimized(isMinimized);
});
}
}
@@ -134,7 +128,6 @@ class PinnedStackController {
@Override
public void binderDied() {
// Clean up the state if the listener dies
- mInInteractiveMode = false;
mPinnedStackListener = null;
}
}
@@ -143,13 +136,13 @@ class PinnedStackController {
mService = service;
mDisplayContent = displayContent;
mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
- mMotionHelper = new PipMotionHelper(UiThread.getHandler());
mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
reloadResources();
}
void onConfigurationChanged() {
reloadResources();
+ notifyMovementBoundsChanged(false /* fromImeAdjustment */);
}
/**
@@ -168,6 +161,10 @@ class PinnedStackController {
dpToPx(defaultSizeDp.getHeight(), mTmpMetrics));
mScreenEdgeInsets = new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
+ mMinAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+ mMaxAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
}
/**
@@ -178,20 +175,29 @@ class PinnedStackController {
listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
listener.onListenerRegistered(mCallbacks);
mPinnedStackListener = listener;
- notifyBoundsChanged(mIsImeShowing);
- notifyMinimizeChanged(mIsMinimized);
- notifySnapToEdgeChanged(mIsSnappingToEdge);
+ notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
+ // The movement bounds notification needs to be sent before the minimized state, since
+ // SystemUI may use the bounds to retore the minimized position
+ notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyActionsChanged(mActions);
+ notifyMinimizeChanged(mIsMinimized);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
}
/**
+ * @return whether the given {@param aspectRatio} is valid.
+ */
+ public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
+ return mMinAspectRatio <= aspectRatio && aspectRatio <= mMaxAspectRatio;
+ }
+
+ /**
* Returns the current bounds (or the default bounds if there are no current bounds) with the
* specified aspect ratio.
*/
- Rect getAspectRatioBounds(Rect stackBounds, float aspectRatio) {
+ Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio) {
// Save the snap fraction, calculate the aspect ratio based on the current bounds
final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
getMovementBounds(stackBounds));
@@ -235,27 +241,20 @@ class PinnedStackController {
final Rect movementBounds = new Rect();
getInsetBounds(movementBounds);
- // Adjust the right/bottom to ensure the stack bounds never goes offscreen
- movementBounds.right = Math.max(movementBounds.left, movementBounds.right -
- stackBounds.width());
- movementBounds.bottom = Math.max(movementBounds.top, movementBounds.bottom -
- stackBounds.height());
-
// Apply the movement bounds adjustments based on the current state
- if (adjustForIme) {
- if (mIsImeShowing) {
- movementBounds.bottom -= mImeHeight;
- }
- }
+ mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
+ (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
return movementBounds;
}
/**
+ * @param preChangeTargetBounds The final bounds of the stack if it is currently animating
* @return the repositioned PIP bounds given it's pre-change bounds, and the new display
* content.
*/
- Rect onDisplayChanged(Rect preChangeStackBounds, DisplayContent displayContent) {
- final Rect postChangeStackBounds = new Rect(preChangeStackBounds);
+ Rect onDisplayChanged(Rect preChangeStackBounds, Rect preChangeTargetBounds,
+ DisplayContent displayContent) {
+ final Rect postChangeStackBounds = new Rect(preChangeTargetBounds);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (!mDisplayInfo.equals(displayInfo)) {
// Calculate the snap fraction of the current stack along the old movement bounds, and
@@ -276,6 +275,7 @@ class PinnedStackController {
mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds,
displaySize, mStableInsets);
}
+ notifyMovementBoundsChanged(false /* fromImeAdjustment */);
}
return postChangeStackBounds;
}
@@ -289,42 +289,19 @@ class PinnedStackController {
return;
}
- final Rect stackBounds = new Rect();
- mService.getStackBounds(PINNED_STACK_ID, stackBounds);
- final Rect prevMovementBounds = getMovementBounds(stackBounds);
mIsImeShowing = adjustedForIme;
mImeHeight = imeHeight;
- if (mInInteractiveMode) {
- // If the user is currently interacting with the PIP and the ime state changes, then
- // don't adjust the bounds and defer that to after the interaction
- notifyBoundsChanged(adjustedForIme /* adjustedForIme */);
- } else {
- // Otherwise, we can move the PIP to a sane location to ensure that it does not block
- // the user from interacting with the IME
- final Rect movementBounds = getMovementBounds(stackBounds);
- final Rect toBounds = new Rect(stackBounds);
- if (adjustedForIme) {
- // IME visible
- if (stackBounds.top == prevMovementBounds.bottom) {
- // If the PIP is resting on top of the IME, then adjust it with the hiding IME
- toBounds.offsetTo(toBounds.left, movementBounds.bottom);
- } else {
- toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
- }
- } else {
- // IME hidden
- if (stackBounds.top == prevMovementBounds.bottom) {
- // If the PIP is resting on top of the IME, then adjust it with the hiding IME
- toBounds.offsetTo(toBounds.left, movementBounds.bottom);
- }
- }
- if (!toBounds.equals(stackBounds)) {
- if (mBoundsAnimator != null) {
- mBoundsAnimator.cancel();
- }
- mBoundsAnimator = mMotionHelper.createAnimationToBounds(stackBounds, toBounds);
- mBoundsAnimator.start();
- }
+ notifyImeVisibilityChanged(adjustedForIme, imeHeight);
+ notifyMovementBoundsChanged(true /* fromImeAdjustment */);
+ }
+
+ /**
+ * Sets the current aspect ratio.
+ */
+ void setAspectRatio(float aspectRatio) {
+ if (Float.compare(mAspectRatio, aspectRatio) != 0) {
+ mAspectRatio = aspectRatio;
+ notifyMovementBoundsChanged(false /* fromImeAdjustment */);
}
}
@@ -340,12 +317,12 @@ class PinnedStackController {
}
/**
- * Notifies listeners that the PIP movement bounds have changed.
+ * Notifies listeners that the PIP needs to be adjusted for the IME.
*/
- private void notifyBoundsChanged(boolean adjustedForIme) {
+ private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
if (mPinnedStackListener != null) {
try {
- mPinnedStackListener.onBoundsChanged(adjustedForIme);
+ mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
}
@@ -366,25 +343,32 @@ class PinnedStackController {
}
/**
- * Notifies listeners that the PIP snap-to-edge state has changed.
+ * Notifies listeners that the PIP actions have changed.
*/
- private void notifySnapToEdgeChanged(boolean isSnappingToEdge) {
+ private void notifyActionsChanged(List<RemoteAction> actions) {
if (mPinnedStackListener != null) {
try {
- mPinnedStackListener.onSnapToEdgeStateChanged(isSnappingToEdge);
+ mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
} catch (RemoteException e) {
- Slog.e(TAG_WM, "Error delivering snap-to-edge changed event.", e);
+ Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
}
}
/**
- * Notifies listeners that the PIP actions have changed.
+ * Notifies listeners that the PIP movement bounds have changed.
*/
- private void notifyActionsChanged(List<RemoteAction> actions) {
+ private void notifyMovementBoundsChanged(boolean fromImeAdjustement) {
if (mPinnedStackListener != null) {
try {
- mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
+ Rect insetBounds = new Rect();
+ getInsetBounds(insetBounds);
+ Rect normalBounds = getDefaultBounds();
+ if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
+ transformBoundsToAspectRatio(normalBounds, mAspectRatio);
+ }
+ mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
+ fromImeAdjustement);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
@@ -417,7 +401,6 @@ class PinnedStackController {
pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
pw.println();
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
- pw.println(prefix + " mInInteractiveMode=" + mInInteractiveMode);
pw.println(prefix + " mIsMinimized=" + mIsMinimized);
if (mActions.isEmpty()) {
pw.println(prefix + " mActions=[]");
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 0cc6c701a93e..80e6655545aa 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -213,7 +213,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
final int displayId = display.getDisplayId();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
- addChild(dc, null);
final DisplayInfo displayInfo = dc.getDisplayInfo();
final Rect rect = new Rect();
@@ -382,6 +381,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
}
}
+ TaskStack getStackById(int stackId) {
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final DisplayContent dc = mChildren.get(i);
+ final TaskStack stack = dc.getStackById(stackId);
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
void setSecureSurfaceState(int userId, boolean disabled) {
forAllWindows((w) -> {
if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) {
@@ -535,18 +545,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
- for (i = displayContent.mExitingTokens.size() - 1; i >= 0; i--) {
- displayContent.mExitingTokens.get(i).hasVisible = false;
- }
- }
-
- for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
- // Initialize state of exiting applications.
- final AppTokenList exitingAppTokens =
- mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
- for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
- exitingAppTokens.get(tokenNdx).hasVisible = false;
- }
+ displayContent.setExitingTokensHasVisible(false);
}
mHoldScreen = null;
@@ -681,33 +680,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// Time to remove any exiting tokens?
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
- ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
- for (i = exitingTokens.size() - 1; i >= 0; i--) {
- WindowToken token = exitingTokens.get(i);
- if (!token.hasVisible) {
- exitingTokens.remove(i);
- }
- }
- }
-
- // Time to remove any exiting applications?
- for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
- // Initialize state of exiting applications.
- final AppTokenList exitingAppTokens =
- mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
- for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
- final AppWindowToken token = exitingAppTokens.get(i);
- if (!token.hasVisible && !mService.mClosingApps.contains(token) &&
- (!token.mIsExiting || token.isEmpty())) {
- // Make sure there is no animation running on this token, so any windows
- // associated with it will be removed as soon as their animations are complete
- token.mAppAnimator.clearAnimation();
- token.mAppAnimator.animating = false;
- if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
- "performLayout: App token exiting now removed" + token);
- token.removeIfPossible();
- }
- }
+ displayContent.removeExistingTokensIfPossible();
}
if (wallpaperDestroyed) {
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
new file mode 100644
index 000000000000..36d07e01e5c1
--- /dev/null
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.app.RemoteAction;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.server.UiThread;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+/**
+ * Controller for the stack container. This is created by activity manager to link activity stacks
+ * to the stack container they use in window manager.
+ *
+ * Test class: {@link StackWindowControllerTests}
+ */
+public class StackWindowController
+ extends WindowContainerController<TaskStack, StackWindowListener> {
+
+ final int mStackId;
+
+ private final H mHandler;
+
+ public StackWindowController(int stackId, StackWindowListener listener,
+ int displayId, boolean onTop, Rect outBounds) {
+ this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
+ }
+
+ @VisibleForTesting
+ public StackWindowController(int stackId, StackWindowListener listener,
+ int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
+ super(listener, service);
+ mStackId = stackId;
+ mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
+
+ synchronized (mWindowMap) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ throw new IllegalArgumentException("Trying to add stackId=" + stackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ final TaskStack stack = dc.addStackToDisplay(stackId, onTop);
+ stack.setController(this);
+ getRawBounds(outBounds);
+ }
+ }
+
+ @Override
+ public void removeContainer() {
+ synchronized (mWindowMap) {
+ if (mContainer != null) {
+ mContainer.removeIfPossible();
+ super.removeContainer();
+ }
+ }
+ }
+
+ public void reparent(int displayId, Rect outStackBounds) {
+ synchronized (mWindowMap) {
+ if (mContainer == null) {
+ throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
+ + " to displayId=" + displayId);
+ }
+
+ final DisplayContent targetDc = mRoot.getDisplayContent(displayId);
+ if (targetDc == null) {
+ throw new IllegalArgumentException("Trying to move stackId=" + mStackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ targetDc.moveStackToDisplay(mContainer);
+ getRawBounds(outStackBounds);
+ }
+ }
+
+ public void positionChildAt(TaskWindowContainerController child, int position, Rect bounds,
+ Configuration overrideConfig) {
+ synchronized (mWindowMap) {
+ if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning task=" + child
+ + " at " + position);
+ if (child.mContainer == null) {
+ if (DEBUG_STACK) Slog.i(TAG_WM,
+ "positionChildAt: could not find task=" + this);
+ return;
+ }
+ if (mContainer == null) {
+ if (DEBUG_STACK) Slog.i(TAG_WM,
+ "positionChildAt: could not find stack for task=" + mContainer);
+ return;
+ }
+ child.mContainer.positionAt(position, bounds, overrideConfig);
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+ }
+
+ public void positionChildAtTop(TaskWindowContainerController child, boolean includingParents) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ synchronized(mWindowMap) {
+ final Task childTask = child.mContainer;
+ if (childTask == null) {
+ Slog.e(TAG_WM, "positionChildAtTop: task=" + child + " not found");
+ return;
+ }
+ mContainer.positionChildAt(POSITION_TOP, childTask, includingParents);
+
+ if (mService.mAppTransition.isTransitionSet()) {
+ childTask.setSendingToBottom(false);
+ }
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+ }
+
+ public void positionChildAtBottom(TaskWindowContainerController child) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ synchronized(mWindowMap) {
+ final Task childTask = child.mContainer;
+ if (childTask == null) {
+ Slog.e(TAG_WM, "positionChildAtBottom: task=" + child + " not found");
+ return;
+ }
+ mContainer.positionChildAt(POSITION_BOTTOM, childTask, false /* includingParents */);
+
+ if (mService.mAppTransition.isTransitionSet()) {
+ childTask.setSendingToBottom(true);
+ }
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+ }
+
+ /**
+ * Re-sizes a stack and its containing tasks.
+ *
+ * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param configs Configurations for tasks in the resized stack, keyed by task id.
+ * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
+ * @return True if the stack is now fullscreen.
+ */
+ public boolean resize(Rect bounds, SparseArray<Configuration> configs,
+ SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) {
+ synchronized (mWindowMap) {
+ if (mContainer == null) {
+ throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
+ }
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ mContainer.prepareFreezingTaskBounds();
+ if (mContainer.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+ && mContainer.isVisible()) {
+ mContainer.getDisplayContent().setLayoutNeeded();
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ return mContainer.getRawFullscreen();
+ }
+ }
+
+ // TODO: This and similar methods should be separated into PinnedStackWindowContainerController
+ public void animateResizePinnedStack(final Rect bounds, final int animationDuration) {
+ synchronized (mWindowMap) {
+ if (mContainer == null) {
+ throw new IllegalArgumentException("Pinned stack container not found :(");
+ }
+ final Rect originalBounds = new Rect();
+ mContainer.getBounds(originalBounds);
+ mContainer.setAnimatingBounds(bounds);
+ UiThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mService.mBoundsAnimationController.animateBounds(
+ mContainer, originalBounds, bounds, animationDuration);
+ }
+ });
+ }
+ }
+
+ /** Sets the current picture-in-picture aspect ratio. */
+ public void setPictureInPictureAspectRatio(float aspectRatio) {
+ synchronized (mWindowMap) {
+ if (!mService.mSupportsPictureInPicture || mContainer == null) {
+ return;
+ }
+
+ final int displayId = mContainer.getDisplayContent().getDisplayId();
+ final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
+ final Rect targetBounds = new Rect();
+ mContainer.getAnimatingBounds(targetBounds);
+ if (!toBounds.equals(targetBounds)) {
+ animateResizePinnedStack(toBounds, -1 /* duration */);
+ }
+
+ final PinnedStackController pinnedStackController =
+ mContainer.getDisplayContent().getPinnedStackController();
+ pinnedStackController.setAspectRatio(
+ pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+ ? aspectRatio : -1f);
+ }
+ }
+
+ /** Sets the current picture-in-picture actions. */
+ public void setPictureInPictureActions(List<RemoteAction> actions) {
+ synchronized (mWindowMap) {
+ if (!mService.mSupportsPictureInPicture || mContainer == null) {
+ return;
+ }
+
+ mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
+ }
+ }
+
+ public void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds,
+ Rect outTempInsetBounds, boolean ignoreVisibility) {
+ synchronized (mWindowMap) {
+ if (mContainer != null) {
+ mContainer.getStackDockedModeBoundsLocked(outBounds, outTempBounds,
+ outTempInsetBounds, ignoreVisibility);
+ return;
+ }
+ outBounds.setEmpty();
+ outTempBounds.setEmpty();
+ outTempInsetBounds.setEmpty();
+ }
+ }
+
+ public void prepareFreezingTaskBounds() {
+ synchronized (mWindowMap) {
+ if (mContainer == null) {
+ throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this
+ + " not found.");
+ }
+ mContainer.prepareFreezingTaskBounds();
+ }
+ }
+
+ private void getRawBounds(Rect outBounds) {
+ if (mContainer.getRawFullscreen()) {
+ outBounds.setEmpty();
+ } else {
+ mContainer.getRawBounds(outBounds);
+ }
+ }
+
+ public void getBounds(Rect outBounds) {
+ synchronized (mWindowMap) {
+ if (mContainer != null) {
+ mContainer.getBounds(outBounds);
+ return;
+ }
+ outBounds.setEmpty();
+ }
+ }
+
+ public void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
+ synchronized(mWindowMap) {
+ mContainer.getBoundsForNewConfiguration(outBounds, outTempBounds);
+ }
+ }
+
+ void requestResize(Rect bounds) {
+ mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
+ }
+
+ @Override
+ public String toString() {
+ return "{StackWindowController stackId=" + mStackId + "}";
+ }
+
+ private static final class H extends Handler {
+
+ static final int REQUEST_RESIZE = 0;
+
+ private final WeakReference<StackWindowController> mController;
+
+ H(WeakReference<StackWindowController> controller, Looper looper) {
+ super(looper);
+ mController = controller;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final StackWindowController controller = mController.get();
+ final StackWindowListener listener = (controller != null)
+ ? controller.mListener : null;
+ if (listener == null) {
+ return;
+ }
+ switch (msg.what) {
+ case REQUEST_RESIZE:
+ listener.requestResize((Rect) msg.obj);
+ break;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/StackWindowListener.java b/services/core/java/com/android/server/wm/StackWindowListener.java
new file mode 100644
index 000000000000..c763c175687f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/StackWindowListener.java
@@ -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 com.android.server.wm;
+
+import android.graphics.Rect;
+
+/**
+ * Interface used by the creator of {@link StackWindowController} to listen to changes with
+ * the stack container.
+ */
+public interface StackWindowListener extends WindowContainerListener {
+
+ /** Called when the stack container would like its controller to resize. */
+ void requestResize(Rect bounds);
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3a3ec71ff86e..ab9a378e7a5b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -27,7 +27,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskDescription;
@@ -82,26 +81,28 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
// Resize mode of the task. See {@link ActivityInfo#resizeMode}
private int mResizeMode;
+ // Whether the task supports picture-in-picture.
+ // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE}
+ private boolean mSupportsPictureInPicture;
+
// Whether the task is currently being drag-resized
private boolean mDragResizing;
private int mDragResizeMode;
private boolean mHomeTask;
- // Whether this task is an on-top launcher task, which is determined by the root activity.
- private boolean mIsOnTopLauncher;
-
private TaskDescription mTaskDescription;
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
- Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode, boolean homeTask,
- TaskDescription taskDescription, TaskWindowContainerController controller) {
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, TaskDescription taskDescription,
+ TaskWindowContainerController controller) {
mTaskId = taskId;
mStack = stack;
mUserId = userId;
mService = service;
- mIsOnTopLauncher = isOnTopLauncher;
mResizeMode = resizeMode;
+ mSupportsPictureInPicture = supportsPictureInPicture;
mHomeTask = homeTask;
setController(controller);
setBounds(bounds, overrideConfig);
@@ -112,7 +113,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
return mStack != null ? mStack.getDisplayContent() : null;
}
- int getAdjustedAddPosition(int suggestedPosition) {
+ private int getAdjustedAddPosition(int suggestedPosition) {
final int size = mChildren.size();
if (suggestedPosition >= size) {
return Math.min(size, suggestedPosition);
@@ -327,7 +328,8 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
}
boolean isResizeable() {
- return ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks;
+ return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
+ || mService.mForceResizableTasks;
}
/**
@@ -341,10 +343,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
|| mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
}
- boolean isOnTopLauncher() {
- return mIsOnTopLauncher;
- }
-
boolean cropWindowsToStackBounds() {
return isResizeable();
}
@@ -560,11 +558,10 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
- // Post message to inform activity manager of the bounds change simulating a one-way
- // call. We do this to prevent a deadlock between window manager lock and activity
- // manager lock been held.
- mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
- RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds).sendToTarget();
+ final TaskWindowContainerController controller = getController();
+ if (controller != null) {
+ controller.requestResize(mBounds, RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 7bc577eae468..90106a9a551d 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -269,7 +269,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
mDragApplicationHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null,
mDisplay.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.inputChannel = mServerChannel;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 53292bb2259d..544d1e3d88db 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -35,17 +35,12 @@ import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVID
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
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.H.RESIZE_STACK;
import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
import android.app.ActivityManager.StackId;
-import android.app.IActivityManager;
import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.Debug;
import android.os.RemoteException;
import android.util.EventLog;
import android.util.Slog;
@@ -53,11 +48,9 @@ import android.util.SparseArray;
import android.view.DisplayInfo;
import android.view.Surface;
-import android.view.WindowManagerPolicy;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
-import com.android.internal.policy.PipSnapAlgorithm;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -167,10 +160,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
}
- boolean topTaskIsOnTopLauncher() {
- return mChildren.get(mChildren.size() - 1).isOnTopLauncher();
- }
-
/**
* Set the bounds of the stack and its containing tasks.
* @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
@@ -206,14 +195,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
}
- boolean isFullscreenBounds(Rect bounds) {
- if (mDisplayContent == null || bounds == null) {
- return true;
- }
- mDisplayContent.getLogicalDisplayRect(mTmpRect);
- return mTmpRect.equals(bounds);
- }
-
/**
* Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
* the normal task bounds.
@@ -228,7 +209,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mAdjustedBounds.set(bounds);
final boolean adjusted = !mAdjustedBounds.isEmpty();
Rect insetBounds = null;
- if (adjusted && isAdjustedForMinimizedDock()) {
+ if (adjusted && isAdjustedForMinimizedDockedStack()) {
insetBounds = mBounds;
} else if (adjusted && mAdjustedForIme) {
if (mImeGoingAway) {
@@ -412,8 +393,10 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
switch (mStackId) {
case PINNED_STACK_ID:
+ Rect targetBounds = new Rect();
+ getAnimatingBounds(targetBounds);
mTmpRect2 = mDisplayContent.getPinnedStackController().onDisplayChanged(mBounds,
- mDisplayContent);
+ targetBounds, mDisplayContent);
break;
case DOCKED_STACK_ID:
repositionDockedStackAfterRotation(mTmpRect2);
@@ -435,9 +418,14 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return true;
}
- void getBoundsForNewConfiguration(Rect outBounds) {
+ void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
outBounds.set(mBoundsAfterRotation);
mBoundsAfterRotation.setEmpty();
+ final DockedStackDividerController controller = getDisplayContent()
+ .mDividerControllerLocked;
+ if (controller.isMinimizedDock() && mStackId == DOCKED_STACK_ID) {
+ outTempBounds.set(controller.getMiddlePositionDockedStackRect());
+ }
}
/**
@@ -497,7 +485,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
- dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
+ dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
+ isMinimizedDockAndHomeStackResizable());
final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
// Recalculate the bounds based on the position of the target.
@@ -658,7 +647,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
final Rect oldBounds = new Rect(mBounds);
Rect bounds = null;
- final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
if (mStackId == DOCKED_STACK_ID
|| (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
&& !dockedStack.fillsParent())) {
@@ -683,21 +672,34 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
// Update the pinned stack controller after the display info is updated
if (mStackId == PINNED_STACK_ID) {
- mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds,
+ Rect targetBounds = new Rect();
+ getAnimatingBounds(targetBounds);
+ mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds, targetBounds,
mDisplayContent);
}
super.onDisplayChanged(dc);
}
- void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
+ void getStackDockedModeBoundsLocked(Rect outBounds, Rect outTempBounds,
+ Rect outTempInsetBounds, boolean ignoreVisibility) {
+ if (mStackId == HOME_STACK_ID && findHomeTask().isResizeable()) {
+ // Calculate the home stack bounds when in docked mode
+ getDisplayContent().mDividerControllerLocked
+ .getHomeStackBoundsInDockedMode(outTempBounds);
+ outTempInsetBounds.set(outTempBounds);
+ } else {
+ outTempBounds.setEmpty();
+ outTempInsetBounds.setEmpty();
+ }
+
if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
|| mDisplayContent == null) {
outBounds.set(mBounds);
return;
}
- final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ final TaskStack dockedStack = mDisplayContent.getDockedStackIgnoringVisibility();
if (dockedStack == null) {
// Not sure why you are calling this method when there is no docked stack...
throw new IllegalStateException(
@@ -804,9 +806,15 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mService.mDockedStackCreateBounds = null;
final Rect bounds = new Rect();
- getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
- mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
- 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
+ final Rect tempBounds = new Rect();
+ final Rect tempInsetBounds = new Rect();
+ getStackDockedModeBoundsLocked(bounds, tempBounds, tempInsetBounds, true /*ignoreVisibility*/);
+ getController().requestResize(bounds);
+ }
+
+ @Override
+ StackWindowController getController() {
+ return (StackWindowController) super.getController();
}
@Override
@@ -957,8 +965,9 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
}
- boolean isAdjustedForMinimizedDock() {
- return mMinimizeAmount != 0f;
+ boolean shouldIgnoreInput() {
+ return isAdjustedForMinimizedDockedStack() || mStackId == DOCKED_STACK_ID &&
+ isMinimizedDockAndHomeStackResizable();
}
/**
@@ -1086,6 +1095,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return true;
}
+ private boolean isMinimizedDockAndHomeStackResizable() {
+ return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
+ && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
+ }
+
/**
* @return the distance in pixels how much the stack gets minimized from it's original size
*/
@@ -1355,9 +1369,17 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
* tasks (including the focused).
*
* We save the focused task region once we find it, and add it back at the end.
+ *
+ * If the task is home stack and it is resizable in the minimized state, we want to
+ * exclude the docked stack from touch so we need the entire screen area and not just a
+ * small portion which the home stack currently is resized to.
*/
- task.getDimBounds(mTmpRect);
+ if (task.isHomeTask() && isMinimizedDockAndHomeStackResizable()) {
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ } else {
+ task.getDimBounds(mTmpRect);
+ }
if (task == focusedTask) {
// Add the focused task rect back into the exclude region once we are done
@@ -1457,7 +1479,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return StackId.hasMovementAnimations(mStackId);
}
- public boolean getForceScaleToCrop() {
+ public boolean getForceScaleToStack() {
return mBoundsAnimating;
}
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 61a2cd96f6c5..efc2e117b02d 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -27,6 +27,8 @@ import android.util.EventLog;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import java.lang.ref.WeakReference;
+
import static com.android.server.EventLogTags.WM_TASK_CREATED;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
@@ -43,45 +45,40 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
public class TaskWindowContainerController
extends WindowContainerController<Task, TaskWindowContainerListener> {
- private static final int REPORT_SNAPSHOT_CHANGED = 0;
-
private final int mTaskId;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case REPORT_SNAPSHOT_CHANGED:
- if (mListener != null) {
- mListener.onSnapshotChanged((TaskSnapshot) msg.obj);
- }
- break;
- }
- }
- };
+ private final H mHandler;
public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
- int stackId, int userId, Rect bounds, Configuration overrideConfig, int resizeMode,
- boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers,
+ StackWindowController stackController, int userId, Rect bounds,
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, boolean toTop, boolean showForAllUsers,
TaskDescription taskDescription) {
- super(listener, WindowManagerService.getInstance());
+ this(taskId, listener, stackController, userId, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, toTop, showForAllUsers, taskDescription,
+ WindowManagerService.getInstance());
+ }
+
+ public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
+ StackWindowController stackController, int userId, Rect bounds,
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, boolean toTop, boolean showForAllUsers,
+ TaskDescription taskDescription, WindowManagerService service) {
+ super(listener, service);
mTaskId = taskId;
+ mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
synchronized(mWindowMap) {
if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId
- + " stackId=" + stackId + " bounds=" + bounds);
+ + " stack=" + stackController + " bounds=" + bounds);
- // TODO: Pass controller for the stack to get the container object when stack is
- // switched to use controller.
- final TaskStack stack = mService.mStackIdToStack.get(stackId);
+ final TaskStack stack = stackController.mContainer;
if (stack == null) {
- throw new IllegalArgumentException("TaskWindowContainerController: invalid stackId="
- + stackId);
+ throw new IllegalArgumentException("TaskWindowContainerController: invalid stack="
+ + stackController);
}
- EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
+ EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
final Task task = createTask(taskId, stack, userId, bounds, overrideConfig, resizeMode,
- homeTask, isOnTopLauncher, taskDescription);
+ supportsPictureInPicture, homeTask, taskDescription);
final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
stack.addTask(task, position, showForAllUsers, true /* moveParents */);
}
@@ -89,10 +86,10 @@ public class TaskWindowContainerController
@VisibleForTesting
Task createTask(int taskId, TaskStack stack, int userId, Rect bounds,
- Configuration overrideConfig, int resizeMode, boolean homeTask,
- boolean isOnTopLauncher, TaskDescription taskDescription) {
- return new Task(taskId, stack, userId, mService, bounds, overrideConfig, isOnTopLauncher,
- resizeMode, homeTask, taskDescription, this);
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, TaskDescription taskDescription) {
+ return new Task(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, taskDescription, this);
}
@Override
@@ -124,21 +121,22 @@ public class TaskWindowContainerController
}
}
- public void reparent(int stackId, int position) {
+ public void reparent(StackWindowController stackController, int position) {
synchronized (mWindowMap) {
if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
- + " to stackId=" + stackId + " at " + position);
+ + " to stack=" + stackController + " at " + position);
if (mContainer == null) {
if (DEBUG_STACK) Slog.i(TAG_WM,
"reparent: could not find taskId=" + mTaskId);
return;
}
- final TaskStack stack = mService.mStackIdToStack.get(stackId);
+ final TaskStack stack = stackController.mContainer;
if (stack == null) {
- throw new IllegalArgumentException("reparent: could not find stackId=" + stackId);
+ throw new IllegalArgumentException("reparent: could not find stack="
+ + stackController);
}
mContainer.reparent(stack, position);
- mService.mWindowPlacerLocked.performSurfacePlacement();
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
}
@@ -158,65 +156,8 @@ public class TaskWindowContainerController
}
if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) {
- mContainer.getDisplayContent().setLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
- }
- }
-
- // TODO: Move to positionChildAt() in stack controller once we have a stack controller.
- public void positionAt(int position, Rect bounds, Configuration overrideConfig) {
- synchronized (mWindowMap) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning taskId=" + mTaskId
- + " at " + position);
- if (mContainer == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionAt: could not find taskId=" + mTaskId);
- return;
- }
- final TaskStack stack = mContainer.mStack;
- if (stack == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionAt: could not find stack for task=" + mContainer);
- return;
- }
- mContainer.positionAt(position, bounds, overrideConfig);
- final DisplayContent displayContent = stack.getDisplayContent();
- displayContent.setLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
- }
-
- // TODO: Replace with moveChildToTop in stack controller?
- public void moveToTop(boolean includingParents) {
- synchronized(mWindowMap) {
- if (mContainer == null) {
- Slog.e(TAG_WM, "moveToTop: taskId=" + mTaskId + " not found");
- return;
- }
- final TaskStack stack = mContainer.mStack;
- stack.positionChildAt(POSITION_TOP, mContainer, includingParents);
-
- if (mService.mAppTransition.isTransitionSet()) {
- mContainer.setSendingToBottom(false);
- }
- stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
- }
-
- // TODO: Replace with moveChildToBottom in stack controller?
- public void moveToBottom() {
- synchronized(mWindowMap) {
- if (mContainer == null) {
- Slog.e(TAG_WM, "moveTaskToBottom: taskId=" + mTaskId + " not found");
- return;
- }
- final TaskStack stack = mContainer.mStack;
- stack.positionChildAt(POSITION_BOTTOM, mContainer, false /* includingParents */);
- if (mService.mAppTransition.isTransitionSet()) {
- mContainer.setSendingToBottom(true);
+ mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
- stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
}
@@ -276,11 +217,46 @@ public class TaskWindowContainerController
}
void reportSnapshotChanged(TaskSnapshot snapshot) {
- mHandler.obtainMessage(REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
+ mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
+ }
+
+ void requestResize(Rect bounds, int resizeMode) {
+ mHandler.obtainMessage(H.REQUEST_RESIZE, resizeMode, 0, bounds).sendToTarget();
}
@Override
public String toString() {
return "{TaskWindowContainerController taskId=" + mTaskId + "}";
}
+
+ private static final class H extends Handler {
+
+ static final int REPORT_SNAPSHOT_CHANGED = 0;
+ static final int REQUEST_RESIZE = 1;
+
+ private final WeakReference<TaskWindowContainerController> mController;
+
+ H(WeakReference<TaskWindowContainerController> controller, Looper looper) {
+ super(looper);
+ mController = controller;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final TaskWindowContainerController controller = mController.get();
+ final TaskWindowContainerListener listener = (controller != null)
+ ? controller.mListener : null;
+ if (listener == null) {
+ return;
+ }
+ switch (msg.what) {
+ case REPORT_SNAPSHOT_CHANGED:
+ listener.onSnapshotChanged((TaskSnapshot) msg.obj);
+ break;
+ case REQUEST_RESIZE:
+ listener.requestResize((Rect) msg.obj, msg.arg1);
+ break;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
index 61b202dc0060..af67de38e5b3 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
@@ -17,14 +17,17 @@
package com.android.server.wm;
import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Rect;
/**
- * Interface used by the creator of the controller to listen to changes with the container.
+ * Interface used by the creator of {@link TaskWindowContainerController} to listen to changes with
+ * the task container.
*/
public interface TaskWindowContainerListener extends WindowContainerListener {
- /**
- * Called when the snapshot of this task has changed.
- */
+ /** Called when the snapshot of this task has changed. */
void onSnapshotChanged(TaskSnapshot snapshot);
+
+ /** Called when the task container would like its controller to resize. */
+ void requestResize(Rect bounds, int resizeMode);
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index feceb8ecb573..c32e68908100 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -447,7 +447,7 @@ class WallpaperController {
private void findWallpaperTarget(DisplayContent dc) {
mFindResults.reset();
- if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
+ if (dc.isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
mFindResults.setUseTopWallpaperAsTarget(true);
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 8ea1b3b1355a..28aebbbb281c 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -40,8 +40,8 @@ class WallpaperWindowToken extends WindowToken {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
- DisplayContent dc) {
- super(service, token, TYPE_WALLPAPER, explicit, dc);
+ DisplayContent dc, boolean ownerCanManageAppTokens) {
+ super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens);
dc.mWallpaperController.addWallpaperToken(this);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5b96263b1817..6973c3c95d49 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -510,14 +510,13 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
* specification...
*/
int getOrientation() {
-
- if (!fillsParent() || !isVisible()) {
- // Ignore invisible containers or containers that don't completely fills their parents.
+ if (!fillsParent()) {
+ // Ignore containers that don't completely fill their parents.
return SCREEN_ORIENTATION_UNSET;
}
- // The container fills its parent so we can use it orientation if it has one specified,
- // otherwise we prefer to use the orientation of its topmost child that has one
+ // The container fills its parent so we can use it orientation if it has one
+ // specified; otherwise we prefer to use the orientation of its topmost child that has one
// specified and fall back on this container's unset or unspecified value as a candidate
// if none of the children have a better candidate for the orientation.
if (mOrientation != SCREEN_ORIENTATION_UNSET
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index e0c3d60142e2..d56110c67c4b 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -59,7 +59,6 @@ class WindowLayersController {
private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mInputMethodWindows = new ArrayDeque<>();
- private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
private WindowState mDockDivider = null;
private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
private int mCurBaseLayer;
@@ -138,7 +137,6 @@ class WindowLayersController {
mPinnedWindows.clear();
mInputMethodWindows.clear();
mDockedWindows.clear();
- mOnTopLauncherWindows.clear();
mReplacingWindows.clear();
mDockDivider = null;
@@ -182,9 +180,6 @@ class WindowLayersController {
if (task == null) {
return;
}
- if (task.isOnTopLauncher()) {
- mOnTopLauncherWindows.add(w);
- }
final TaskStack stack = task.mStack;
if (stack == null) {
return;
@@ -206,10 +201,6 @@ class WindowLayersController {
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
- while (!mOnTopLauncherWindows.isEmpty()) {
- layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
- }
-
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
// treatment, e.g. to be above the dock divider.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c8f4bd23204d..597e8b6ac8fc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,13 +16,14 @@
package com.android.server.wm;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -101,7 +102,6 @@ import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IActivityManager;
-import android.app.RemoteAction;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -236,7 +236,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -523,7 +522,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mSupportsPictureInPicture = false;
int getDragLayerLocked() {
- return mPolicy.windowTypeToLayerLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
+ return mPolicy.getWindowLayerFromTypeLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
}
class RotationWatcher {
@@ -706,12 +705,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowAnimator mAnimator;
- private final BoundsAnimationController mBoundsAnimationController;
-
- /** All of the TaskStacks in the window manager, unordered. For an ordered list call
- * DisplayContent.getStacks(). */
- // TODO: Don't believe this is needed with the WindowContainer model.
- SparseArray<TaskStack> mStackIdToStack = new SparseArray<>();
+ final BoundsAnimationController mBoundsAnimationController;
private final PointerEventDispatcher mPointerEventDispatcher;
@@ -1104,6 +1098,8 @@ public class WindowManagerService extends IWindowManager.Stub
long origId;
final int callingUid = Binder.getCallingUid();
final int type = attrs.type;
+ final boolean ownerCanAddInternalSystemWindow =
+ mContext.checkCallingPermission(INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
synchronized(mWindowMap) {
if (!mDisplayReady) {
@@ -1205,7 +1201,8 @@ public class WindowManagerService extends IWindowManager.Stub
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
- token = new WindowToken(this, attrs.token, type, false, displayContent);
+ token = new WindowToken(this, attrs.token, type, false, displayContent,
+ ownerCanAddInternalSystemWindow);
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
atoken = token.asAppWindowToken();
if (atoken == null) {
@@ -1275,11 +1272,13 @@ public class WindowManagerService extends IWindowManager.Stub
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
- token = new WindowToken(this, null, type, false, displayContent);
+ token = new WindowToken(this, null, type, false, displayContent,
+ ownerCanAddInternalSystemWindow);
}
- WindowState win = new WindowState(this, session, client, token, parentWindow,
- appOp[0], seq, attrs, viewVisibility, session.mUid);
+ final WindowState win = new WindowState(this, session, client, token, parentWindow,
+ appOp[0], seq, attrs, viewVisibility, session.mUid,
+ ownerCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
@@ -2176,7 +2175,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
- WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
+ WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(
+ win.mAttrs.type, win.mOwnerUid);
if (surfaceController != null) {
surfaceController.getSurface(outSurface);
if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied");
@@ -2409,9 +2409,10 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
if (type == TYPE_WALLPAPER) {
- new WallpaperWindowToken(this, binder, true, dc);
+ new WallpaperWindowToken(this, binder, true, dc,
+ true /* ownerCanManageAppTokens */);
} else {
- new WindowToken(this, binder, type, true, dc);
+ new WindowToken(this, binder, type, true, dc, true /* ownerCanManageAppTokens */);
}
}
}
@@ -2573,16 +2574,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- @Override
- public Rect getBoundsForNewConfiguration(int stackId) {
- synchronized(mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- final Rect outBounds = new Rect();
- stack.getBoundsForNewConfiguration(outBounds);
- return outBounds;
- }
- }
-
void setFocusTaskRegionLocked() {
final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
if (focusedTask != null) {
@@ -2827,11 +2818,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- boolean isStackVisibleLocked(int stackId) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- return (stack != null && stack.isVisible());
- }
-
public void setDockedStackCreateState(int mode, Rect bounds) {
synchronized (mWindowMap) {
setDockedStackCreateStateLocked(mode, bounds);
@@ -2843,174 +2829,49 @@ public class WindowManagerService extends IWindowManager.Stub
mDockedStackCreateBounds = bounds;
}
- @Override
- public Rect getPictureInPictureDefaultBounds(int displayId) {
- synchronized (mWindowMap) {
- if (!mSupportsPictureInPicture) {
- return null;
- }
-
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- return displayContent.getPinnedStackController().getDefaultBounds();
- }
- }
-
- @Override
- public Rect getPictureInPictureMovementBounds(int displayId) {
+ public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
synchronized (mWindowMap) {
if (!mSupportsPictureInPicture) {
return null;
}
- final Rect stackBounds = new Rect();
- getStackBounds(PINNED_STACK_ID, stackBounds);
- if (stackBounds.isEmpty()) {
- return stackBounds;
- }
-
+ final Rect stackBounds;
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- return displayContent.getPinnedStackController().getMovementBounds(stackBounds);
- }
- }
-
- public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
- synchronized (mWindowMap) {
- if (!mSupportsPictureInPicture) {
+ if (displayContent == null) {
return null;
}
- final Rect stackBounds;
- final DisplayContent displayContent;
- final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+ final PinnedStackController pinnedStackController =
+ displayContent.getPinnedStackController();
+ final TaskStack stack = displayContent.getStackById(PINNED_STACK_ID);
if (stack != null) {
// If the stack exists, then use its final bounds to calculate the new aspect ratio
// bounds.
- displayContent = stack.getDisplayContent();
stackBounds = new Rect();
stack.getAnimatingBounds(stackBounds);
} else {
// Otherwise, just calculate the aspect ratio bounds from the default bounds
- displayContent = mRoot.getDisplayContent(displayId);
- stackBounds = displayContent.getPinnedStackController().getDefaultBounds();
- }
- return displayContent.getPinnedStackController().getAspectRatioBounds(stackBounds,
- aspectRatio);
- }
- }
-
- /**
- * Sets the current picture-in-picture aspect ratio.
- */
- public void setPictureInPictureAspectRatio(float aspectRatio) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
- if (!mSupportsPictureInPicture || stack == null) {
- return;
- }
-
- final int displayId = stack.getDisplayContent().getDisplayId();
- final Rect toBounds = getPictureInPictureBounds(displayId, aspectRatio);
- animateResizePinnedStack(toBounds, -1 /* duration */);
- }
- }
-
- /**
- * Sets the current picture-in-picture actions.
- */
- public void setPictureInPictureActions(List<RemoteAction> actions) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
- if (!mSupportsPictureInPicture || stack == null) {
- return;
- }
-
- stack.getDisplayContent().getPinnedStackController().setActions(actions);
- }
- }
-
- /**
- * Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with
- * specified stackId.
- * @param stackId The unique identifier of the new stack.
- * @param displayId The unique identifier of the DisplayContent.
- * @param onTop If true the stack will be place at the top of the display,
- * else at the bottom.
- * @return The bounds that the stack has after adding. null means fullscreen.
- */
- public Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mWindowMap) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- throw new IllegalArgumentException("Trying to add stackId=" + stackId
- + " to unknown displayId=" + displayId);
- }
-
- return dc.addStackToDisplay(stackId, onTop);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- /**
- * Move a TaskStack from current DisplayContent to specified one.
- * @param stackId The unique identifier of the new stack.
- * @param displayId The unique identifier of the new display.
- */
- public Rect moveStackToDisplay(int stackId, int displayId) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mWindowMap) {
- TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null) {
- throw new IllegalArgumentException("Trying to move unknown stackId=" + stackId
- + " to displayId=" + displayId);
- }
-
- final DisplayContent targetDisplayContent = mRoot.getDisplayContent(displayId);
- if (targetDisplayContent == null) {
- throw new IllegalArgumentException("Trying to move stackId=" + stackId
- + " to unknown displayId=" + displayId);
- }
-
- return targetDisplayContent.moveStackToDisplay(stack);
+ stackBounds = pinnedStackController.getDefaultBounds();
}
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
- /**
- * Remove a TaskStack completely.
- * @param stackId The unique identifier of the stack.
- */
- public void removeStack(int stackId) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack != null) {
- stack.removeIfPossible();
- mStackIdToStack.remove(stackId);
+ if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+ return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio);
+ } else {
+ return stackBounds;
}
}
}
- public void getStackDockedModeBounds(int stackId, Rect bounds, boolean ignoreVisibility) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack != null) {
- stack.getStackDockedModeBoundsLocked(bounds, ignoreVisibility);
- return;
- }
- bounds.setEmpty();
- }
+ public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
+ aspectRatio);
}
@Override
public void getStackBounds(int stackId, Rect bounds) {
synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
+ final TaskStack stack = mRoot.getStackById(stackId);
if (stack != null) {
stack.getBounds(bounds);
return;
@@ -3035,43 +2896,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
/**
- * Re-sizes a stack and its containing tasks.
- * @param stackId Id of stack to resize.
- * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
- * @param configs Configurations for tasks in the resized stack, keyed by task id.
- * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
- * @return True if the stack is now fullscreen.
- * */
- public boolean resizeStack(int stackId, Rect bounds,
- SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
- SparseArray<Rect> taskTempInsetBounds) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null) {
- throw new IllegalArgumentException("resizeStack: stackId " + stackId
- + " not found.");
- }
- if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
- && stack.isVisible()) {
- stack.getDisplayContent().setLayoutNeeded();
- mWindowPlacerLocked.performSurfacePlacement();
- }
- return stack.getRawFullscreen();
- }
- }
-
- public void prepareFreezingTaskBounds(int stackId) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null) {
- throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId
- + " not found.");
- }
- stack.prepareFreezingTaskBounds();
- }
- }
-
- /**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
* layouting will be resumed once the last caller has called {@link #continueSurfaceLayout}
@@ -3505,8 +3329,9 @@ public class WindowManagerService extends IWindowManager.Stub
// Notify whether the docked stack exists for the current user
final DisplayContent displayContent = getDefaultDisplayContentLocked();
- displayContent.mDividerControllerLocked
- .notifyDockedStackExistsChanged(hasDockedTasksForUser(newUserId));
+ final TaskStack stack = displayContent.getDockedStackIgnoringVisibility();
+ displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
+ stack != null && stack.hasTaskForUser(newUserId));
// If the display is already prepared, update the density.
// Otherwise, we'll update it when it's prepared.
@@ -3519,15 +3344,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- /** Returns whether there is a docked task for the current user. */
- boolean hasDockedTasksForUser(int userId) {
- final TaskStack stack = mStackIdToStack.get(DOCKED_STACK_ID);
- if (stack == null) {
- return false;
- }
- return stack.hasTaskForUser(userId);
- }
-
/* Called by WindowState */
boolean isCurrentProfileLocked(int userId) {
if (userId == mCurrentUserId) return true;
@@ -3777,7 +3593,7 @@ public class WindowManagerService extends IWindowManager.Stub
mCircularDisplayMask = new CircularDisplayMask(
getDefaultDisplayContentLocked().getDisplay(),
mFxSession,
- mPolicy.windowTypeToLayerLw(
+ mPolicy.getWindowLayerFromTypeLw(
WindowManager.LayoutParams.TYPE_POINTER)
* TYPE_LAYER_MULTIPLIER + 10, screenOffset, maskThickness);
}
@@ -3806,7 +3622,7 @@ public class WindowManagerService extends IWindowManager.Stub
mContext,
getDefaultDisplayContentLocked().getDisplay(),
mFxSession,
- mPolicy.windowTypeToLayerLw(
+ mPolicy.getWindowLayerFromTypeLw(
WindowManager.LayoutParams.TYPE_POINTER)
* TYPE_LAYER_MULTIPLIER + 10);
}
@@ -4998,6 +4814,14 @@ public class WindowManagerService extends IWindowManager.Stub
mDisplayMetrics, dw, dh, displayId);
config.densityDpi = displayInfo.logicalDensityDpi;
+ config.colorMode =
+ (displayInfo.isHdr()
+ ? Configuration.COLOR_MODE_HDR_YES
+ : Configuration.COLOR_MODE_HDR_NO)
+ | (displayInfo.isWideColorGamut()
+ ? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
+ : Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
+
// Update the configuration based on available input devices, lid switch,
// and platform configuration.
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
@@ -5417,8 +5241,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int UPDATE_DOCKED_STACK_DIVIDER = 41;
- public static final int RESIZE_STACK = 42;
- public static final int RESIZE_TASK = 43;
public static final int TEAR_DOWN_DRAG_AND_DROP_INPUT = 44;
public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
@@ -5844,23 +5666,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
break;
- case RESIZE_TASK: {
- try {
- mActivityManager.resizeTask(msg.arg1, (Rect) msg.obj, msg.arg2);
- } catch (RemoteException e) {
- // This will not happen since we are in the same process.
- }
- }
- break;
- case RESIZE_STACK: {
- try {
- mActivityManager.resizeStack(
- msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false, false, -1);
- } catch (RemoteException e) {
- // This will not happen since we are in the same process.
- }
- }
- break;
case WINDOW_REPLACEMENT_TIMEOUT: {
synchronized (mWindowMap) {
for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
@@ -7646,26 +7451,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void animateResizePinnedStack(final Rect bounds, final int animationDuration) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
- if (stack == null) {
- Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
- return;
- }
- final Rect originalBounds = new Rect();
- stack.getBounds(originalBounds);
- stack.setAnimatingBounds(bounds);
- UiThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- mBoundsAnimationController.animateBounds(
- stack, originalBounds, bounds, animationDuration);
- }
- });
- }
- }
-
public void setForceResizableTasks(boolean forceResizableTasks) {
synchronized (mWindowMap) {
mForceResizableTasks = forceResizableTasks;
@@ -8123,7 +7908,8 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean isStackVisible(int stackId) {
synchronized (mWindowMap) {
- return WindowManagerService.this.isStackVisibleLocked(stackId);
+ final DisplayContent dc = getDefaultDisplayContentLocked();
+ return dc.isStackVisible(stackId);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 10aebe662828..867080ed2450 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
import static android.app.ActivityManager.StackId;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.isLowRamDeviceStatic;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -164,6 +163,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final int mAppOp;
// UserId and appId of the owner. Don't display windows of non-current user.
final int mOwnerUid;
+ /** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */
+ final boolean mOwnerCanAddInternalSystemWindow;
final IWindowId mWindowId;
WindowToken mToken;
// The same object as mToken if this is an app window and null for non-app windows.
@@ -561,7 +562,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
- int viewVisibility, int ownerId) {
+ int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
mService = service;
mSession = s;
mClient = c;
@@ -569,6 +570,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mToken = token;
mAppToken = mToken.asAppWindowToken();
mOwnerUid = ownerId;
+ mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new IWindowId.Stub() {
@Override
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -613,9 +615,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
- mBaseLayer = mPolicy.windowTypeToLayerLw(parentWindow.mAttrs.type)
+ mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
- mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
+ mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
@@ -629,7 +631,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
- mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
+ mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
@@ -657,7 +659,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mYOffset = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
- mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, getDisplayId());
+ mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
+ getDisplayId());
}
void attach() {
@@ -675,6 +678,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mAttrs.packageName;
}
+ @Override
+ public boolean canAddInternalSystemWindow() {
+ return mOwnerCanAddInternalSystemWindow;
+ }
+
/**
* Subtracts the insets calculated by intersecting {@param layoutFrame} with {@param insetFrame}
* from {@param frame}. In other words, it applies the insets that would result if
@@ -1671,11 +1679,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mLastReportedConfiguration.equals(getConfiguration());
}
- boolean isAdjustedForMinimizedDock() {
- return mAppToken != null && mAppToken.mTask != null
- && mAppToken.mTask.mStack.isAdjustedForMinimizedDock();
- }
-
void onWindowReplacementTimeout() {
if (mWillReplaceWindow) {
// Since the window already timed out, remove it immediately now.
@@ -2304,6 +2307,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final WindowState win = mService.windowForClientLocked(mSession, mClient, false);
Slog.i(TAG, "WIN DEATH: " + win);
if (win != null) {
+ final DisplayContent dc = getDisplayContent();
if (win.mAppToken != null && win.mAppToken.findMainWindow() == win) {
mService.mTaskSnapshotController.onAppDied(win.mAppToken);
}
@@ -2313,7 +2317,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// just in case they have the divider at an unstable position. Better
// also reset drag resizing state, because the owner can't do it
// anymore.
- final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ final TaskStack stack = dc.getDockedStackIgnoringVisibility();
if (stack != null) {
stack.resetDockedStackToMiddle();
}
@@ -2363,7 +2367,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
&& (mAppToken == null || mAppToken.windowsAreFocusable())
- && !isAdjustedForMinimizedDock();
+ && !canReceiveTouchInput();
+ }
+
+ /** @return true if this window desires touch events. */
+ boolean canReceiveTouchInput() {
+ return mAppToken != null && mAppToken.mTask != null
+ && mAppToken.mTask.mStack.shouldIgnoreInput();
}
@Override
@@ -3198,8 +3208,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (task == null) {
return false;
}
+ if (!StackId.isStackAffectedByDragResizing(getStackId())) {
+ return false;
+ }
if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
-
// Floating windows never enter drag resize mode.
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 19ef44cace33..d2ea64c89a98 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -577,7 +577,7 @@ class WindowStateAnimator {
}
}
- WindowSurfaceController createSurfaceLocked() {
+ WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
final WindowState w = mWin;
if (w.restoreSavedSurface()) {
if (DEBUG_ANIM) Slog.i(TAG,
@@ -653,7 +653,7 @@ class WindowStateAnimator {
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),
- width, height, format, flags, this);
+ width, height, format, flags, this, windowType, ownerUid);
w.setHasSurface(true);
@@ -915,10 +915,15 @@ class WindowStateAnimator {
if (attachedTransformation != null) {
tmpMatrix.postConcat(attachedTransformation.getMatrix());
}
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
+
+ // The translation that applies the position of the window needs to be applied at the
+ // end in case that other translations include scaling. Otherwise the scaling will
+ // affect this translation. But it needs to be set before the screen rotation animation
+ // so the pivot point is at the center of the screen for all windows.
+ tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
@@ -1313,18 +1318,20 @@ class WindowStateAnimator {
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
- if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
+ if ((task != null && task.mStack.getForceScaleToStack()) || mForceScaleUntilResize) {
int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
if (!mForceScaleUntilResize) {
mSurfaceController.forceScaleableInTransaction(true);
}
+
+ task.mStack.getDimBounds(mTmpStackBounds);
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
- mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
- mExtraVScale = (mTmpClipRect.height() - vInsets) / (float)(surfaceHeight - vInsets);
+ mExtraHScale = (mTmpStackBounds.width() - hInsets) / (float)(surfaceWidth - hInsets);
+ mExtraVScale = (mTmpStackBounds.height() - vInsets) / (float)(surfaceHeight - vInsets);
- // In the case of ForceScaleToCrop we scale entire tasks together,
+ // In the case of ForceScaleToStack we scale entire tasks together,
// and so we need to scale our offsets relative to the task bounds
// or parent and child windows would fall out of alignment.
int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - mExtraHScale));
@@ -1345,8 +1352,7 @@ class WindowStateAnimator {
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
// past where the system would have cropped us
- mTmpClipRect.set(0, 0, (int)surfaceWidth, (int)surfaceHeight);
- mTmpFinalClipRect.setEmpty();
+ clipRect = null;
// Various surfaces in the scaled stack may resize at different times.
// We need to ensure for each surface, that we disable transformation matrix
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c48a58514c3d..1096ede96316 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -79,8 +79,8 @@ class WindowSurfaceController {
private final WindowManagerService mService;
- public WindowSurfaceController(SurfaceSession s,
- String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
+ public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
+ int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
mSurfaceW = w;
@@ -98,13 +98,13 @@ class WindowSurfaceController {
animator.mWin.mSubLayer < 0 &&
animator.mWin.mAppToken != null) {
mSurfaceControl = new SurfaceControlWithBackground(s,
- name, w, h, format, flags, animator.mWin.mAppToken);
+ name, w, h, format, flags, animator.mWin.mAppToken, windowType, ownerUid);
} else if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
- s, name, w, h, format, flags);
+ s, name, w, h, format, flags, windowType, ownerUid);
} else {
mSurfaceControl = new SurfaceControl(
- s, name, w, h, format, flags);
+ s, name, w, h, format, flags, windowType, ownerUid);
}
if (mService.mRoot.mSurfaceTraceEnabled) {
@@ -569,9 +569,21 @@ class WindowSurfaceController {
private float mDsdx, mDtdx, mDsdy, mDtdy;
private final String mName;
+ public SurfaceTrace(SurfaceSession s, String name, int w, int h, int format, int flags,
+ int windowType, int ownerUid)
+ throws OutOfResourcesException {
+ super(s, name, w, h, format, flags, windowType, ownerUid);
+ mName = name != null ? name : "Not named";
+ mSize.set(w, h);
+ if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+ + Debug.getCallers(3));
+ synchronized (sSurfaces) {
+ sSurfaces.add(0, this);
+ }
+ }
+
public SurfaceTrace(SurfaceSession s,
- String name, int w, int h, int format, int flags)
- throws OutOfResourcesException {
+ String name, int w, int h, int format, int flags) {
super(s, name, w, h, format, flags);
mName = name != null ? name : "Not named";
mSize.set(w, h);
@@ -806,11 +818,10 @@ class WindowSurfaceController {
public boolean mVisible = false;
public int mLayer = -1;
- public SurfaceControlWithBackground(SurfaceSession s,
- String name, int w, int h, int format, int flags,
- AppWindowToken token)
- throws OutOfResourcesException {
- super(s, name, w, h, format, flags);
+ public SurfaceControlWithBackground(SurfaceSession s, String name, int w, int h, int format,
+ int flags, AppWindowToken token, int windowType, int ownerUid)
+ throws OutOfResourcesException {
+ super(s, name, w, h, format, flags, windowType, ownerUid);
mBackgroundControl = new SurfaceControl(s, name, w, h,
PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 4b94d1566681..8beb87d3354b 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -77,6 +77,9 @@ class WindowToken extends WindowContainer<WindowState> {
// The display this token is on.
protected DisplayContent mDisplayContent;
+ /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */
+ final boolean mOwnerCanManageAppTokens;
+
/**
* Compares two child window of this token and returns -1 if the first is lesser than the
* second in terms of z-order and 1 otherwise.
@@ -98,11 +101,12 @@ class WindowToken extends WindowContainer<WindowState> {
};
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
- DisplayContent dc) {
+ DisplayContent dc, boolean ownerCanManageAppTokens) {
mService = service;
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
+ mOwnerCanManageAppTokens = ownerCanManageAppTokens;
onDisplayChanged(dc);
}
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 545b3d757e10..703518d1c246 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -70,7 +70,7 @@ float finalizeTemperature(float temperature) {
static void nativeInit(JNIEnv* env, jobject obj) {
// TODO(b/31632518)
if (gThermalModule == nullptr) {
- gThermalModule = IThermal::getService("thermal");
+ gThermalModule = IThermal::getService();
}
if (gThermalModule == nullptr) {
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index e46490bb3fac..3120af56a1fd 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -26,18 +26,11 @@
namespace android {
-static int start_sensor_service(void* /*unused*/) {
- SensorService::instantiate();
- return 0;
-}
-
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
- // Start the sensor service in a new thread
- createThreadEtc(start_sensor_service, nullptr,
- "StartSensorThread", PRIORITY_FOREGROUND);
+ SensorService::instantiate();
}
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 6791da928b1b..8baa96bf9bae 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -207,6 +207,7 @@ public:
void setPointerIconType(int32_t iconId);
void reloadPointerIcons();
void setCustomPointerIcon(const SpriteIcon& icon);
+ void setPointerCapture(bool enabled);
/* --- InputReaderPolicyInterface implementation --- */
@@ -276,6 +277,9 @@ private:
// Show touches feature enable/disable.
bool showTouches;
+ // Pointer capture feature enable/disable.
+ bool pointerCapture;
+
// Sprite controller singleton, created on first use.
sp<SpriteController> spriteController;
@@ -312,6 +316,7 @@ NativeInputManager::NativeInputManager(jobject contextObj,
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
+ mLocked.pointerCapture = false;
}
mInteractive = true;
@@ -339,6 +344,7 @@ void NativeInputManager::dump(String8& dump) {
dump.appendFormat(INDENT "Pointer Gestures Enabled: %s\n",
toString(mLocked.pointerGesturesEnabled));
dump.appendFormat(INDENT "Show Touches: %s\n", toString(mLocked.showTouches));
+ dump.appendFormat(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture));
}
dump.append("\n");
@@ -460,6 +466,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->showTouches = mLocked.showTouches;
+ outConfig->pointerCapture = mLocked.pointerCapture;
+
outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
} // release lock
@@ -767,6 +775,22 @@ void NativeInputManager::setShowTouches(bool enabled) {
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}
+void NativeInputManager::setPointerCapture(bool enabled) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.pointerCapture == enabled) {
+ return;
+ }
+
+ ALOGI("Setting pointer capture to %s.", enabled ? "enabled" : "disabled");
+ mLocked.pointerCapture = enabled;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+}
+
void NativeInputManager::setInteractive(bool interactive) {
mInteractive = interactive;
}
@@ -1323,6 +1347,12 @@ static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
im->setFocusedApplication(env, applicationHandleObj);
}
+static void nativeSetPointerCapture(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jboolean enabled) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ im->setPointerCapture(enabled);
+}
+
static void nativeSetInputDispatchMode(JNIEnv* /* env */,
jclass /* clazz */, jlong ptr, jboolean enabled, jboolean frozen) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1509,6 +1539,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*) nativeSetInputWindows },
{ "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V",
(void*) nativeSetFocusedApplication },
+ { "nativeSetPointerCapture", "(JZ)V",
+ (void*) nativeSetPointerCapture },
{ "nativeSetInputDispatchMode", "(JZZ)V",
(void*) nativeSetInputDispatchMode },
{ "nativeSetSystemUiVisibility", "(JI)V",
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index 517fce058d1a..05ef0d11e16c 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -558,12 +558,12 @@ void getHubsCb(const ::android::hardware::hidl_vec<ContextHub>& hubs) {
void initContextHubService() {
db.hubInfo.numHubs = 0;
- db.hubInfo.contextHub = IContexthub::getService("context_hub_hal");
+ db.hubInfo.contextHub = IContexthub::getService("context_hub");
if (db.hubInfo.contextHub == nullptr) {
ALOGE("Could not load context hub hal");
} else {
- ALOGI("Loaded context hub hal");
+ ALOGI("Loaded context hub hal, isRemote %s", db.hubInfo.contextHub->isRemote() ? "TRUE" : "FALSE");
}
// Prep for storing app info
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 01a1efc3506e..1578562a4faf 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -58,6 +58,7 @@ static jmethodID method_reportGeofencePauseStatus;
static jmethodID method_reportGeofenceResumeStatus;
static jmethodID method_reportMeasurementData;
static jmethodID method_reportNavigationMessages;
+static jmethodID method_reportLocationBatch;
/*
* Save a pointer to JavaVm to attach/detach threads executing
@@ -80,6 +81,8 @@ using android::hardware::gnss::V1_0::IAGnssCallback;
using android::hardware::gnss::V1_0::IAGnssRil;
using android::hardware::gnss::V1_0::IAGnssRilCallback;
using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::gnss::V1_0::IGnssBatching;
+using android::hardware::gnss::V1_0::IGnssBatchingCallback;
using android::hardware::gnss::V1_0::IGnssCallback;
using android::hardware::gnss::V1_0::IGnssConfiguration;
using android::hardware::gnss::V1_0::IGnssDebug;
@@ -100,6 +103,7 @@ sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IAGnssRil> agnssRilIface = nullptr;
sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
sp<IAGnss> agnssIface = nullptr;
+sp<IGnssBatching> gnssBatchingIface = nullptr;
sp<IGnssDebug> gnssDebugIface = nullptr;
sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
@@ -139,6 +143,7 @@ void JavaMethodHelper<T>::callJavaMethod(
class JavaObject {
public:
JavaObject(JNIEnv* env, const char* class_name);
+ JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1);
virtual ~JavaObject();
template<class T>
@@ -159,6 +164,12 @@ JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
object_ = env_->NewObject(clazz_, ctor);
}
+JavaObject::JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1) : env_(env) {
+ clazz_ = env_->FindClass(class_name);
+ jmethodID ctor = env->GetMethodID(clazz_, "<init>", "(Ljava/lang/String;)V");
+ object_ = env_->NewObject(clazz_, ctor, env->NewStringUTF(sz_arg_1));
+}
+
JavaObject::~JavaObject() {
env_->DeleteLocalRef(clazz_);
}
@@ -591,6 +602,7 @@ Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb(
env->CallVoidMethod(mCallbacksObj,
method_reportNavigationMessages,
navigationMessage);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(navigationMessage);
return Void();
}
@@ -925,6 +937,81 @@ Return<void> AGnssRilCallback::requestRefLocCb() {
return Void();
}
+/*
+ * GnssBatchingCallback interface implements the callback methods
+ * required by the IGnssBatching interface.
+ */
+struct GnssBatchingCallback : public IGnssBatchingCallback {
+ /*
+ * Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
+ * follow.
+ */
+ Return<void> gnssLocationBatchCb(
+ const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations)
+ override;
+ private:
+ jobject translateLocation(
+ JNIEnv* env, const hardware::gnss::V1_0::GnssLocation* location);
+};
+
+Return<void> GnssBatchingCallback::gnssLocationBatchCb(
+ const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations) {
+ JNIEnv* env = getJniEnv();
+
+ jobjectArray jLocations = env->NewObjectArray(locations.size(),
+ env->FindClass("android/location/Location"), nullptr);
+
+ for (uint16_t i = 0; i < locations.size(); ++i) {
+ jobject jLocation = translateLocation(env, &locations[i]);
+ env->SetObjectArrayElement(jLocations, i, jLocation);
+ env->DeleteLocalRef(jLocation);
+ }
+
+ env->CallVoidMethod(mCallbacksObj, method_reportLocationBatch, jLocations);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+ env->DeleteLocalRef(jLocations);
+
+ return Void();
+}
+
+// TODO: Use this common code to translate location for Geofencing and regular Location
+jobject GnssBatchingCallback::translateLocation(
+ JNIEnv* env, const hardware::gnss::V1_0::GnssLocation* location) {
+ JavaObject object(env, "android/location/Location", "gps");
+
+ uint16_t flags = static_cast<uint32_t>(location->gnssLocationFlags);
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) {
+ SET(Latitude, location->latitudeDegrees);
+ SET(Longitude, location->longitudeDegrees);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_ALTITUDE) {
+ SET(Altitude, location->altitudeMeters);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED) {
+ SET(Speed, location->speedMetersPerSec);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING) {
+ SET(Bearing, location->bearingDegrees);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+ SET(Accuracy, location->horizontalAccuracyMeters);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ SET(VerticalAccuracyMeters, location->verticalAccuracyMeters);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ SET(SpeedAccuracyMetersPerSecond, location->speedAccuracyMetersPerSecond);
+ }
+ if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ SET(BearingAccuracyDegrees, location->bearingAccuracyDegrees);
+ }
+ SET(Time, location->timestamp);
+
+ return object.get();
+}
+
+
static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
@@ -959,6 +1046,10 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
clazz,
"reportNavigationMessage",
"(Landroid/location/GnssNavigationMessage;)V");
+ method_reportLocationBatch = env->GetMethodID(
+ clazz,
+ "reportLocationBatch",
+ "([Landroid/location/Location;)V");
/*
* Save a pointer to JVM.
@@ -1033,6 +1124,13 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
} else {
gnssGeofencingIface = gnssGeofencing;
}
+
+ auto gnssBatching = gnssHal->getExtensionGnssBatching();
+ if (!gnssBatching.isOk()) {
+ ALOGD("Unable to get a handle to gnssBatching");
+ } else {
+ gnssBatchingIface = gnssBatching;
+ }
} else {
ALOGE("Unable to get GPS service\n");
}
@@ -1704,6 +1802,67 @@ static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_sele
}
}
+static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
+ if (gnssBatchingIface == nullptr) {
+ return 0; // batching not supported, size = 0
+ }
+ auto result = gnssBatchingIface->getBatchSize();
+ if (result.isOk()) {
+ return static_cast<jint>(result);
+ } else {
+ return 0; // failure in binder, don't support batching
+ }
+}
+
+static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
+ if (gnssBatchingIface == nullptr) {
+ return JNI_FALSE; // batching not supported
+ }
+ sp<IGnssBatchingCallback> gnssBatchingCbIface = new GnssBatchingCallback();
+
+ return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface));
+}
+
+static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
+ if (gnssBatchingIface == nullptr) {
+ return; // batching not supported
+ }
+ gnssBatchingIface->cleanup();
+}
+
+static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
+ jlong periodNanos, jboolean wakeOnFifoFull) {
+ if (gnssBatchingIface == nullptr) {
+ return JNI_FALSE; // batching not supported
+ }
+
+ IGnssBatching::Options options;
+ options.periodNanos = periodNanos;
+ if (wakeOnFifoFull) {
+ options.flags = static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL);
+ } else {
+ options.flags = 0;
+ }
+
+ return static_cast<jboolean>(gnssBatchingIface->start(options));
+}
+
+static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
+ if (gnssBatchingIface == nullptr) {
+ return; // batching not supported
+ }
+
+ gnssBatchingIface->flush();
+}
+
+static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
+ if (gnssBatchingIface == nullptr) {
+ return JNI_FALSE; // batching not supported
+ }
+
+ return gnssBatchingIface->stop();
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", reinterpret_cast<void *>(
@@ -1829,6 +1988,27 @@ static const JNINativeMethod sMethods[] = {
{"native_set_emergency_supl_pdn",
"(I)Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
+ {"native_get_batch_size",
+ "()I",
+ reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)},
+ {"native_init_batching",
+ "()Z",
+ reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)},
+ {"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)},
};
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index b2372a3eb84c..fab309bfb148 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -110,7 +110,7 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t
static void nativeInit(JNIEnv* env, jobject obj) {
gPowerManagerServiceObj = env->NewGlobalRef(obj);
- gPowerHal = IPower::getService("power");
+ gPowerHal = IPower::getService();
if (gPowerHal == nullptr) {
ALOGE("Couldn't load PowerHAL module");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f3b013122890..003b6d0d3be9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -33,6 +33,13 @@ import static android.app.admin.DevicePolicyManager.CODE_SYSTEM_USER;
import static android.app.admin.DevicePolicyManager.CODE_USER_HAS_PROFILE_OWNER;
import static android.app.admin.DevicePolicyManager.CODE_USER_NOT_RUNNING;
import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -53,6 +60,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
@@ -259,6 +267,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
= "application-restrictions-manager";
+ // Comprehensive list of delegations.
+ private static final String DELEGATIONS[] = {
+ DELEGATION_CERT_INSTALL,
+ DELEGATION_APP_RESTRICTIONS,
+ DELEGATION_BLOCK_UNINSTALL,
+ DELEGATION_ENABLE_SYSTEM_APP,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+ DELEGATION_PACKAGE_ACCESS,
+ DELEGATION_PERMISSION_GRANT
+ };
+
/**
* System property whose value is either "true" or "false", indicating whether
* device owner is present.
@@ -468,12 +487,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ComponentName mRestrictionsProvider;
- String mDelegatedCertInstallerPackage;
+ // Map of delegate package to delegation scopes
+ final ArrayMap<String, List<String>> mDelegationMap = new ArrayMap<>();
boolean doNotAskCredentialsOnBoot = false;
- String mApplicationRestrictionsManagingPackage;
-
Set<String> mAffiliationIds = new ArraySet<>();
long mLastSecurityLogRetrievalTime = -1;
@@ -1397,7 +1415,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void handlePackagesChanged(String packageName, int userHandle) {
- boolean removed = false;
+ boolean removedAdmin = false;
if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
synchronized (this) {
@@ -1413,32 +1431,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userHandle) == null) {
- removed = true;
+ removedAdmin = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
}
}
} catch (RemoteException re) {
- // Shouldn't happen
+ // Shouldn't happen.
}
}
- if (removed) {
+ if (removedAdmin) {
validatePasswordOwnerLocked(policy);
- saveSettingsLocked(policy.mUserHandle);
}
- // Check if delegated cert installer or app restrictions managing packages are removed.
- if (isRemovedPackage(packageName, policy.mDelegatedCertInstallerPackage, userHandle)) {
- policy.mDelegatedCertInstallerPackage = null;
- saveSettingsLocked(policy.mUserHandle);
+ boolean removedDelegate = false;
+
+ // Check if a delegate was removed.
+ for (int i = policy.mDelegationMap.size() - 1; i >= 0; i--) {
+ final String delegatePackage = policy.mDelegationMap.keyAt(i);
+ if (isRemovedPackage(packageName, delegatePackage, userHandle)) {
+ policy.mDelegationMap.removeAt(i);
+ removedDelegate = true;
+ }
}
- if (isRemovedPackage(
- packageName, policy.mApplicationRestrictionsManagingPackage, userHandle)) {
- policy.mApplicationRestrictionsManagingPackage = null;
+
+ // Persist updates if the removed package was an admin or delegate.
+ if (removedAdmin || removedDelegate) {
saveSettingsLocked(policy.mUserHandle);
}
}
- if (removed) {
+ if (removedAdmin) {
// The removed admin might have disabled camera, so update user restrictions.
pushUserRestrictions(userHandle);
}
@@ -1510,6 +1532,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
}
+ AlarmManager getAlarmManager() {
+ return (AlarmManager) mContext.getSystemService(AlarmManager.class);
+ }
+
IWindowManager getIWindowManager() {
return IWindowManager.Stub
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -1609,6 +1635,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.getSystemService(PowerManager.class).reboot(reason);
}
+ void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
+ throws IOException {
+ RecoverySystem.rebootWipeUserData(mContext, shutdown, reason, force);
+ }
+
boolean systemPropertiesGetBoolean(String key, boolean def) {
return SystemProperties.getBoolean(key, def);
}
@@ -2065,7 +2096,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long token = mInjector.binderClearCallingIdentity();
try {
int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
- AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ AlarmManager am = mInjector.getAlarmManager();
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
@@ -2372,13 +2403,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.attribute(null, ATTR_PERMISSION_POLICY,
Integer.toString(policy.mPermissionPolicy));
}
- if (policy.mDelegatedCertInstallerPackage != null) {
- out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
- policy.mDelegatedCertInstallerPackage);
- }
- if (policy.mApplicationRestrictionsManagingPackage != null) {
- out.attribute(null, ATTR_APPLICATION_RESTRICTIONS_MANAGER,
- policy.mApplicationRestrictionsManagingPackage);
+
+ // Serialize delegations.
+ for (int i = 0; i < policy.mDelegationMap.size(); ++i) {
+ final String delegatePackage = policy.mDelegationMap.keyAt(i);
+ final List<String> scopes = policy.mDelegationMap.valueAt(i);
+
+ // Every "delegation" tag serializes the information of one delegate-scope pair.
+ for (String scope : scopes) {
+ out.startTag(null, "delegation");
+ out.attribute(null, "delegatePackage", delegatePackage);
+ out.attribute(null, "scope", scope);
+ out.endTag(null, "delegation");
+ }
}
final int N = policy.mAdminList.size();
@@ -2562,10 +2599,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!TextUtils.isEmpty(permissionPolicy)) {
policy.mPermissionPolicy = Integer.parseInt(permissionPolicy);
}
- policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
- ATTR_DELEGATED_CERT_INSTALLER);
- policy.mApplicationRestrictionsManagingPackage = parser.getAttributeValue(null,
- ATTR_APPLICATION_RESTRICTIONS_MANAGER);
+ // Check for delegation compatibility with pre-O.
+ // TODO(edmanp) remove in P.
+ {
+ final String certDelegate = parser.getAttributeValue(null,
+ ATTR_DELEGATED_CERT_INSTALLER);
+ if (certDelegate != null) {
+ List<String> scopes = policy.mDelegationMap.get(certDelegate);
+ if (scopes == null) {
+ scopes = new ArrayList<>();
+ policy.mDelegationMap.put(certDelegate, scopes);
+ }
+ if (!scopes.contains(DELEGATION_CERT_INSTALL)) {
+ scopes.add(DELEGATION_CERT_INSTALL);
+ needsRewrite = true;
+ }
+ }
+ final String appRestrictionsDelegate = parser.getAttributeValue(null,
+ ATTR_APPLICATION_RESTRICTIONS_MANAGER);
+ if (appRestrictionsDelegate != null) {
+ List<String> scopes = policy.mDelegationMap.get(appRestrictionsDelegate);
+ if (scopes == null) {
+ scopes = new ArrayList<>();
+ policy.mDelegationMap.put(appRestrictionsDelegate, scopes);
+ }
+ if (!scopes.contains(DELEGATION_APP_RESTRICTIONS)) {
+ scopes.add(DELEGATION_APP_RESTRICTIONS);
+ needsRewrite = true;
+ }
+ }
+ }
type = parser.next();
int outerDepth = parser.getDepth();
@@ -2600,6 +2663,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (RuntimeException e) {
Slog.w(LOG_TAG, "Failed loading admin " + name, e);
}
+ } else if ("delegation".equals(tag)) {
+ // Parse delegation info.
+ final String delegatePackage = parser.getAttributeValue(null,
+ "delegatePackage");
+ final String scope = parser.getAttributeValue(null, "scope");
+
+ // Get a reference to the scopes list for the delegatePackage.
+ List<String> scopes = policy.mDelegationMap.get(delegatePackage);
+ // Or make a new list if none was found.
+ if (scopes == null) {
+ scopes = new ArrayList<>();
+ policy.mDelegationMap.put(delegatePackage, scopes);
+ }
+ // Add the new scope to the list of delegatePackage if it's not already there.
+ if (!scopes.contains(scope)) {
+ scopes.add(scope);
+ }
} else if ("failed-password-attempts".equals(tag)) {
policy.mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
@@ -4522,9 +4602,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void enforceCanManageCaCerts(ComponentName who) {
+ public void enforceCanManageCaCerts(ComponentName who, String callerPackage) {
if (who == null) {
- if (!isCallerDelegatedCertInstaller()) {
+ if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
}
} else {
@@ -4538,35 +4618,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private void enforceCanManageInstalledKeys(ComponentName who) {
- if (who == null) {
- if (!isCallerDelegatedCertInstaller()) {
- throw new SecurityException("who == null, but caller is not cert installer");
- }
- } else {
- enforceProfileOrDeviceOwner(who);
- }
- }
-
- private boolean isCallerDelegatedCertInstaller() {
- final int callingUid = mInjector.binderGetCallingUid();
- final int userHandle = UserHandle.getUserId(callingUid);
- synchronized (this) {
- final DevicePolicyData policy = getUserData(userHandle);
- if (policy.mDelegatedCertInstallerPackage == null) {
- return false;
- }
-
- try {
- int uid = mInjector.getPackageManager().getPackageUidAsUser(
- policy.mDelegatedCertInstallerPackage, userHandle);
- return uid == callingUid;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
- }
-
@Override
public boolean approveCaCert(String alias, int userId, boolean approval) {
enforceManageUsers();
@@ -4608,8 +4659,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
- enforceCanManageCaCerts(admin);
+ public boolean installCaCert(ComponentName admin, String callerPackage, byte[] certBuffer)
+ throws RemoteException {
+ enforceCanManageCaCerts(admin, callerPackage);
byte[] pemCert;
try {
@@ -4651,8 +4703,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void uninstallCaCerts(ComponentName admin, String[] aliases) {
- enforceCanManageCaCerts(admin);
+ public void uninstallCaCerts(ComponentName admin, String callerPackage, String[] aliases) {
+ enforceCanManageCaCerts(admin, callerPackage);
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
final long id = mInjector.binderClearCallingIdentity();
@@ -4676,9 +4728,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, byte[] chain,
- String alias, boolean requestAccess) {
- enforceCanManageInstalledKeys(who);
+ public boolean installKeyPair(ComponentName who, String callerPackage, byte[] privKey,
+ byte[] cert, byte[] chain, String alias, boolean requestAccess) {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_CERT_INSTALL);
+
final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
@@ -4709,8 +4763,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean removeKeyPair(ComponentName who, String alias) {
- enforceCanManageInstalledKeys(who);
+ public boolean removeKeyPair(ComponentName who, String callerPackage, String alias) {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_CERT_INSTALL);
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
final long id = Binder.clearCallingIdentity();
@@ -4795,36 +4850,271 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}.execute();
}
+ /**
+ * Set the scopes of a device owner or profile owner delegate.
+ *
+ * @param who the device owner or profile owner.
+ * @param delegatePackage the name of the delegate package.
+ * @param scopes the list of delegation scopes to be given to the delegate package.
+ */
@Override
- public void setCertInstallerPackage(ComponentName who, String installerPackage)
- throws SecurityException {
- int userHandle = UserHandle.getCallingUserId();
+ public void setDelegatedScopes(ComponentName who, String delegatePackage,
+ List<String> scopes) throws SecurityException {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkStringNotEmpty(delegatePackage, "Delegate package is null or empty");
+ Preconditions.checkCollectionElementsNotNull(scopes, "Scopes");
+ // Remove possible duplicates.
+ scopes = new ArrayList(new ArraySet(scopes));
+ // Ensure given scopes are valid.
+ if (scopes.retainAll(Arrays.asList(DELEGATIONS))) {
+ throw new IllegalArgumentException("Unexpected delegation scopes");
+ }
+
+ // Retrieve the user ID of the calling process.
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
+ // Ensure calling process is device/profile owner.
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- if (getTargetSdk(who.getPackageName(), userHandle) >= Build.VERSION_CODES.N) {
- if (installerPackage != null &&
- !isPackageInstalledForUser(installerPackage, userHandle)) {
- throw new IllegalArgumentException("Package " + installerPackage
+ // Ensure the delegate is installed (skip this for DELEGATION_CERT_INSTALL in pre-N).
+ if (scopes.size() == 1 && scopes.get(0).equals(DELEGATION_CERT_INSTALL) ||
+ getTargetSdk(who.getPackageName(), userId) >= Build.VERSION_CODES.N) {
+ // Throw when the delegate package is not installed.
+ if (!isPackageInstalledForUser(delegatePackage, userId)) {
+ throw new IllegalArgumentException("Package " + delegatePackage
+ " is not installed on the current user");
}
}
- DevicePolicyData policy = getUserData(userHandle);
- policy.mDelegatedCertInstallerPackage = installerPackage;
- saveSettingsLocked(userHandle);
+
+ // Set the new delegate in user policies.
+ final DevicePolicyData policy = getUserData(userId);
+ if (!scopes.isEmpty()) {
+ policy.mDelegationMap.put(delegatePackage, new ArrayList<>(scopes));
+ } else {
+ // Remove any delegation info if the given scopes list is empty.
+ policy.mDelegationMap.remove(delegatePackage);
+ }
+
+ // Notify delegate package of updates.
+ final Intent intent = new Intent(
+ DevicePolicyManager.ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED);
+ // Only call receivers registered with Context#registerReceiver (don’t wake delegate).
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ // Limit components this intent resolves to to the delegate package.
+ intent.setPackage(delegatePackage);
+ // Include the list of delegated scopes as an extra.
+ intent.putStringArrayListExtra(DevicePolicyManager.EXTRA_DELEGATION_SCOPES,
+ (ArrayList<String>) scopes);
+ // Send the broadcast.
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+
+ // Persist updates.
+ saveSettingsLocked(userId);
}
}
+ /**
+ * Get the delegation scopes given to a delegate package by a device owner or profile owner.
+ *
+ * A DO/PO can get the scopes of any package. A non DO/PO package can get its own scopes by
+ * passing in {@code null} as the {@code who} parameter and its own name as the
+ * {@code delegatepackage}.
+ *
+ * @param who the device owner or profile owner, or {@code null} if the caller is
+ * {@code delegatePackage}.
+ * @param delegatePackage the name of the delegate package whose scopes are to be retrieved.
+ * @return a list of the delegation scopes currently given to {@code delegatePackage}.
+ */
@Override
- public String getCertInstallerPackage(ComponentName who) throws SecurityException {
- int userHandle = UserHandle.getCallingUserId();
+ @NonNull
+ public List<String> getDelegatedScopes(ComponentName who,
+ String delegatePackage) throws SecurityException {
+ Preconditions.checkNotNull(delegatePackage, "Delegate package is null");
+
+ // Retrieve the user ID of the calling process.
+ final int callingUid = mInjector.binderGetCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ synchronized (this) {
+ // Ensure calling process is device/profile owner.
+ if (who != null) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Or ensure calling process is delegatePackage itself.
+ } else {
+ int uid = 0;
+ try {
+ uid = mInjector.getPackageManager()
+ .getPackageUidAsUser(delegatePackage, userId);
+ } catch(NameNotFoundException e) {
+ }
+ if (uid != callingUid) {
+ throw new SecurityException("Caller with uid " + callingUid + " is not "
+ + delegatePackage);
+ }
+ }
+ final DevicePolicyData policy = getUserData(userId);
+ // Retrieve the scopes assigned to delegatePackage, or null if no scope was given.
+ final List<String> scopes = policy.mDelegationMap.get(delegatePackage);
+ return scopes == null ? Collections.EMPTY_LIST : scopes;
+ }
+ }
+
+ /**
+ * Get a list of packages that were given a specific delegation scopes by a device owner or
+ * profile owner.
+ *
+ * @param who the device owner or profile owner.
+ * @param scope the scope whose delegates are to be retrieved.
+ * @return a list of the delegate packages currently given the {@code scope} delegation.
+ */
+ @NonNull
+ public List<String> getDelegatePackages(ComponentName who, String scope)
+ throws SecurityException {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkNotNull(scope, "Scope is null");
+ if (!Arrays.asList(DELEGATIONS).contains(scope)) {
+ throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
+ }
+
+ // Retrieve the user ID of the calling process.
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
+ // Ensure calling process is device/profile owner.
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- DevicePolicyData policy = getUserData(userHandle);
- return policy.mDelegatedCertInstallerPackage;
+ final DevicePolicyData policy = getUserData(userId);
+
+ // Create a list to hold the resulting delegate packages.
+ final List<String> delegatePackagesWithScope = new ArrayList<>();
+ // Add all delegations containing scope to the result list.
+ for (int i = 0; i < policy.mDelegationMap.size(); i++) {
+ if (policy.mDelegationMap.valueAt(i).contains(scope)) {
+ delegatePackagesWithScope.add(policy.mDelegationMap.keyAt(i));
+ }
+ }
+ return delegatePackagesWithScope;
+ }
+ }
+
+ /**
+ * Check whether a caller application has been delegated a given scope via
+ * {@link #setDelegatedScopes} to access privileged APIs on the behalf of a profile owner or
+ * device owner.
+ * <p>
+ * This is done by checking that {@code callerPackage} was granted {@code scope} delegation and
+ * then comparing the calling UID with the UID of {@code callerPackage} as reported by
+ * {@link PackageManager#getPackageUidAsUser}.
+ *
+ * @param callerPackage the name of the package that is trying to invoke a function in the DPMS.
+ * @param scope the delegation scope to be checked.
+ * @return {@code true} if the calling process is a delegate of {@code scope}.
+ */
+ private boolean isCallerDelegate(String callerPackage, String scope) {
+ Preconditions.checkNotNull(callerPackage, "callerPackage is null");
+ if (!Arrays.asList(DELEGATIONS).contains(scope)) {
+ throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
+ }
+
+ // Retrieve the UID and user ID of the calling process.
+ final int callingUid = mInjector.binderGetCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ synchronized (this) {
+ // Retrieve user policy data.
+ final DevicePolicyData policy = getUserData(userId);
+ // Retrieve the list of delegation scopes granted to callerPackage.
+ final List<String> scopes = policy.mDelegationMap.get(callerPackage);
+ // Check callingUid only if callerPackage has the required scope delegation.
+ if (scopes != null && scopes.contains(scope)) {
+ try {
+ // Retrieve the expected UID for callerPackage.
+ final int uid = mInjector.getPackageManager()
+ .getPackageUidAsUser(callerPackage, userId);
+ // Return true if the caller is actually callerPackage.
+ return uid == callingUid;
+ } catch (NameNotFoundException e) {
+ // Ignore.
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Throw a security exception if a ComponentName is given and it is not a device/profile owner
+ * or if the calling process is not a delegate of the given scope.
+ *
+ * @param who the device owner of profile owner, or null if {@code callerPackage} is a
+ * {@code scope} delegate.
+ * @param callerPackage the name of the calling package. Required if {@code who} is
+ * {@code null}.
+ * @param reqPolicy the policy used in the API whose access permission is being checked.
+ * @param scoppe the delegation scope corresponding to the API being checked.
+ * @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy};
+ * or when {@code who} is {@code null} and {@code callerPackage} is not a delegate
+ * of {@code scope}.
+ */
+ private void enforceCanManageScope(ComponentName who, String callerPackage, int reqPolicy,
+ String scope) {
+ // If a ComponentName is given ensure it is a device or profile owner according to policy.
+ if (who != null) {
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, reqPolicy);
+ }
+ // If no ComponentName is given ensure calling process has scope delegation.
+ } else if (!isCallerDelegate(callerPackage, scope)) {
+ throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid()
+ + " is not a delegate of scope " + scope + ".");
}
}
/**
+ * Helper function to preserve delegation behavior pre-O when using the deprecated functions
+ * {@code #setCertInstallerPackage} and {@code #setApplicationRestrictionsManagingPackage}.
+ */
+ private void setDelegatedScopePreO(ComponentName who,
+ String delegatePackage, String scope) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+ synchronized(this) {
+ // Ensure calling process is device/profile owner.
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final DevicePolicyData policy = getUserData(userId);
+
+ if (delegatePackage != null) {
+ // Set package as a delegate for scope if it is not already one.
+ List<String> scopes = policy.mDelegationMap.get(delegatePackage);
+ if (scopes == null) {
+ scopes = new ArrayList<>();
+ }
+ if (!scopes.contains(scope)) {
+ scopes.add(scope);
+ setDelegatedScopes(who, delegatePackage, scopes);
+ }
+ }
+
+ // Clear any existing scope delegates.
+ for (int i = 0; i < policy.mDelegationMap.size(); i++) {
+ final String currentPackage = policy.mDelegationMap.keyAt(i);
+ final List<String> currentScopes = policy.mDelegationMap.valueAt(i);
+
+ if (!currentPackage.equals(delegatePackage) && currentScopes.remove(scope)) {
+ setDelegatedScopes(who, currentPackage, currentScopes);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setCertInstallerPackage(ComponentName who, String installerPackage)
+ throws SecurityException {
+ setDelegatedScopePreO(who, installerPackage, DELEGATION_CERT_INSTALL);
+ }
+
+ @Override
+ public String getCertInstallerPackage(ComponentName who) throws SecurityException {
+ final List<String> delegatePackages = getDelegatePackages(who, DELEGATION_CERT_INSTALL);
+ return delegatePackages.size() > 0 ? delegatePackages.get(0) : null;
+ }
+
+ /**
* @return {@code true} if the package is installed and set as always-on, {@code false} if it is
* not installed and therefore not available.
*
@@ -4869,7 +5159,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private void wipeDataNoLock(boolean wipeExtRequested, String reason, boolean force) {
+ private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason) {
wtfIfInLock();
if (wipeExtRequested) {
@@ -4878,95 +5168,88 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
sm.wipeAdoptableDisks();
}
try {
- RecoverySystem.rebootWipeUserData(mContext, false /* shutdown */, reason, force);
+ mInjector.recoverySystemRebootWipeUserData(
+ /*shutdown=*/ false, reason, /*force=*/ true);
} catch (IOException | SecurityException e) {
Slog.w(LOG_TAG, "Failed requesting data wipe", e);
}
}
+ private void forceWipeUser(int userId) {
+ try {
+ IActivityManager am = mInjector.getIActivityManager();
+ if (am.getCurrentUser().id == userId) {
+ am.switchUser(UserHandle.USER_SYSTEM);
+ }
+
+ boolean userRemoved = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
+ if (!userRemoved) {
+ Slog.w(LOG_TAG, "Couldn't remove user " + userId);
+ } else if (isManagedProfile(userId)) {
+ sendWipeProfileNotification();
+ }
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ }
+ }
+
@Override
public void wipeData(int flags) {
if (!mHasFeature) {
return;
}
- final int userHandle = mInjector.userHandleGetCallingUserId();
- enforceFullCrossUsersPermission(userHandle);
+ enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
- final String source;
+ final ActiveAdmin admin;
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
- DeviceAdminInfo.USES_POLICY_WIPE_DATA);
- source = admin.info.getComponent().flattenToShortString();
-
- long ident = mInjector.binderClearCallingIdentity();
- try {
- final String restriction;
- if (userHandle == UserHandle.USER_SYSTEM) {
- restriction = UserManager.DISALLOW_FACTORY_RESET;
- } else if (isManagedProfile(userHandle)) {
- restriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
- } else {
- restriction = UserManager.DISALLOW_REMOVE_USER;
- }
- if (isAdminAffectedByRestriction(
- admin.info.getComponent(), restriction, userHandle)) {
- throw new SecurityException("Cannot wipe data. " + restriction
- + " restriction is set for user " + userHandle);
- }
-
- if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
- if (!isDeviceOwner(admin.info.getComponent(), userHandle)) {
- throw new SecurityException(
- "Only device owner admins can set WIPE_RESET_PROTECTION_DATA");
- }
- PersistentDataBlockManager manager = (PersistentDataBlockManager)
- mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
- if (manager != null) {
- manager.wipe();
- }
- }
-
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA);
}
- final boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
- wipeDeviceNoLock(wipeExtRequested, userHandle,
- "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
+ String reason = "DevicePolicyManager.wipeData() from "
+ + admin.info.getComponent().flattenToShortString();
+ wipeDataNoLock(
+ admin.info.getComponent(), flags, reason, admin.getUserHandle().getIdentifier());
}
- private void wipeDeviceNoLock(
- boolean wipeExtRequested, final int userHandle, String reason, boolean force) {
+ private void wipeDataNoLock(ComponentName admin, int flags, String reason, int userId) {
wtfIfInLock();
long ident = mInjector.binderClearCallingIdentity();
try {
- // TODO If split user is enabled and the device owner is set in the primary user (rather
- // than system), we should probably trigger factory reset. Current code just remove
- // that user (but still clears FRP...)
- if (userHandle == UserHandle.USER_SYSTEM) {
- wipeDataNoLock(wipeExtRequested, reason, force);
+ // First check whether the admin is allowed to wipe the device/user/profile.
+ final String restriction;
+ if (userId == UserHandle.USER_SYSTEM) {
+ restriction = UserManager.DISALLOW_FACTORY_RESET;
+ } else if (isManagedProfile(userId)) {
+ restriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
} else {
- try {
- IActivityManager am = mInjector.getIActivityManager();
- if (am.getCurrentUser().id == userHandle) {
- am.switchUser(UserHandle.USER_SYSTEM);
- }
+ restriction = UserManager.DISALLOW_REMOVE_USER;
+ }
+ if (isAdminAffectedByRestriction(admin, restriction, userId)) {
+ throw new SecurityException("Cannot wipe data. " + restriction
+ + " restriction is set for user " + userId);
+ }
- boolean userRemoved = force
- ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
- : mUserManager.removeUser(userHandle);
- if (!userRemoved) {
- Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
- } else if (isManagedProfile(userHandle)) {
- sendWipeProfileNotification();
- }
- } catch (RemoteException re) {
- // Shouldn't happen
+ if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
+ if (!isDeviceOwner(admin, userId)) {
+ throw new SecurityException(
+ "Only device owner admins can set WIPE_RESET_PROTECTION_DATA");
+ }
+ PersistentDataBlockManager manager = (PersistentDataBlockManager)
+ mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+ if (manager != null) {
+ manager.wipe();
}
}
+
+ // TODO If split user is enabled and the device owner is set in the primary user
+ // (rather than system), we should probably trigger factory reset. Current code just
+ // removes that user (but still clears FRP...)
+ if (userId == UserHandle.USER_SYSTEM) {
+ forceWipeDeviceNoLock(/*wipeExtRequested=*/ (flags & WIPE_EXTERNAL_STORAGE) != 0,
+ reason);
+ } else {
+ forceWipeUser(userId);
+ }
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -5105,25 +5388,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ boolean wipeData = false;
+ ActiveAdmin strictestAdmin = null;
final long ident = mInjector.binderClearCallingIdentity();
try {
- boolean wipeData = false;
- int identifier = 0;
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
policy.mFailedPasswordAttempts++;
saveSettingsLocked(userHandle);
if (mHasFeature) {
- ActiveAdmin strictestAdmin = getAdminWithMinimumFailedPasswordsForWipeLocked(
+ strictestAdmin = getAdminWithMinimumFailedPasswordsForWipeLocked(
userHandle, /* parent */ false);
int max = strictestAdmin != null
? strictestAdmin.maximumFailedPasswordsForWipe : 0;
if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- // Wipe the user/profile associated with the policy that was violated. This
- // is not necessarily calling user: if the policy that fired was from a
- // managed profile rather than the main user profile, we wipe former only.
wipeData = true;
- identifier = strictestAdmin.getUserHandle().getIdentifier();
}
sendAdminCommandForLockscreenPoliciesLocked(
@@ -5131,14 +5410,33 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
}
- if (wipeData) {
- // Call without holding lock.
- wipeDeviceNoLock(false, identifier, "reportFailedPasswordAttempt()", false);
- }
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
+ if (wipeData && strictestAdmin != null) {
+ final int userId = strictestAdmin.getUserHandle().getIdentifier();
+ Slog.i(LOG_TAG, "Max failed password attempts policy reached for admin: "
+ + strictestAdmin.info.getComponent().flattenToShortString()
+ + ". Calling wipeData for user " + userId);
+
+ // Attempt to wipe the device/user/profile associated with the admin, as if the
+ // admin had called wipeData(). That way we can check whether the admin is actually
+ // allowed to wipe the device (e.g. a regular device admin shouldn't be able to wipe the
+ // device if the device owner has set DISALLOW_FACTORY_RESET, but the DO should be
+ // able to do so).
+ // IMPORTANT: Call without holding the lock to prevent deadlock.
+ try {
+ wipeDataNoLock(strictestAdmin.info.getComponent(),
+ /*flags=*/ 0,
+ /*reason=*/ "reportFailedPasswordAttempt()",
+ userId);
+ } catch (SecurityException e) {
+ Slog.w(LOG_TAG, "Failed to wipe user " + userId
+ + " after max failed password attempts reached.", e);
+ }
+ }
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
/*method strength*/ 1);
@@ -5854,8 +6152,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
intent.setComponent(mOwners.getDeviceOwnerComponent());
intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
- mContext.grantUriPermission(mOwners.getDeviceOwnerComponent().getPackageName(),
- bugreportUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ LocalServices.getService(ActivityManagerInternal.class)
+ .grantUriPermissionFromIntent(Process.SHELL_UID,
+ mOwners.getDeviceOwnerComponent().getPackageName(),
+ intent, mOwners.getDeviceOwnerUserId());
mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
}
} catch (FileNotFoundException e) {
@@ -6016,32 +6318,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void setKeepUninstalledPackages(ComponentName who, List<String> packageList) {
+ public void setKeepUninstalledPackages(ComponentName who, String callerPackage,
+ List<String> packageList) {
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
Preconditions.checkNotNull(packageList, "packageList is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- admin.keepUninstalledPackages = packageList;
+ // Ensure the caller is a DO or a keep uninstalled packages delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES);
+ // Get the device owner
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ // Set list of packages to be kept even if uninstalled.
+ deviceOwner.keepUninstalledPackages = packageList;
+ // Save settings.
saveSettingsLocked(userHandle);
+ // Notify package manager.
mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList);
}
}
@Override
- public List<String> getKeepUninstalledPackages(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public List<String> getKeepUninstalledPackages(ComponentName who, String callerPackage) {
if (!mHasFeature) {
return null;
}
// TODO In split system user mode, allow apps on user 0 to query the list
synchronized (this) {
- // Check if this is the device owner who is calling
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ // Ensure the caller is a DO or a keep uninstalled packages delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES);
return getKeepUninstalledPackagesLocked();
}
}
@@ -6110,7 +6418,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
// TODO Send to system too?
mContext.sendBroadcastAsUser(
- new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
+ new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED)
+ .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
UserHandle.of(userId));
} finally {
mInjector.binderRestoreCallingIdentity(ident);
@@ -6146,6 +6455,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private boolean isProfileOwnerPackage(String packageName, int userId) {
+ synchronized (this) {
+ return mOwners.hasProfileOwner(userId)
+ && mOwners.getProfileOwnerPackage(userId).equals(packageName);
+ }
+ }
+
public boolean isProfileOwner(ComponentName who, int userId) {
final ComponentName profileOwner = getProfileOwner(userId);
return who != null && who.equals(profileOwner);
@@ -6253,6 +6569,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
clearDeviceOwnerLocked(admin, deviceOwnerUserId);
removeActiveAdminLocked(deviceOwnerComponent, deviceOwnerUserId);
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(deviceOwnerUserId));
} finally {
mInjector.binderRestoreCallingIdentity(ident);
@@ -6387,13 +6704,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void clearUserPoliciesLocked(int userId) {
- // Reset some of the user-specific policies
- DevicePolicyData policy = getUserData(userId);
+ // Reset some of the user-specific policies.
+ final DevicePolicyData policy = getUserData(userId);
policy.mPermissionPolicy = DevicePolicyManager.PERMISSION_POLICY_PROMPT;
- policy.mDelegatedCertInstallerPackage = null;
- policy.mApplicationRestrictionsManagingPackage = null;
+ // Clear delegations.
+ policy.mDelegationMap.clear();
policy.mStatusBarDisabled = false;
policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
+ policy.mAffiliationIds.clear();
+ policy.mLockTaskPackages.clear();
saveSettingsLocked(userId);
try {
@@ -6975,66 +7294,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean setApplicationRestrictionsManagingPackage(ComponentName admin,
String packageName) {
- Preconditions.checkNotNull(admin, "ComponentName is null");
-
- final int userHandle = mInjector.userHandleGetCallingUserId();
- synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- if (packageName != null && !isPackageInstalledForUser(packageName, userHandle)) {
- return false;
- }
- DevicePolicyData policy = getUserData(userHandle);
- policy.mApplicationRestrictionsManagingPackage = packageName;
- saveSettingsLocked(userHandle);
- return true;
+ try {
+ setDelegatedScopePreO(admin, packageName, DELEGATION_APP_RESTRICTIONS);
+ } catch (IllegalArgumentException e) {
+ return false;
}
+ return true;
}
@Override
public String getApplicationRestrictionsManagingPackage(ComponentName admin) {
- Preconditions.checkNotNull(admin, "ComponentName is null");
-
- final int userHandle = mInjector.userHandleGetCallingUserId();
- synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- DevicePolicyData policy = getUserData(userHandle);
- return policy.mApplicationRestrictionsManagingPackage;
- }
+ final List<String> delegatePackages = getDelegatePackages(admin,
+ DELEGATION_APP_RESTRICTIONS);
+ return delegatePackages.size() > 0 ? delegatePackages.get(0) : null;
}
@Override
- public boolean isCallerApplicationRestrictionsManagingPackage() {
- final int callingUid = mInjector.binderGetCallingUid();
- final int userHandle = UserHandle.getUserId(callingUid);
- synchronized (this) {
- final DevicePolicyData policy = getUserData(userHandle);
- if (policy.mApplicationRestrictionsManagingPackage == null) {
- return false;
- }
-
- try {
- int uid = mInjector.getPackageManager().getPackageUidAsUser(
- policy.mApplicationRestrictionsManagingPackage, userHandle);
- return uid == callingUid;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
- }
-
- private void enforceCanManageApplicationRestrictions(ComponentName who) {
- if (who != null) {
- enforceProfileOrDeviceOwner(who);
- } else if (!isCallerApplicationRestrictionsManagingPackage()) {
- throw new SecurityException(
- "No admin component given, and caller cannot manage application restrictions "
- + "for other apps.");
- }
+ public boolean isCallerApplicationRestrictionsManagingPackage(String callerPackage) {
+ return isCallerDelegate(callerPackage, DELEGATION_APP_RESTRICTIONS);
}
@Override
- public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
- enforceCanManageApplicationRestrictions(who);
+ public void setApplicationRestrictions(ComponentName who, String callerPackage,
+ String packageName, Bundle settings) {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_APP_RESTRICTIONS);
final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
@@ -7724,8 +8008,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
- enforceCanManageApplicationRestrictions(who);
+ public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
+ String packageName) {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_APP_RESTRICTIONS);
final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
@@ -7740,12 +8026,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public String[] setPackagesSuspended(ComponentName who, String[] packageNames,
- boolean suspended) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public String[] setPackagesSuspended(ComponentName who, String callerPackage,
+ String[] packageNames, boolean suspended) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -7762,10 +8049,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean isPackageSuspended(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long id = mInjector.binderClearCallingIdentity();
@@ -7877,12 +8166,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean setApplicationHidden(ComponentName who, String packageName,
+ public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
boolean hidden) {
- Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -7899,11 +8189,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean isApplicationHidden(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public boolean isApplicationHidden(ComponentName who, String callerPackage,
+ String packageName) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -7920,12 +8212,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void enableSystemApp(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public void enableSystemApp(ComponentName who, String callerPackage, String packageName) {
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or an enable system app delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_ENABLE_SYSTEM_APP);
int userId = UserHandle.getCallingUserId();
long id = mInjector.binderClearCallingIdentity();
@@ -7955,12 +8246,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public int enableSystemAppWithIntent(ComponentName who, String callerPackage, Intent intent) {
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or an enable system app delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_ENABLE_SYSTEM_APP);
int userId = UserHandle.getCallingUserId();
long id = mInjector.binderClearCallingIdentity();
@@ -8059,12 +8349,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void setUninstallBlocked(ComponentName who, String packageName,
+ public void setUninstallBlocked(ComponentName who, String callerPackage, String packageName,
boolean uninstallBlocked) {
- Preconditions.checkNotNull(who, "ComponentName is null");
final int userId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a block uninstall delegate
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_BLOCK_UNINSTALL);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8280,18 +8571,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- /**
- * Sets which packages may enter lock task mode.
- *
- * <p>This function can only be called by the device owner or alternatively by the profile owner
- * in case the user is affiliated.
- *
- * @param packages The list of packages allowed to enter lock task mode.
- */
@Override
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkNotNull(packages, "packages is null");
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8314,48 +8598,48 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
updateLockTaskPackagesLocked(packages, userHandle);
}
- /**
- * This function returns the list of components allowed to start the task lock mode.
- */
+ private void maybeClearLockTaskPackagesLocked() {
+ final long ident = mInjector.binderClearCallingIdentity();
+ try {
+ final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ for (int i = 0; i < userInfos.size(); i++) {
+ int userId = userInfos.get(i).id;
+ final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
+ if (!lockTaskPackages.isEmpty() &&
+ !isUserAffiliatedWithDeviceLocked(userId)) {
+ Slog.d(LOG_TAG,
+ "User id " + userId + " not affiliated. Clearing lock task packages");
+ setLockTaskPackagesLocked(userId, Collections.<String>emptyList());
+ }
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ }
+
@Override
public String[] getLockTaskPackages(ComponentName who) {
Preconditions.checkNotNull(who, "ComponentName is null");
+
+ final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
- final List<String> packages = getLockTaskPackagesLocked(userHandle);
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isUserAffiliatedWithDeviceLocked(userHandle)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
+
+ final List<String> packages = getUserData(userHandle).mLockTaskPackages;
return packages.toArray(new String[packages.size()]);
}
}
- private List<String> getLockTaskPackagesLocked(int userHandle) {
- final DevicePolicyData policy = getUserData(userHandle);
- return policy.mLockTaskPackages;
- }
-
- /**
- * This function lets the caller know whether the given package is allowed to start the
- * lock task mode.
- * @param pkg The package to check
- */
@Override
public boolean isLockTaskPermitted(String pkg) {
- // Get current user's devicepolicy
- int uid = mInjector.binderGetCallingUid();
- int userHandle = UserHandle.getUserId(uid);
- DevicePolicyData policy = getUserData(userHandle);
+ final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- for (int i = 0; i < policy.mLockTaskPackages.size(); i++) {
- String lockTaskPackage = policy.mLockTaskPackages.get(i);
-
- // If the given package equals one of the packages stored our list,
- // we allow this package to start lock task mode.
- if (lockTaskPackage.equals(pkg)) {
- return true;
- }
- }
+ return getUserData(userHandle).mLockTaskPackages.contains(pkg);
}
- return false;
}
@Override
@@ -8678,18 +8962,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
if (profileOwner != null) {
- return createShowAdminSupportIntent(profileOwner, userId);
+ return DevicePolicyManagerService.this
+ .createShowAdminSupportIntent(profileOwner, userId);
}
final Pair<Integer, ComponentName> deviceOwner =
mOwners.getDeviceOwnerUserIdAndComponent();
if (deviceOwner != null && deviceOwner.first == userId) {
- return createShowAdminSupportIntent(deviceOwner.second, userId);
+ return DevicePolicyManagerService.this
+ .createShowAdminSupportIntent(deviceOwner.second, userId);
}
// We're not specifying the device admin because there isn't one.
if (useDefaultIfNoAdmin) {
- return createShowAdminSupportIntent(null, userId);
+ return DevicePolicyManagerService.this.createShowAdminSupportIntent(null, userId);
}
return null;
}
@@ -8717,11 +9003,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (enforcedByDo && enforcedByPo) {
// In this case, we'll show an admin support dialog that does not
// specify the admin.
- return createShowAdminSupportIntent(null, userId);
+ return DevicePolicyManagerService.this.createShowAdminSupportIntent(null, userId);
} else if (enforcedByPo) {
final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
if (profileOwner != null) {
- return createShowAdminSupportIntent(profileOwner, userId);
+ return DevicePolicyManagerService.this
+ .createShowAdminSupportIntent(profileOwner, userId);
}
// This could happen if another thread has changed the profile owner since we called
// getUserRestrictionSource
@@ -8730,7 +9017,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final Pair<Integer, ComponentName> deviceOwner
= mOwners.getDeviceOwnerUserIdAndComponent();
if (deviceOwner != null) {
- return createShowAdminSupportIntent(deviceOwner.second, deviceOwner.first);
+ return DevicePolicyManagerService.this
+ .createShowAdminSupportIntent(deviceOwner.second, deviceOwner.first);
}
// This could happen if another thread has changed the device owner since we called
// getUserRestrictionSource
@@ -8738,15 +9026,57 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return null;
}
+ }
+
+ private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
+ // This method is called with AMS lock held, so don't take DPMS lock
+ final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ intent.putExtra(Intent.EXTRA_USER_ID, userId);
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
- private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
- // This method is called with AMS lock held, so don't take DPMS lock
- final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
- intent.putExtra(Intent.EXTRA_USER_ID, userId);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return intent;
+ @Override
+ public Intent createAdminSupportIntent(String restriction) {
+ Preconditions.checkNotNull(restriction);
+ final int uid = mInjector.binderGetCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ Intent intent = null;
+ if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction) ||
+ DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) {
+ synchronized(this) {
+ final DevicePolicyData policy = getUserData(userId);
+ final int N = policy.mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ final ActiveAdmin admin = policy.mAdminList.get(i);
+ if ((admin.disableCamera &&
+ DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) ||
+ (admin.disableScreenCapture && DevicePolicyManager
+ .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction))) {
+ intent = createShowAdminSupportIntent(admin.info.getComponent(), userId);
+ break;
+ }
+ }
+ // For the camera, a device owner on a different user can disable it globally,
+ // so we need an additional check.
+ if (intent == null
+ && DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) {
+ final ActiveAdmin admin = getDeviceOwnerAdminLocked();
+ if (admin != null && admin.disableCamera) {
+ intent = createShowAdminSupportIntent(admin.info.getComponent(),
+ mOwners.getDeviceOwnerUserId());
+ }
+ }
+ }
+ } else {
+ // if valid, |restriction| can only be a user restriction
+ intent = mLocalService.createUserRestrictionSupportIntent(userId, restriction);
+ }
+ if (intent != null) {
+ intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, restriction);
}
+ return intent;
}
/**
@@ -8891,10 +9221,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void setPermissionPolicy(ComponentName admin, int policy) throws RemoteException {
+ public void setPermissionPolicy(ComponentName admin, String callerPackage, int policy)
+ throws RemoteException {
int userId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PERMISSION_GRANT);
DevicePolicyData userPolicy = getUserData(userId);
if (userPolicy.mPermissionPolicy != policy) {
userPolicy.mPermissionPolicy = policy;
@@ -8913,11 +9246,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean setPermissionGrantState(ComponentName admin, String packageName,
- String permission, int grantState) throws RemoteException {
+ public boolean setPermissionGrantState(ComponentName admin, String callerPackage,
+ String packageName, String permission, int grantState) throws RemoteException {
UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PERMISSION_GRANT);
long ident = mInjector.binderClearCallingIdentity();
try {
if (getTargetSdk(packageName, user.getIdentifier())
@@ -8957,12 +9292,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public int getPermissionGrantState(ComponentName admin, String packageName,
- String permission) throws RemoteException {
+ public int getPermissionGrantState(ComponentName admin, String callerPackage,
+ String packageName, String permission) throws RemoteException {
PackageManager packageManager = mInjector.getPackageManager();
UserHandle user = mInjector.binderGetCallingUserHandle();
- enforceProfileOwnerOrSystemUser(admin);
+ if (!isCallerWithSystemUid()) {
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, DELEGATION_PERMISSION_GRANT);
+ }
synchronized (this) {
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -9119,21 +9458,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final long ident = mInjector.binderClearCallingIdentity();
try {
final UserHandle callingUserHandle = UserHandle.of(callingUserId);
- if (mUserManager.hasUserRestriction(
- UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle)) {
- // The DO can initiate provisioning if the restriction was set by the DO.
- if (!isDeviceOwnerPackage(packageName, callingUserId)
- || isAdminAffectedByRestriction(mOwners.getDeviceOwnerComponent(),
- UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) {
- // Caller is not DO or the restriction was set by the system.
+ final ComponentName ownerAdmin = getOwnerComponent(packageName, callingUserId);
+ if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+ callingUserHandle)) {
+ // An admin can initiate provisioning if it has set the restriction.
+ if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
+ UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) {
return CODE_ADD_MANAGED_PROFILE_DISALLOWED;
}
}
-
- // TODO: Allow it if the caller is the DO? DO could just call removeUser() before
- // provisioning, so not strictly required...
- boolean canRemoveProfile = !mUserManager.hasUserRestriction(
- UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, callingUserHandle);
+ boolean canRemoveProfile = true;
+ if (mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ callingUserHandle)) {
+ // We can remove a profile if the admin itself has set the restriction.
+ if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
+ UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ callingUserId)) {
+ canRemoveProfile = false;
+ }
+ }
if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
return CODE_CANNOT_ADD_MANAGED_PROFILE;
}
@@ -9143,6 +9486,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return CODE_OK;
}
+ private ComponentName getOwnerComponent(String packageName, int userId) {
+ if (isDeviceOwnerPackage(packageName, userId)) {
+ return mOwners.getDeviceOwnerComponent();
+ }
+ if (isProfileOwnerPackage(packageName, userId)) {
+ return mOwners.getProfileOwnerComponent(userId);
+ }
+ return null;
+ }
+
private int checkManagedUserProvisioningPreCondition(int callingUserId) {
if (!hasFeatureManagedUsers()) {
return CODE_MANAGED_USERS_NOT_SUPPORTED;
@@ -9495,6 +9848,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// but as a result of that other users might become affiliated or un-affiliated.
maybePauseDeviceWideLoggingLocked();
maybeResumeDeviceWideLoggingLocked();
+ maybeClearLockTaskPackagesLocked();
}
}
@@ -9555,7 +9909,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean areAllUsersAffiliatedWithDeviceLocked() {
final long ident = mInjector.binderClearCallingIdentity();
try {
- final List<UserInfo> userInfos = mUserManager.getUsers();
+ final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
for (int i = 0; i < userInfos.size(); i++) {
int userId = userInfos.get(i).id;
if (!isUserAffiliatedWithDeviceLocked(userId)) {
@@ -9963,47 +10317,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return Collections.emptyList();
}
Preconditions.checkNotNull(admin);
- ArrayList<UserHandle> targetUsers = new ArrayList<>();
synchronized (this) {
- ActiveAdmin callingOwner = getActiveAdminForCallerLocked(
- admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
final int callingUserId = mInjector.userHandleGetCallingUserId();
- final boolean isCallerDeviceOwner = isDeviceOwner(callingOwner);
- final boolean isCallerManagedProfile = isManagedProfile(callingUserId);
- if ((!isCallerDeviceOwner && !isCallerManagedProfile)
- || !isUserAffiliatedWithDeviceLocked(callingUserId)) {
- return targetUsers;
- }
-
final long callingIdentity = mInjector.binderClearCallingIdentity();
try {
- String callingOwnerPackage = callingOwner.info.getComponent().getPackageName();
- for (int userId : mUserManager.getProfileIdsWithDisabled(callingUserId)) {
- if (userId == callingUserId) {
- continue;
+ ArrayList<UserHandle> targetUsers = new ArrayList<>();
+ if (!isDeviceOwner(admin, callingUserId)) {
+ // Profile owners can only bind to the device owner.
+ if (canUserBindToDeviceOwnerLocked(callingUserId)) {
+ targetUsers.add(UserHandle.of(mOwners.getDeviceOwnerUserId()));
}
-
- // We only allow the device owner and a managed profile owner to bind to each
- // other.
- if ((isCallerManagedProfile && userId == mOwners.getDeviceOwnerUserId())
- || (isCallerDeviceOwner && isManagedProfile(userId))) {
- String targetOwnerPackage = getOwnerPackageNameForUserLocked(userId);
-
- // Both must be the same package and be affiliated in order to bind.
- if (callingOwnerPackage.equals(targetOwnerPackage)
- && isUserAffiliatedWithDeviceLocked(userId)) {
+ } else {
+ // Caller is the device owner: Look for profile owners that it can bind to.
+ final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ for (int i = 0; i < userInfos.size(); i++) {
+ final int userId = userInfos.get(i).id;
+ if (userId != callingUserId && canUserBindToDeviceOwnerLocked(userId)) {
targetUsers.add(UserHandle.of(userId));
}
}
}
+
+ return targetUsers;
} finally {
mInjector.binderRestoreCallingIdentity(callingIdentity);
}
}
+ }
+
+ private boolean canUserBindToDeviceOwnerLocked(int userId) {
+ // There has to be a device owner, under another user id.
+ if (!mOwners.hasDeviceOwner() || userId == mOwners.getDeviceOwnerUserId()) {
+ return false;
+ }
+
+ // The user must have a profile owner that belongs to the same package as the device owner.
+ if (!mOwners.hasProfileOwner(userId) || !TextUtils.equals(
+ mOwners.getDeviceOwnerPackageName(), mOwners.getProfileOwnerPackage(userId))) {
+ return false;
+ }
- return targetUsers;
+ // The user must be affiliated.
+ return isUserAffiliatedWithDeviceLocked(userId);
}
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 7d6841248dcd..9b4de043a647 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -16,12 +16,15 @@
package com.android.server.devicepolicy;
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.NetworkEvent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -42,11 +45,26 @@ final class NetworkLoggingHandler extends Handler {
// If this value changes, update DevicePolicyManager#retrieveNetworkLogs() javadoc
private static final int MAX_EVENTS_PER_BATCH = 1200;
private static final long BATCH_FINALIZATION_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(90);
+ private static final long BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS =
+ TimeUnit.MINUTES.toMillis(30);
- static final int LOG_NETWORK_EVENT_MSG = 1;
- static final int FINALIZE_BATCH_MSG = 2;
+ private static final String NETWORK_LOGGING_TIMEOUT_ALARM_TAG = "NetworkLogging.batchTimeout";
private final DevicePolicyManagerService mDpm;
+ private final AlarmManager mAlarmManager;
+
+ private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() {
+ @Override
+ public void onAlarm() {
+ Log.d(TAG, "Received a batch finalization timeout alarm, finalizing "
+ + mNetworkEvents.size() + " pending events.");
+ synchronized (NetworkLoggingHandler.this) {
+ finalizeBatchAndNotifyDeviceOwnerLocked();
+ }
+ }
+ };
+
+ static final int LOG_NETWORK_EVENT_MSG = 1;
// threadsafe as it's Handler's thread confined
@GuardedBy("this")
@@ -68,6 +86,7 @@ final class NetworkLoggingHandler extends Handler {
NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) {
super(looper);
mDpm = dpm;
+ mAlarmManager = mDpm.mInjector.getAlarmManager();
}
@Override
@@ -85,19 +104,19 @@ final class NetworkLoggingHandler extends Handler {
}
break;
}
- case FINALIZE_BATCH_MSG: {
- synchronized (NetworkLoggingHandler.this) {
- finalizeBatchAndNotifyDeviceOwnerLocked();
- }
+ default: {
+ Log.d(TAG, "NetworkLoggingHandler received an unknown of message.");
break;
}
}
}
void scheduleBatchFinalization() {
- removeMessages(FINALIZE_BATCH_MSG);
- sendMessageDelayed(obtainMessage(FINALIZE_BATCH_MSG), BATCH_FINALIZATION_TIMEOUT_MS);
- Log.d(TAG, "Scheduled new batch finalization " + BATCH_FINALIZATION_TIMEOUT_MS
+ final long when = SystemClock.elapsedRealtime() + BATCH_FINALIZATION_TIMEOUT_MS;
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,
+ BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS, NETWORK_LOGGING_TIMEOUT_ALARM_TAG,
+ mBatchTimeoutAlarmListener, this);
+ Log.d(TAG, "Scheduled a new batch finalization alarm " + BATCH_FINALIZATION_TIMEOUT_MS
+ "ms from now.");
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c3ef23b92fb4..83e209dd5bba 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.policy.EmergencyAffordanceManager;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.widget.ILockSettings;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
@@ -83,7 +84,6 @@ import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
-import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.OtaDexoptService;
@@ -100,6 +100,7 @@ import com.android.server.soundtrigger.SoundTriggerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
import com.android.server.telecom.TelecomLoaderService;
+import com.android.server.text.TextClassificationService;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.tv.TvRemoteService;
@@ -117,14 +118,20 @@ import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
import static android.view.Display.DEFAULT_DISPLAY;
public final class SystemServer {
private static final String TAG = "SystemServer";
+ // Tag for timing measurement of main thread.
+ private static final String SYSTEM_SERVER_TIMING_TAG = "SystemServerTiming";
+ // Tag for timing measurement of non-main asynchronous operations.
+ private static final String SYSTEM_SERVER_TIMING_ASYNC_TAG = SYSTEM_SERVER_TIMING_TAG + "Async";
+
private static final BootTimingsTraceLog BOOT_TIMINGS_TRACE_LOG
- = new BootTimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
+ = new BootTimingsTraceLog(SYSTEM_SERVER_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
private static final String ENCRYPTED_STATE = "1";
@@ -147,6 +154,8 @@ public final class SystemServer {
"com.android.server.voiceinteraction.VoiceInteractionManagerService";
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
+ private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
+ "com.android.server.print.CompanionDeviceManagerService";
private static final String USB_SERVICE_CLASS =
"com.android.server.usb.UsbService$Lifecycle";
private static final String MIDI_SERVICE_CLASS =
@@ -225,8 +234,11 @@ public final class SystemServer {
private boolean mFirstBoot;
private final boolean mRuntimeRestart;
+ private static final String START_SENSOR_SERVICE = "StartSensorService";
+ private Future<?> mSensorServiceStart;
+
/**
- * Start the sensor service.
+ * Start the sensor service. This is a blocking call and can take time.
*/
private static native void startSensorService();
@@ -380,7 +392,7 @@ public final class SystemServer {
MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
final int MAX_UPTIME_MILLIS = 60 * 1000;
if (uptimeMillis > MAX_UPTIME_MILLIS) {
- Slog.wtf("SystemServerTiming",
+ Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
"SystemServer init took too long. uptimeMillis=" + uptimeMillis);
}
}
@@ -454,6 +466,12 @@ public final class SystemServer {
* the other functions.
*/
private void startBootstrapServices() {
+ Slog.i(TAG, "Reading configuration...");
+ final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
+ traceBeginAndSlog(TAG_SYSTEM_CONFIG);
+ SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);
+ traceEnd();
+
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
@@ -576,9 +594,15 @@ public final class SystemServer {
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
- traceBeginAndSlog("StartSensorService");
- startSensorService();
- traceEnd();
+ // Start sensor service in a separate thread. Completion should be checked
+ // before using it.
+ mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
+ BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
+ SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceLog.traceBegin(START_SENSOR_SERVICE);
+ startSensorService();
+ traceLog.traceEnd();
+ }, START_SENSOR_SERVICE);
}
/**
@@ -664,11 +688,6 @@ public final class SystemServer {
}
try {
- Slog.i(TAG, "Reading configuration...");
- traceBeginAndSlog("ReadingSystemConfig");
- SystemConfig.getInstance();
- traceEnd();
-
traceBeginAndSlog("StartKeyAttestationApplicationIdProviderService");
ServiceManager.addService("sec_key_att_app_id_provider",
new KeyAttestationApplicationIdProviderService(context));
@@ -739,6 +758,9 @@ public final class SystemServer {
traceEnd();
traceBeginAndSlog("StartWindowManagerService");
+ // WMS needs sensor service ready
+ ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
+ mSensorServiceStart = null;
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
@@ -951,6 +973,12 @@ public final class SystemServer {
traceEnd();
}
+ if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartTextClassificationService");
+ mSystemServiceManager.startService(TextClassificationService.Lifecycle.class);
+ traceEnd();
+ }
+
if (!disableNetwork) {
traceBeginAndSlog("StartNetworkScoreService");
try {
@@ -1324,6 +1352,10 @@ public final class SystemServer {
traceEnd();
}
+ traceBeginAndSlog("StartCompanionDeviceManager");
+ mSystemServiceManager.startService(COMPANION_DEVICE_MANAGER_SERVICE_CLASS);
+ traceEnd();
+
traceBeginAndSlog("StartRestrictionManager");
mSystemServiceManager.startService(RestrictionsManagerService.class);
traceEnd();
@@ -1372,11 +1404,19 @@ public final class SystemServer {
traceEnd();
}
- traceBeginAndSlog("StartBackgroundDexOptService");
+ traceBeginAndSlog("StartBackgroundDexOptJobService");
+ try {
+ BackgroundDexOptJobService.schedule(context);
+ } catch (Throwable e) {
+ reportWtf("starting StartBackgroundDexOptJobService", e);
+ }
+ traceEnd();
+
+ traceBeginAndSlog("StartPruneInstantAppsJobService");
try {
- BackgroundDexOptService.schedule(context);
+ PruneInstantAppsJobService.schedule(context);
} catch (Throwable e) {
- reportWtf("starting BackgroundDexOptService", e);
+ reportWtf("StartPruneInstantAppsJobService", e);
}
traceEnd();
}
@@ -1565,11 +1605,19 @@ public final class SystemServer {
}
traceEnd();
+ // No dependency on Webview preparation in system server. But this should
+ // be completed before allowring 3rd party
+ final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
+ Future<?> webviewPrep = null;
if (!mOnlyCore) {
- Slog.i(TAG, "WebViewFactory preparation");
- traceBeginAndSlog("WebViewFactoryPreparation");
- mWebViewUpdateService.prepareWebViewInSystemServer();
- traceEnd();
+ webviewPrep = SystemServerInitThreadPool.get().submit(() -> {
+ Slog.i(TAG, WEBVIEW_PREPARATION);
+ BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
+ SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceLog.traceBegin(WEBVIEW_PREPARATION);
+ mWebViewUpdateService.prepareWebViewInSystemServer();
+ traceLog.traceEnd();
+ }, WEBVIEW_PREPARATION);
}
traceBeginAndSlog("StartSystemUI");
@@ -1629,6 +1677,10 @@ public final class SystemServer {
// It is now okay to let the various system services start their
// third party code...
traceBeginAndSlog("PhaseThirdPartyAppsCanStart");
+ // confirm webview completion before starting 3rd party
+ if (webviewPrep != null) {
+ ConcurrentUtils.waitForFutureNoInterrupt(webviewPrep, WEBVIEW_PREPARATION);
+ }
mSystemServiceManager.startBootPhase(
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
traceEnd();
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 83001df58023..0a907496ebdd 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -286,7 +286,8 @@ public class ApfFilter {
}
// Returns seconds since device boot.
- private static long curTime() {
+ @VisibleForTesting
+ protected long currentTimeSeconds() {
return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
}
@@ -450,7 +451,7 @@ public class ApfFilter {
}
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
- mLastSeen = curTime();
+ mLastSeen = currentTimeSeconds();
// Sanity check packet in case a packet arrives before we attach RA filter
// to our packet socket. b/29586253
@@ -580,7 +581,7 @@ public class ApfFilter {
// How many seconds does this RA's have to live, taking into account the fact
// that we might have seen it a while ago.
long currentLifetime() {
- return mMinLifetime - (curTime() - mLastSeen);
+ return mMinLifetime - (currentTimeSeconds() - mLastSeen);
}
boolean isExpired() {
@@ -946,7 +947,7 @@ public class ApfFilter {
Log.e(TAG, "Failed to generate APF program.", e);
return;
}
- mLastTimeInstalledProgram = curTime();
+ mLastTimeInstalledProgram = currentTimeSeconds();
mLastInstalledProgramMinLifetime = programMinLifetime;
mLastInstalledProgram = program;
mNumProgramUpdates++;
@@ -965,7 +966,7 @@ public class ApfFilter {
*/
private boolean shouldInstallnewProgram() {
long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
- return expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
+ return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
}
private void hexDump(String msg, byte[] packet, int length) {
@@ -999,7 +1000,7 @@ public class ApfFilter {
if (ra.matches(packet, length)) {
if (VDBG) log("matched RA " + ra);
// Update lifetimes.
- ra.mLastSeen = curTime();
+ ra.mLastSeen = currentTimeSeconds();
ra.mMinLifetime = ra.minLifetime(packet, length);
ra.seenCount++;
@@ -1128,7 +1129,7 @@ public class ApfFilter {
pw.println("Program updates: " + mNumProgramUpdates);
pw.println(String.format(
"Last program length %d, installed %ds ago, lifetime %ds",
- mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
+ mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
mLastInstalledProgramMinLifetime));
pw.println("RA filters:");
@@ -1137,7 +1138,7 @@ public class ApfFilter {
pw.println(ra);
pw.increaseIndent();
pw.println(String.format(
- "Seen: %d, last %ds ago", ra.seenCount, curTime() - ra.mLastSeen));
+ "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
if (DBG) {
pw.println("Last match:");
pw.increaseIndent();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index abdf6831b06c..76b1c90642ec 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -33,7 +33,7 @@ import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
@@ -398,7 +398,7 @@ public class IpManager extends StateMachine {
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
- private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final LocalLog mLocalLog;
private final LocalLog mConnectivityPacketLog;
private final MessageHandlingLogger mMsgStateLogger;
@@ -492,7 +492,7 @@ public class IpManager extends StateMachine {
mLinkProperties = new LinkProperties();
mLinkProperties.setInterfaceName(mInterfaceName);
- mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler(),
+ mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
() -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
@@ -527,7 +527,7 @@ public class IpManager extends StateMachine {
Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
- mAvoidBadWifiTracker.start();
+ mMultinetworkPolicyTracker.start();
}
@Override
@@ -538,7 +538,7 @@ public class IpManager extends StateMachine {
// Shut down this IpManager instance altogether.
public void shutdown() {
stop();
- mAvoidBadWifiTracker.shutdown();
+ mMultinetworkPolicyTracker.shutdown();
quit();
}
@@ -767,7 +767,7 @@ public class IpManager extends StateMachine {
// Note that we can still be disconnected by IpReachabilityMonitor
// if the IPv6 default gateway (but not the IPv6 DNS servers; see
// accompanying code in IpReachabilityMonitor) is unreachable.
- final boolean ignoreIPv6ProvisioningLoss = !mAvoidBadWifiTracker.currentValue();
+ final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
// Additionally:
//
@@ -1045,7 +1045,7 @@ public class IpManager extends StateMachine {
mCallback.onReachabilityLost(logMsg);
}
},
- mAvoidBadWifiTracker);
+ mMultinetworkPolicyTracker);
} catch (IllegalArgumentException iae) {
// Failed to start IpReachabilityMonitor. Log it and call
// onProvisioningFailure() immediately.
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index a883e28e96c6..20eac622d37f 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -34,7 +34,7 @@ import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -151,7 +151,7 @@ public class IpReachabilityMonitor {
private final String mInterfaceName;
private final int mInterfaceIndex;
private final Callback mCallback;
- private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final NetlinkSocketObserver mNetlinkSocketObserver;
private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -226,7 +226,7 @@ public class IpReachabilityMonitor {
}
public IpReachabilityMonitor(Context context, String ifName, Callback callback,
- AvoidBadWifiTracker tracker) throws IllegalArgumentException {
+ MultinetworkPolicyTracker tracker) throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
try {
@@ -238,7 +238,7 @@ public class IpReachabilityMonitor {
mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mCallback = callback;
- mAvoidBadWifiTracker = tracker;
+ mMultinetworkPolicyTracker = tracker;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
@@ -379,7 +379,7 @@ public class IpReachabilityMonitor {
}
private boolean avoidingBadLinks() {
- return (mAvoidBadWifiTracker != null) ? mAvoidBadWifiTracker.currentValue() : true;
+ return (mMultinetworkPolicyTracker == null) || mMultinetworkPolicyTracker.getAvoidBadWifi();
}
public void probeAll() {
diff --git a/services/net/java/android/net/util/AvoidBadWifiTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
index 2abaeb1ae35b..424e40d2096f 100644
--- a/services/net/java/android/net/util/AvoidBadWifiTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -29,10 +30,14 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
+import java.util.Arrays;
+import java.util.List;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
/**
* A class to encapsulate management of the "Smart Networking" capability of
@@ -42,8 +47,8 @@ import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
* This enables the device to switch to another form of connectivity, like
* mobile, if it's available and working.
*
- * The Runnable |cb|, if given, is called on the supplied Handler's thread
- * whether the computed "avoid bad wifi" value changes.
+ * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
+ * Handler' whenever the computed "avoid bad wifi" value changes.
*
* Disabling this reverts the device to a level of networking sophistication
* circa 2012-13 by disabling disparate code paths each of which contribute to
@@ -51,28 +56,36 @@ import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
*
* @hide
*/
-public class AvoidBadWifiTracker {
- private static String TAG = AvoidBadWifiTracker.class.getSimpleName();
+public class MultinetworkPolicyTracker {
+ private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
private final Context mContext;
private final Handler mHandler;
private final Runnable mReevaluateRunnable;
- private final Uri mUri;
+ private final List<Uri> mSettingsUris;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true;
+ private volatile int mMeteredMultipathPreference;
- public AvoidBadWifiTracker(Context ctx, Handler handler) {
+ public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
}
- public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
+ public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
mContext = ctx;
mHandler = handler;
- mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
- mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+ mReevaluateRunnable = () -> {
+ if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
+ avoidBadWifiCallback.run();
+ }
+ updateMeteredMultipathPreference();
+ };
+ mSettingsUris = Arrays.asList(
+ Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+ Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -82,11 +95,14 @@ public class AvoidBadWifiTracker {
}
};
- update();
+ updateAvoidBadWifi();
+ updateMeteredMultipathPreference();
}
public void start() {
- mResolver.registerContentObserver(mUri, false, mSettingObserver);
+ for (Uri uri : mSettingsUris) {
+ mResolver.registerContentObserver(uri, false, mSettingObserver);
+ }
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -102,10 +118,14 @@ public class AvoidBadWifiTracker {
mContext.unregisterReceiver(mBroadcastReceiver);
}
- public boolean currentValue() {
+ public boolean getAvoidBadWifi() {
return mAvoidBadWifi;
}
+ public int getMeteredMultipathPreference() {
+ return mMeteredMultipathPreference;
+ }
+
/**
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
@@ -117,10 +137,10 @@ public class AvoidBadWifiTracker {
* Whether we should display a notification when wifi becomes unvalidated.
*/
public boolean shouldNotifyWifiUnvalidated() {
- return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
+ return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
}
- public String getSettingsValue() {
+ public String getAvoidBadWifiSetting() {
return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
}
@@ -129,13 +149,30 @@ public class AvoidBadWifiTracker {
mHandler.post(mReevaluateRunnable);
}
- public boolean update() {
- final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
+ public boolean updateAvoidBadWifi() {
+ final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
final boolean prev = mAvoidBadWifi;
mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
return mAvoidBadWifi != prev;
}
+ /**
+ * The default (device and carrier-dependent) value for metered multipath preference.
+ */
+ public int configMeteredMultipathPreference() {
+ return mContext.getResources().getInteger(
+ R.integer.config_networkMeteredMultipathPreference);
+ }
+
+ public void updateMeteredMultipathPreference() {
+ String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
+ try {
+ mMeteredMultipathPreference = Integer.parseInt(setting);
+ } catch (NumberFormatException e) {
+ mMeteredMultipathPreference = configMeteredMultipathPreference();
+ }
+ }
+
private class SettingObserver extends ContentObserver {
public SettingObserver() {
super(null);
@@ -148,7 +185,9 @@ public class AvoidBadWifiTracker {
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (!mUri.equals(uri)) return;
+ if (!mSettingsUris.contains(uri)) {
+ Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+ }
reevaluate();
}
}
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
new file mode 100644
index 000000000000..9824c1d12613
--- /dev/null
+++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.server.print;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.companion.AssociationRequest;
+import android.companion.ICompanionDeviceManager;
+import android.companion.ICompanionDeviceManagerService;
+import android.companion.IOnAssociateCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+//TODO move to own package!
+/** @hide */
+public class CompanionDeviceManagerService extends SystemService {
+
+ private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
+ "com.android.companiondevicemanager", ".DeviceDiscoveryService");
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "CompanionDeviceManagerService";
+
+ private final CompanionDeviceManagerImpl mImpl;
+
+ public CompanionDeviceManagerService(Context context) {
+ super(context);
+ mImpl = new CompanionDeviceManagerImpl();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
+ }
+
+ class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
+
+ @Override
+ public void associate(
+ AssociationRequest request,
+ IOnAssociateCallback callback,
+ String callingPackage) throws RemoteException {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
+ + ", callingPackage = " + callingPackage + ")");
+ }
+ checkNotNull(request);
+ checkNotNull(callback);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ //TODO bindServiceAsUser
+ getContext().bindService(
+ new Intent().setComponent(SERVICE_TO_BIND_TO),
+ getServiceConnection(request, callback, callingPackage),
+ Context.BIND_AUTO_CREATE);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+ }
+
+ private ServiceConnection getServiceConnection(
+ final AssociationRequest<?> request,
+ final IOnAssociateCallback callback,
+ final String callingPackage) {
+ return new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "onServiceConnected(name = " + name + ", service = "
+ + service + ")");
+ }
+ try {
+ ICompanionDeviceManagerService.Stub
+ .asInterface(service)
+ .startDiscovery(
+ request,
+ getCallback(callingPackage, callback),
+ callingPackage);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")");
+ }
+ };
+ }
+
+ private IOnAssociateCallback.Stub getCallback(
+ String callingPackage,
+ IOnAssociateCallback propagateTo) {
+ return new IOnAssociateCallback.Stub() {
+
+ @Override
+ public void onSuccess(PendingIntent launcher)
+ throws RemoteException {
+ if (DEBUG) Log.i(LOG_TAG, "onSuccess(launcher = " + launcher + ")");
+ recordSpecialPriviledgesForPackage(callingPackage);
+ propagateTo.onSuccess(launcher);
+ }
+
+ @Override
+ public void onFailure(CharSequence reason) throws RemoteException {
+ if (DEBUG) Log.i(LOG_TAG, "onFailure()");
+ propagateTo.onFailure(reason);
+ }
+ };
+ }
+
+ void recordSpecialPriviledgesForPackage(String priviledgedPackage) {
+ //TODO Show dialog before recording notification access
+// final SettingStringHelper setting =
+// new SettingStringHelper(
+// getContext().getContentResolver(),
+// Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+// Binder.getCallingUid());
+// setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage));
+ }
+}
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 785c3fa7ed5b..f943ee2c09bf 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -58,6 +58,7 @@ import android.os.UserManager;
import android.provider.CallLog;
import android.provider.MediaStore;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Slog;
import com.android.internal.os.BackgroundThread;
@@ -105,7 +106,8 @@ public class RetailDemoModeService extends SystemService {
private static final String DEMO_SESSION_COUNT = "retail_demo_session_count";
private static final String DEMO_SESSION_DURATION = "retail_demo_session_duration";
- boolean mDeviceInDemoMode = false;
+ boolean mDeviceInDemoMode;
+ boolean mIsCarrierDemoMode;
int mCurrentUserId = UserHandle.USER_SYSTEM;
long mUserInactivityTimeout;
long mWarningDialogTimeout;
@@ -135,7 +137,8 @@ public class RetailDemoModeService extends SystemService {
if (!mDeviceInDemoMode) {
return;
}
- switch (intent.getAction()) {
+ final String action = intent.getAction();
+ switch (action) {
case Intent.ACTION_SCREEN_OFF:
mHandler.removeMessages(MSG_TURN_SCREEN_ON);
mHandler.sendEmptyMessageDelayed(MSG_TURN_SCREEN_ON, SCREEN_WAKEUP_DELAY);
@@ -166,7 +169,7 @@ public class RetailDemoModeService extends SystemService {
mInjector.acquireWakeLock();
break;
case MSG_INACTIVITY_TIME_OUT:
- if (isDemoLauncherDisabled()) {
+ if (!mIsCarrierDemoMode && isDemoLauncherDisabled()) {
Slog.i(TAG, "User inactivity timeout reached");
showInactivityCountdownDialog();
}
@@ -177,12 +180,30 @@ public class RetailDemoModeService extends SystemService {
}
removeMessages(MSG_START_NEW_SESSION);
removeMessages(MSG_INACTIVITY_TIME_OUT);
- if (mCurrentUserId != UserHandle.USER_SYSTEM) {
+ if (!mIsCarrierDemoMode && mCurrentUserId != UserHandle.USER_SYSTEM) {
logSessionDuration();
}
- final UserInfo demoUser = mInjector.getUserManager().createUser(DEMO_USER_NAME,
- UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
- if (demoUser != null) {
+
+ final UserManager um = mInjector.getUserManager();
+ UserInfo demoUser = null;
+ if (mIsCarrierDemoMode) {
+ // Re-use the existing demo user in carrier demo mode.
+ for (UserInfo user : um.getUsers()) {
+ if (user.isDemo()) {
+ demoUser = user;
+ break;
+ }
+ }
+ }
+
+ if (demoUser == null) {
+ // User in carrier demo mode should survive reboots.
+ final int flags = UserInfo.FLAG_DEMO
+ | (mIsCarrierDemoMode ? 0 : UserInfo.FLAG_EPHEMERAL);
+ demoUser = um.createUser(DEMO_USER_NAME, flags);
+ }
+
+ if (demoUser != null && mCurrentUserId != demoUser.id) {
setupDemoUser(demoUser);
mInjector.switchUser(demoUser.id);
}
@@ -211,7 +232,7 @@ public class RetailDemoModeService extends SystemService {
}
public void register() {
- ContentResolver cr = mInjector.getContentResolver();
+ final ContentResolver cr = mInjector.getContentResolver();
cr.registerContentObserver(mDeviceDemoModeUri, false, this, UserHandle.USER_SYSTEM);
cr.registerContentObserver(mDeviceProvisionedUri, false, this, UserHandle.USER_SYSTEM);
cr.registerContentObserver(mRetailDemoConstantsUri, false, this,
@@ -224,29 +245,27 @@ public class RetailDemoModeService extends SystemService {
refreshTimeoutConstants();
return;
}
- if (mDeviceDemoModeUri.equals(uri)) {
- mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
- if (mDeviceInDemoMode) {
+
+ // If device is provisioned and left demo mode - run the cleanup in demo folder
+ if (isDeviceProvisioned()) {
+ if (UserManager.isDeviceInDemoMode(getContext())) {
startDemoMode();
} else {
mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
- if (mInjector.isWakeLockHeld()) {
- mInjector.releaseWakeLock();
- }
- }
- }
- // If device is provisioned and left demo mode - run the cleanup in demo folder
- if (!mDeviceInDemoMode && isDeviceProvisioned()) {
- // Run on the bg thread to not block the fg thread
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
+
+ // Run on the bg thread to not block the fg thread
+ BackgroundThread.getHandler().post(() -> {
if (!deletePreloadsFolderContents()) {
Slog.w(TAG, "Failed to delete preloads folder contents");
}
+ });
+
+ stopDemoMode();
+
+ if (mInjector.isWakeLockHeld()) {
+ mInjector.releaseWakeLock();
}
- });
- stopDemoMode();
+ }
}
}
@@ -300,23 +319,22 @@ public class RetailDemoModeService extends SystemService {
}
boolean isDemoLauncherDisabled() {
- IPackageManager pm = mInjector.getIPackageManager();
int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
- String demoLauncherComponent = getContext().getResources()
- .getString(R.string.config_demoModeLauncherComponent);
try {
- enabledState = pm.getComponentEnabledSetting(
- ComponentName.unflattenFromString(demoLauncherComponent),
- mCurrentUserId);
- } catch (RemoteException exc) {
- Slog.e(TAG, "Unable to talk to Package Manager", exc);
+ final IPackageManager iPm = mInjector.getIPackageManager();
+ final String demoLauncherComponent =
+ getContext().getString(R.string.config_demoModeLauncherComponent);
+ enabledState = iPm.getComponentEnabledSetting(
+ ComponentName.unflattenFromString(demoLauncherComponent), mCurrentUserId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Error retrieving demo launcher enabled setting", re);
}
return enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
private void setupDemoUser(UserInfo userInfo) {
- UserManager um = mInjector.getUserManager();
- UserHandle user = UserHandle.of(userInfo.id);
+ final UserManager um = mInjector.getUserManager();
+ final UserHandle user = UserHandle.of(userInfo.id);
um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
@@ -327,6 +345,11 @@ public class RetailDemoModeService extends SystemService {
um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
// Disallow rebooting in safe mode - controlled by user 0
um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
+ if (mIsCarrierDemoMode) {
+ // Enable SMS in carrier demo mode.
+ um.setUserRestriction(UserManager.DISALLOW_SMS, false, user);
+ }
+
Settings.Secure.putIntForUser(mInjector.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
Settings.Global.putInt(mInjector.getContentResolver(),
@@ -334,6 +357,47 @@ public class RetailDemoModeService extends SystemService {
grantRuntimePermissionToCamera(user);
clearPrimaryCallLog();
+
+ if (!mIsCarrierDemoMode) {
+ // Enable demo launcher.
+ final String demoLauncher = getContext().getString(
+ R.string.config_demoModeLauncherComponent);
+ if (!TextUtils.isEmpty(demoLauncher)) {
+ final ComponentName componentToEnable =
+ ComponentName.unflattenFromString(demoLauncher);
+ final String packageName = componentToEnable.getPackageName();
+ try {
+ final IPackageManager iPm = AppGlobals.getPackageManager();
+ iPm.setComponentEnabledSetting(componentToEnable,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id);
+ iPm.setApplicationEnabledSetting(packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null);
+ } catch (RemoteException re) {
+ // Internal, shouldn't happen
+ }
+ }
+ } else {
+ // Set the carrier demo mode setting for the demo user.
+ final String carrierDemoModeSetting = getContext().getString(
+ R.string.config_carrierDemoModeSetting);
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ carrierDemoModeSetting, 1, userInfo.id);
+
+ // Enable packages for carrier demo mode.
+ final String packageList = getContext().getString(
+ R.string.config_carrierDemoModePackages);
+ final String[] packageNames = packageList == null ? new String[0]
+ : TextUtils.split(packageList, ",");
+ final IPackageManager iPm = AppGlobals.getPackageManager();
+ for (String packageName : packageNames) {
+ try {
+ iPm.setApplicationEnabledSetting(packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Error enabling application: " + packageName, re);
+ }
+ }
+ }
}
private void grantRuntimePermissionToCamera(UserHandle user) {
@@ -380,18 +444,43 @@ public class RetailDemoModeService extends SystemService {
private boolean deletePreloadsFolderContents() {
final File dir = mInjector.getDataPreloadsDirectory();
+ final File[] files = FileUtils.listFilesOrEmpty(dir);
+ final File fileCacheDirectory = mInjector.getDataPreloadsFileCacheDirectory();
Slog.i(TAG, "Deleting contents of " + dir);
- return FileUtils.deleteContents(dir);
+ boolean success = true;
+ for (File file : files) {
+ if (file.isFile()) {
+ if (!file.delete()) {
+ success = false;
+ Slog.w(TAG, "Cannot delete file " + file);
+ }
+ } else {
+ // Do not remove file_cache dir
+ if (!file.equals(fileCacheDirectory)) {
+ if (!FileUtils.deleteContentsAndDir(file)) {
+ success = false;
+ Slog.w(TAG, "Cannot delete dir and its content " + file);
+ }
+ } else {
+ Slog.i(TAG, "Skipping directory with file cache " + file);
+ }
+ }
+ }
+ return success;
}
private void registerBroadcastReceiver() {
- if (mBroadcastReceiver == null) {
- final IntentFilter filter = new IntentFilter();
+ if (mBroadcastReceiver != null) {
+ return;
+ }
+
+ final IntentFilter filter = new IntentFilter();
+ if (!mIsCarrierDemoMode) {
filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(ACTION_RESET_DEMO);
- mBroadcastReceiver = new IntentReceiver();
- getContext().registerReceiver(mBroadcastReceiver, filter);
}
+ filter.addAction(ACTION_RESET_DEMO);
+ mBroadcastReceiver = new IntentReceiver();
+ getContext().registerReceiver(mBroadcastReceiver, filter);
}
private void unregisterBroadcastReceiver() {
@@ -427,6 +516,8 @@ public class RetailDemoModeService extends SystemService {
}
private void startDemoMode() {
+ mDeviceInDemoMode = true;
+
mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
mInjector.initializeWakeLock();
if (mCameraIdsWithFlash == null) {
@@ -434,6 +525,12 @@ public class RetailDemoModeService extends SystemService {
}
registerBroadcastReceiver();
+ final String carrierDemoModeSetting =
+ getContext().getString(R.string.config_carrierDemoModeSetting);
+ mIsCarrierDemoMode = !TextUtils.isEmpty(carrierDemoModeSetting)
+ && (Settings.Secure.getInt(getContext().getContentResolver(),
+ carrierDemoModeSetting, 0) == 1);
+
mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
@@ -444,6 +541,8 @@ public class RetailDemoModeService extends SystemService {
}
private void stopDemoMode() {
+ mDeviceInDemoMode = false;
+ mIsCarrierDemoMode = false;
mPreloadAppsInstaller = null;
mCameraIdsWithFlash = null;
mInjector.destroyWakeLock();
@@ -471,13 +570,12 @@ public class RetailDemoModeService extends SystemService {
public void onBootPhase(int bootPhase) {
switch (bootPhase) {
case PHASE_THIRD_PARTY_APPS_CAN_START:
- SettingsObserver settingsObserver = new SettingsObserver(mHandler);
+ final SettingsObserver settingsObserver = new SettingsObserver(mHandler);
settingsObserver.register();
settingsObserver.refreshTimeoutConstants();
break;
case PHASE_BOOT_COMPLETED:
if (UserManager.isDeviceInDemoMode(getContext())) {
- mDeviceInDemoMode = true;
startDemoMode();
}
break;
@@ -497,33 +595,39 @@ public class RetailDemoModeService extends SystemService {
Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
return;
}
- if (!mInjector.isWakeLockHeld()) {
+ if (!mIsCarrierDemoMode && !mInjector.isWakeLockHeld()) {
mInjector.acquireWakeLock();
}
mCurrentUserId = userId;
mInjector.getActivityManagerInternal().updatePersistentConfigurationForUser(
mInjector.getSystemUsersConfiguration(), userId);
+
mInjector.turnOffAllFlashLights(mCameraIdsWithFlash);
muteVolumeStreams();
if (!mInjector.getWifiManager().isWifiEnabled()) {
mInjector.getWifiManager().setWifiEnabled(true);
}
+
// Disable lock screen for demo users.
mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId);
- mInjector.getNotificationManager().notifyAsUser(TAG,
- 1, mInjector.createResetNotification(), UserHandle.of(userId));
- synchronized (mActivityLock) {
- mUserUntouched = true;
- }
- mInjector.logSessionCount(1);
- mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mPreloadAppsInstaller.installApps(userId);
+ if (!mIsCarrierDemoMode) {
+ // Show reset notification (except in carrier demo mode).
+ mInjector.getNotificationManager().notifyAsUser(TAG,
+ 1, mInjector.createResetNotification(), UserHandle.of(userId));
+
+ synchronized (mActivityLock) {
+ mUserUntouched = true;
}
- });
+ mInjector.logSessionCount(1);
+ mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mPreloadAppsInstaller.installApps(userId);
+ }
+ });
+ }
}
private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
@@ -531,7 +635,7 @@ public class RetailDemoModeService extends SystemService {
@Override
public void onUserActivity() {
- if (!mDeviceInDemoMode) {
+ if (!mDeviceInDemoMode || mIsCarrierDemoMode) {
return;
}
long timeOfActivity = SystemClock.uptimeMillis();
@@ -682,7 +786,7 @@ public class RetailDemoModeService extends SystemService {
}
boolean isWakeLockHeld() {
- return mWakeLock.isHeld();
+ return mWakeLock != null && mWakeLock.isHeld();
}
void acquireWakeLock() {
@@ -738,6 +842,10 @@ public class RetailDemoModeService extends SystemService {
return Environment.getDataPreloadsDirectory();
}
+ File getDataPreloadsFileCacheDirectory() {
+ return Environment.getDataPreloadsFileCacheDirectory();
+ }
+
void publishLocalService(RetailDemoModeService service,
RetailDemoModeServiceInternal localService) {
service.publishLocalService(RetailDemoModeServiceInternal.class, localService);
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 468a26b57d7e..15f7557c92ef 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -20,7 +20,6 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import com.android.server.lights.Light;
-import com.android.server.statusbar.StatusBarManagerInternal;
import org.junit.Before;
import org.junit.Test;
@@ -67,7 +66,6 @@ public class BuzzBeepBlinkTest {
@Mock AudioManager mAudioManager;
@Mock Vibrator mVibrator;
@Mock android.media.IRingtonePlayer mRingtonePlayer;
- @Mock StatusBarManagerInternal mStatusBar;
@Mock Light mLight;
@Mock Handler mHandler;
@@ -85,6 +83,10 @@ public class BuzzBeepBlinkTest {
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
+ private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .build();
private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
private static final int CUSTOM_LIGHT_ON = 10000;
private static final int CUSTOM_LIGHT_OFF = 10000;
@@ -104,7 +106,6 @@ public class BuzzBeepBlinkTest {
mService.setVibrator(mVibrator);
mService.setSystemReady(true);
mService.setHandler(mHandler);
- mService.setStatusBarManager(mStatusBar);
mService.setLights(mLight);
mService.setScreenOn(false);
mService.setFallbackVibrationPattern(FALLBACK_VIBRATION);
@@ -200,10 +201,11 @@ public class BuzzBeepBlinkTest {
if (noisy) {
if (defaultSound) {
defaults |= Notification.DEFAULT_SOUND;
- channel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
+ channel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
} else {
builder.setSound(CUSTOM_SOUND);
- channel.setSound(CUSTOM_SOUND);
+ channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
}
}
if (buzzy) {
@@ -221,7 +223,7 @@ public class BuzzBeepBlinkTest {
} else {
builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
}
- channel.setLights(true);
+ channel.enableLights(true);
}
builder.setDefaults(defaults);
@@ -293,12 +295,12 @@ public class BuzzBeepBlinkTest {
}
private void verifyLights() {
- verify(mStatusBar, times(1)).notificationLightPulse(anyInt(), anyInt(), anyInt());
+ verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
}
private void verifyCustomLights() {
- verify(mStatusBar, times(1)).notificationLightPulse(
- eq(CUSTOM_LIGHT_COLOR), eq(CUSTOM_LIGHT_ON), eq(CUSTOM_LIGHT_OFF));
+ verify(mLight, times(1)).setFlashing(
+ eq(CUSTOM_LIGHT_COLOR), anyInt(), eq(CUSTOM_LIGHT_ON), eq(CUSTOM_LIGHT_OFF));
}
private Context getContext() {
@@ -330,17 +332,6 @@ public class BuzzBeepBlinkTest {
}
@Test
- public void testLightsFromChannel() throws Exception {
- NotificationRecord r = getQuietNotification();
- r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
- r.getChannel().setLights(true);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyLights();
- }
-
- @Test
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
@@ -350,16 +341,6 @@ public class BuzzBeepBlinkTest {
}
@Test
- public void testChannelNoOverwriteCustomLights() throws Exception {
- NotificationRecord r = getCustomLightsNotification();
- r.getChannel().setLights(true);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyCustomLights();
- }
-
- @Test
public void testNoInterruptionForMin() throws Exception {
NotificationRecord r = getBeepyNotification();
r.setImportance(NotificationManager.IMPORTANCE_MIN, "foo");
@@ -521,6 +502,8 @@ public class BuzzBeepBlinkTest {
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(FALLBACK_VIBRATION),
eq(-1), (AudioAttributes) anyObject());
+ verify(mRingtonePlayer, never()).playAsync
+ (anyObject(), anyObject(), anyBoolean(), anyObject());
}
@Test
@@ -557,7 +540,7 @@ public class BuzzBeepBlinkTest {
}
@Test
- public void testVibratTwice() throws Exception {
+ public void testVibrateTwice() throws Exception {
NotificationRecord r = getBuzzyNotification();
// set up internal state
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index aa08b41d69c0..064ab0a3adc4 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -112,6 +112,7 @@ public class NotificationComparatorTest {
Notification n2 = new Notification.Builder(mContext)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setColorized(true /* colorized */)
.build();
mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "highcall", callUid, callUid, n2,
@@ -186,10 +187,10 @@ public class NotificationComparatorTest {
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(mRecordHighCall);
expected.add(mRecordDefaultMedia);
- expected.add(mRecordStarredContact);
- expected.add(mRecordContact);
expected.add(mRecordInlineReply);
expected.add(mRecordSms);
+ expected.add(mRecordStarredContact);
+ expected.add(mRecordContact);
expected.add(mRecordEmail);
expected.add(mRecordUrgent);
expected.add(mRecordCheater);
@@ -207,14 +208,19 @@ public class NotificationComparatorTest {
@Test
public void testMessaging() throws Exception {
NotificationComparator comp = new NotificationComparator(mContext);
- assertTrue(comp.isImportantMessaging(mRecordStarredContact));
- assertTrue(comp.isImportantMessaging(mRecordContact));
assertTrue(comp.isImportantMessaging(mRecordInlineReply));
assertTrue(comp.isImportantMessaging(mRecordSms));
assertFalse(comp.isImportantMessaging(mRecordEmail));
assertFalse(comp.isImportantMessaging(mRecordCheater));
}
+ @Test
+ public void testPeople() throws Exception {
+ NotificationComparator comp = new NotificationComparator(mContext);
+ assertTrue(comp.isImportantPeople(mRecordStarredContact));
+ assertTrue(comp.isImportantPeople(mRecordContact));
+ }
+
private NotificationChannel getDefaultChannel() {
return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
NotificationManager.IMPORTANCE_LOW);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 92d9810f7c3f..db010b8bc99f 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -20,13 +20,12 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -42,39 +41,36 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
-import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Looper;
import android.os.MessageQueue;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.annotation.UiThreadTest;
import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.io.FileNotFoundException;
-import java.io.IOException;
+
import java.util.Arrays;
-import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
+
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-@SmallTest
-@RunWith(AndroidJUnit4.class)
public class NotificationManagerServiceTest {
+ private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
private final String pkg = "com.android.server.notification";
private final int uid = Binder.getCallingUid();
private NotificationManagerService mNotificationManagerService;
private INotificationManager mBinderService;
private IPackageManager mPackageManager = mock(IPackageManager.class);
+ final PackageManager mPackageManagerClient = mock(PackageManager.class);
private Context mContext;
private HandlerThread mThread;
+ final RankingHelper mRankingHelper = mock(RankingHelper.class);
@Before
+ @Test
@UiThreadTest
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
@@ -85,8 +81,7 @@ public class NotificationManagerServiceTest {
applicationInfo.uid = uid;
when(mPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
- final PackageManager mockPackageManagerClient = mock(PackageManager.class);
- when(mockPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
@@ -101,7 +96,7 @@ public class NotificationManagerServiceTest {
new ComponentName(pkg, "test_class"), uid, true, null, 0));
mNotificationManagerService.init(mThread.getLooper(), mPackageManager,
- mockPackageManagerClient, mockLightsManager, mockNotificationListeners);
+ mPackageManagerClient, mockLightsManager, mockNotificationListeners);
// Tests call directly into the Binder.
mBinderService = mNotificationManagerService.getBinderService();
@@ -109,6 +104,9 @@ public class NotificationManagerServiceTest {
public void waitForIdle() throws Exception {
MessageQueue queue = mThread.getLooper().getQueue();
+ if (queue.isIdle()) {
+ return;
+ }
CountDownLatch latch = new CountDownLatch(1);
queue.addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
@@ -116,24 +114,32 @@ public class NotificationManagerServiceTest {
return false;
}
});
- latch.await();
- if (!queue.isIdle()) {
- waitForIdle();
- }
+ // Timeout is valid in the cases where the queue goes idle before the IdleHandler
+ // is added.
+ latch.await(WAIT_FOR_IDLE_TIMEOUT, TimeUnit.SECONDS);
+ waitForIdle();
}
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
+ return generateNotificationRecord(channel, null);
+ }
+
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel,
+ Notification.TvExtender extender) {
if (channel == null) {
channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
}
- Notification n = new Notification.Builder(mContext)
+ Notification.Builder nb = new Notification.Builder(mContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setPriority(Notification.PRIORITY_HIGH)
- .build();
+ .setChannel(channel.getId())
+ .setPriority(Notification.PRIORITY_HIGH);
+ if (extender != null) {
+ nb.extend(extender);
+ }
StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(),
mContext.getPackageName(), 1, "tag", uid, 0,
- n, new UserHandle(uid), null, 0);
+ nb.build(), new UserHandle(uid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -217,10 +223,7 @@ public class NotificationManagerServiceTest {
NotificationChannel channel = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_HIGH);
NotificationRecord r = generateNotificationRecord(channel);
- NotificationManagerService.EnqueueNotificationRunnable enqueue =
- mNotificationManagerService.new EnqueueNotificationRunnable(UserHandle.USER_SYSTEM,
- r);
- assertTrue(enqueue.isBlocked(r, usageStats));
+ assertTrue(mNotificationManagerService.isBlocked(r, usageStats));
verify(usageStats, times(1)).registerSuspendedByAdmin(eq(r));
}
@@ -234,10 +237,7 @@ public class NotificationManagerServiceTest {
NotificationManager.IMPORTANCE_HIGH);
channel.setImportance(NotificationManager.IMPORTANCE_NONE);
NotificationRecord r = generateNotificationRecord(channel);
- NotificationManagerService.EnqueueNotificationRunnable enqueue =
- mNotificationManagerService.new EnqueueNotificationRunnable(UserHandle.USER_SYSTEM,
- r);
- assertTrue(enqueue.isBlocked(r, usageStats));
+ assertTrue(mNotificationManagerService.isBlocked(r, usageStats));
verify(usageStats, times(1)).registerBlocked(eq(r));
}
@@ -251,10 +251,7 @@ public class NotificationManagerServiceTest {
NotificationManager.IMPORTANCE_HIGH);
NotificationRecord r = generateNotificationRecord(channel);
r.setUserImportance(NotificationManager.IMPORTANCE_NONE);
- NotificationManagerService.EnqueueNotificationRunnable enqueue =
- mNotificationManagerService.new EnqueueNotificationRunnable(UserHandle.USER_SYSTEM,
- r);
- assertTrue(enqueue.isBlocked(r, usageStats));
+ assertTrue(mNotificationManagerService.isBlocked(r, usageStats));
verify(usageStats, times(1)).registerBlocked(eq(r));
}
@@ -364,14 +361,33 @@ public class NotificationManagerServiceTest {
@Test
@UiThreadTest
- public void testSnoozeNotificationImmediatelyAfterEnqueue() throws Exception {
- final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
- sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
- mBinderService.snoozeNotificationFromListener(null, sbn.getKey());
- waitForIdle();
- StatusBarNotification[] notifs =
- mBinderService.getActiveNotifications(sbn.getPackageName());
- assertEquals(0, notifs.length);
+ public void testTvExtenderChannelOverride_onTv() throws Exception {
+ mNotificationManagerService.setIsTelevision(true);
+ mNotificationManagerService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannelWithFallback(
+ anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
+ new NotificationChannel("foo", "foo", NotificationManager.IMPORTANCE_HIGH));
+
+ Notification.TvExtender tv = new Notification.TvExtender().setChannel("foo");
+ mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+ generateNotificationRecord(null, tv).getNotification(), new int[1], 0);
+ verify(mRankingHelper, times(1)).getNotificationChannelWithFallback(
+ anyString(), anyInt(), eq("foo"), anyBoolean());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testTvExtenderChannelOverride_notOnTv() throws Exception {
+ mNotificationManagerService.setIsTelevision(false);
+ mNotificationManagerService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannelWithFallback(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH));
+
+ Notification.TvExtender tv = new Notification.TvExtender().setChannel("foo");
+ mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+ generateNotificationRecord(null, tv).getNotification(), new int[1], 0);
+ verify(mRankingHelper, times(1)).getNotificationChannelWithFallback(
+ anyString(), anyInt(), eq("id"), anyBoolean());
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 15dcc266bbb7..13d6c5d774d6 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -16,7 +16,9 @@
package com.android.server.notification;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
@@ -31,6 +33,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.Color;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Build;
@@ -76,7 +79,6 @@ public class NotificationRecordTest {
final ApplicationInfo legacy = new ApplicationInfo();
final ApplicationInfo upgrade = new ApplicationInfo();
-
private static final long[] CUSTOM_VIBRATION = new long[] {
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
@@ -87,6 +89,8 @@ public class NotificationRecordTest {
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
+ private static final NotificationRecord.Light CUSTOM_LIGHT =
+ new NotificationRecord.Light(1, 2, 3);
@Before
public void setUp() {
@@ -105,7 +109,7 @@ public class NotificationRecordTest {
}
private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
- boolean buzzy, boolean defaultVibration) {
+ boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
final Builder builder = new Builder(mMockContext)
.setContentTitle("foo")
@@ -118,6 +122,7 @@ public class NotificationRecordTest {
defaults |= Notification.DEFAULT_SOUND;
} else {
builder.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
+ channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
}
}
if (buzzy) {
@@ -128,6 +133,18 @@ public class NotificationRecordTest {
channel.setVibrationPattern(CUSTOM_CHANNEL_VIBRATION);
}
}
+ if (lights) {
+ if (defaultLights) {
+ defaults |= Notification.DEFAULT_LIGHTS;
+ } else {
+ builder.setLights(CUSTOM_LIGHT.color, CUSTOM_LIGHT.onMs, CUSTOM_LIGHT.offMs);
+ channel.setLightColor(Color.BLUE);
+ }
+ channel.enableLights(true);
+ } else {
+ channel.enableLights(false);
+ }
+
builder.setDefaults(defaults);
if (!preO) {
builder.setChannel(channelId);
@@ -150,47 +167,55 @@ public class NotificationRecordTest {
@Test
public void testSound_default_preUpgradeUsesNotification() throws Exception {
- defaultChannel.setSound(null);
+ defaultChannel.setSound(null, null);
// pre upgrade, default sound.
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
+ assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
}
@Test
public void testSound_custom_preUpgradeUsesNotification() throws Exception {
- defaultChannel.setSound(null);
+ defaultChannel.setSound(null, null);
// pre upgrade, custom sound.
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_SOUND, record.getSound());
+ assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@Test
public void testSound_default_userLocked_preUpgrade() throws Exception {
- defaultChannel.setSound(CUSTOM_SOUND);
+ defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
// pre upgrade, default sound.
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_SOUND, record.getSound());
+ assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@Test
public void testSound_default_upgradeUsesChannel() throws Exception {
- channel.setSound(CUSTOM_SOUND);
+ channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
// post upgrade, default sound.
StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(CUSTOM_SOUND, record.getSound());
+ assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@Test
@@ -198,7 +223,8 @@ public class NotificationRecordTest {
defaultChannel.enableVibration(false);
// pre upgrade, default vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
- false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */);
+ false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertNotNull(record.getVibration());
@@ -209,7 +235,8 @@ public class NotificationRecordTest {
defaultChannel.enableVibration(false);
// pre upgrade, custom vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
- false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
+ false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertEquals(CUSTOM_VIBRATION, record.getVibration());
@@ -221,7 +248,8 @@ public class NotificationRecordTest {
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
// pre upgrade, custom vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
- false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
+ false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
@@ -232,58 +260,114 @@ public class NotificationRecordTest {
channel.enableVibration(true);
// post upgrade, custom vibration.
StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
- false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
+ false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
}
@Test
- public void testAudioAttributes_preUpgrade() throws Exception {
- defaultChannel.setSound(null);
- // pre upgrade, default sound.
+ public void testImportance_preUpgrade() throws Exception {
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
-
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
- assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
+ assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
}
@Test
- public void testAudioAttributes_upgrade() throws Exception {
- channel.setSound(null);
- // post upgrade, default sound.
+ public void testImportance_locked_preUpgrade() throws Exception {
+ defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+ defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
- assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
+ assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
}
@Test
- public void testImportance_preUpgrade() throws Exception {
+ public void testImportance_upgrade() throws Exception {
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
+ }
+
+ @Test
+ public void testLights_preUpgrade_noLight() throws Exception {
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
- assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
+ assertNull(record.getLight());
}
+
@Test
- public void testImportance_locked_preUpgrade() throws Exception {
- defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ public void testLights_preUpgrade() throws Exception {
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ true /* lights */, false /*defaultLights */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ assertEquals(CUSTOM_LIGHT, record.getLight());
+ }
+
+ @Test
+ public void testLights_locked_preUpgrade() throws Exception {
+ defaultChannel.enableLights(true);
+ defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
+ StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ true /* lights */, false /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
- assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
+ assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
}
@Test
- public void testImportance_upgrade() throws Exception {
+ public void testLights_upgrade_defaultLights() throws Exception {
+ int defaultLightColor = mMockContext.getResources().getColor(
+ com.android.internal.R.color.config_defaultNotificationColor);
+ int defaultLightOn = mMockContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOn);
+ int defaultLightOff = mMockContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOff);
+
+ NotificationRecord.Light expected = new NotificationRecord.Light(
+ defaultLightColor, defaultLightOn, defaultLightOff);
StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
- true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */);
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ true /* lights */, true /*defaultLights */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
+ assertEquals(expected, record.getLight());
+ }
+
+ @Test
+ public void testLights_upgrade() throws Exception {
+ int defaultLightOn = mMockContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOn);
+ int defaultLightOff = mMockContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOff);
+
+ NotificationRecord.Light expected = new NotificationRecord.Light(
+ Color.BLUE, defaultLightOn, defaultLightOff);
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ true /* lights */, false /*defaultLights */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ assertEquals(expected, record.getLight());
+ }
+
+ @Test
+ public void testLights_upgrade_noLight() throws Exception {
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /*defaultLights */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ assertNull(record.getLight());
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 0320d8acad74..e20b5715043d 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -30,12 +30,14 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.app.Notification;
+import android.app.NotificationChannelGroup;
import android.content.Context;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
+import android.graphics.Color;
+import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
@@ -66,9 +68,12 @@ import static org.mockito.Mockito.when;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RankingHelperTest {
- @Mock NotificationUsageStats mUsageStats;
- @Mock RankingHandler handler;
- @Mock PackageManager mPm;
+ @Mock
+ NotificationUsageStats mUsageStats;
+ @Mock
+ RankingHandler handler;
+ @Mock
+ PackageManager mPm;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
@@ -85,6 +90,7 @@ public class RankingHelperTest {
private final int uid = 0;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private AudioAttributes mAudioAttributes;
private Context getContext() {
return InstrumentationRegistry.getTargetContext();
@@ -96,7 +102,7 @@ public class RankingHelperTest {
UserHandle user = UserHandle.ALL;
mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats,
- new String[] {ImportanceExtractor.class.getName()});
+ new String[]{ImportanceExtractor.class.getName()});
mNotiGroupGSortA = new Notification.Builder(getContext())
.setContentTitle("A")
@@ -143,6 +149,12 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
+ mAudioAttributes = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+ .build();
+
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
final ApplicationInfo upgrade = new ApplicationInfo();
@@ -150,7 +162,8 @@ public class RankingHelperTest {
try {
when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
- } catch (PackageManager.NameNotFoundException e) {}
+ } catch (PackageManager.NameNotFoundException e) {
+ }
}
private NotificationChannel getDefaultChannel() {
@@ -186,6 +199,9 @@ public class RankingHelperTest {
assertEquals(expected.getSound(), actual.getSound());
assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
+ assertEquals(expected.getGroup(), actual.getGroup());
+ assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
+ assertEquals(expected.getLightColor(), actual.getLightColor());
}
@Test
@@ -240,17 +256,21 @@ public class RankingHelperTest {
@Test
public void testChannelXml() throws Exception {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("1", "2");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel2.setSound(new Uri.Builder().scheme("test").build());
- channel2.setLights(true);
+ channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel2.enableLights(true);
channel2.setBypassDnd(true);
channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel2.enableVibration(true);
- channel2.setVibrationPattern(new long[] {100, 67, 145, 156});
+ channel2.setGroup(ncg.getId());
+ channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
+ channel2.setLightColor(Color.BLUE);
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
mHelper.createNotificationChannel(pkg, uid, channel1, true);
mHelper.createNotificationChannel(pkg, uid, channel2, false);
@@ -274,6 +294,10 @@ public class RankingHelperTest {
mHelper.getNotificationChannel(pkg, uid, channel2.getId(), false));
assertNotNull(mHelper.getNotificationChannel(
pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false));
+ assertEquals(ncg.getId(),
+ mHelper.getNotificationChannelGroups(pkg, uid, false).getList().get(0).getId());
+ assertEquals(channel2.getGroup(), mHelper.getNotificationChannelGroups(
+ pkg, uid, false).getList().get(0).getChannels().get(0).getGroup());
}
@Test
@@ -296,13 +320,13 @@ public class RankingHelperTest {
pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
assertFalse(updated.canBypassDnd());
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,updated.getLockscreenVisibility());
+ assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
assertEquals(0, updated.getUserLockedFields());
}
@Test
public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
- NotificationChannel channel1 =
+ NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
mHelper.createNotificationChannel(pkg, uid, channel1, true);
@@ -327,15 +351,16 @@ public class RankingHelperTest {
@Test
public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
final String preupgradeXml = "<ranking version=\"1\">\n"
- + "<package name=\"" + pkg + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
- + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
- + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + uid + "\" />\n"
- + "<package name=\"" + pkg2 + "\" uid=\"" + uid2 + "\" visibility=\""
- + Notification.VISIBILITY_PRIVATE + "\" />\n"
- + "</ranking>";
+ + "<package name=\"" + pkg + "\" importance=\""
+ + NotificationManager.IMPORTANCE_HIGH
+ + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
+ + Notification.VISIBILITY_SECRET + "\"" + " uid=\"" + uid + "\" />\n"
+ + "<package name=\"" + pkg2 + "\" uid=\"" + uid2 + "\" visibility=\""
+ + Notification.VISIBILITY_PRIVATE + "\" />\n"
+ + "</ranking>";
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
- null);
+ null);
parser.nextTag();
mHelper.readXml(parser, false);
@@ -345,8 +370,8 @@ public class RankingHelperTest {
assertTrue(updated1.canBypassDnd());
assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
- | NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_VISIBILITY, updated1.getUserLockedFields());
+ | NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_VISIBILITY, updated1.getUserLockedFields());
final NotificationChannel updated2 = mHelper.getNotificationChannel(
pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -374,14 +399,14 @@ public class RankingHelperTest {
public void testUpdate_userLockedImportance() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
mHelper.createNotificationChannel(pkg, uid, channel, false);
// same id, try to update
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -393,7 +418,7 @@ public class RankingHelperTest {
public void testUpdate_userLockedVisibility() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
@@ -401,7 +426,7 @@ public class RankingHelperTest {
// same id, try to update
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -414,17 +439,17 @@ public class RankingHelperTest {
public void testUpdate_userLockedVibration() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setLights(false);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ channel.enableLights(false);
channel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
mHelper.createNotificationChannel(pkg, uid, channel, false);
// same id, try to update
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
channel2.enableVibration(true);
- channel2.setVibrationPattern(new long[] {100});
+ channel2.setVibrationPattern(new long[]{100});
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -436,16 +461,16 @@ public class RankingHelperTest {
public void testUpdate_userLockedLights() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setLights(false);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ channel.enableLights(false);
channel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
mHelper.createNotificationChannel(pkg, uid, channel, false);
// same id, try to update
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
- channel2.setLights(true);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ channel2.enableLights(true);
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -457,7 +482,7 @@ public class RankingHelperTest {
public void testUpdate_userLockedPriority() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
channel.setBypassDnd(true);
channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
@@ -465,7 +490,7 @@ public class RankingHelperTest {
// same id, try to update all fields
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
channel2.setBypassDnd(false);
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -478,16 +503,16 @@ public class RankingHelperTest {
public void testUpdate_userLockedRingtone() throws Exception {
// all fields locked by user
final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
mHelper.createNotificationChannel(pkg, uid, channel, false);
// same id, try to update all fields
final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
- channel2.setSound(new Uri.Builder().scheme("test2").build());
+ new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+ channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
@@ -519,8 +544,8 @@ public class RankingHelperTest {
// no fields locked by user
final NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
- channel.setLights(true);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel.enableLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
@@ -529,8 +554,8 @@ public class RankingHelperTest {
// same id, try to update all fields
final NotificationChannel channel2 =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
- channel2.setSound(new Uri.Builder().scheme("test2").build());
- channel2.setLights(false);
+ channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
+ channel2.enableLights(false);
channel2.setBypassDnd(false);
channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
@@ -551,8 +576,8 @@ public class RankingHelperTest {
public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
- channel.setLights(true);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel.enableLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
@@ -578,8 +603,8 @@ public class RankingHelperTest {
public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
- channel.setLights(true);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel.enableLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
@@ -605,12 +630,12 @@ public class RankingHelperTest {
public void testGetDeletedChannel() throws Exception {
NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
- channel.setLights(true);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel.enableLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.enableVibration(true);
- channel.setVibrationPattern(new long[] {100, 67, 145, 156});
+ channel.setVibrationPattern(new long[]{100, 67, 145, 156});
mHelper.createNotificationChannel(pkg, uid, channel, true);
mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
@@ -631,12 +656,12 @@ public class RankingHelperTest {
Map<String, NotificationChannel> channelMap = new HashMap<>();
NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setSound(new Uri.Builder().scheme("test").build());
- channel.setLights(true);
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel.enableLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
channel.enableVibration(true);
- channel.setVibrationPattern(new long[] {100, 67, 145, 156});
+ channel.setVibrationPattern(new long[]{100, 67, 145, 156});
channelMap.put(channel.getId(), channel);
NotificationChannel channel2 =
new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
@@ -657,7 +682,7 @@ public class RankingHelperTest {
}
// Returns deleted channels too
- channels = mHelper.getNotificationChannels(pkg, uid, true).getList();
+ channels = mHelper.getNotificationChannels(pkg, uid, true).getList();
assertEquals(3, channels.size()); // Includes default channel
for (NotificationChannel nc : channels) {
if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
@@ -674,7 +699,7 @@ public class RankingHelperTest {
mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
- channel.setSound(new Uri.Builder().scheme("test").build());
+ channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
try {
mHelper.updateNotificationChannel(pkg, uid, channel);
fail("Updated deleted channel");
@@ -692,7 +717,7 @@ public class RankingHelperTest {
@Test
public void testCreateDeletedChannel() throws Exception {
- long[] vibration = new long[] {100, 67, 145, 156};
+ long[] vibration = new long[]{100, 67, 145, 156};
NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
channel.setVibrationPattern(vibration);
@@ -702,7 +727,7 @@ public class RankingHelperTest {
NotificationChannel newChannel = new NotificationChannel(
channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
- newChannel.setVibrationPattern(new long[] {100});
+ newChannel.setVibrationPattern(new long[]{100});
mHelper.createNotificationChannel(pkg, uid, newChannel, true);
@@ -713,7 +738,7 @@ public class RankingHelperTest {
@Test
public void testCreateChannel_alreadyExists() throws Exception {
- long[] vibration = new long[] {100, 67, 145, 156};
+ long[] vibration = new long[]{100, 67, 145, 156};
NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
channel.setVibrationPattern(vibration);
@@ -722,7 +747,7 @@ public class RankingHelperTest {
NotificationChannel newChannel = new NotificationChannel(
channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
- newChannel.setVibrationPattern(new long[] {100});
+ newChannel.setVibrationPattern(new long[]{100});
mHelper.createNotificationChannel(pkg, uid, newChannel, true);
@@ -766,9 +791,113 @@ public class RankingHelperTest {
}
@Test
+ public void testOnPackageChanged_packageRemoval_importance() throws Exception {
+ mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_HIGH);
+
+ mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
+
+ assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid));
+ }
+
+ @Test
+ public void testOnPackageChanged_packageRemoval_groups() throws Exception {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+ NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true);
+
+ mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
+
+ assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size());
+ }
+
+ @Test
public void testRecordDefaults() throws Exception {
assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid));
assertEquals(true, mHelper.canShowBadge(pkg, uid));
assertEquals(1, mHelper.getNotificationChannels(pkg, uid, false).getList().size());
}
+
+ @Test
+ public void testCreateGroup() throws Exception {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+ assertEquals(ncg, mHelper.getNotificationChannelGroups(pkg, uid).iterator().next());
+ }
+
+ @Test
+ public void testCannotCreateChannel_badGroup() throws Exception {
+ NotificationChannel channel1 =
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel1.setGroup("garbage");
+ try {
+ mHelper.createNotificationChannel(pkg, uid, channel1, true);
+ fail("Created a channel with a bad group");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testCannotCreateChannel_goodGroup() throws Exception {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+ NotificationChannel channel1 =
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel1.setGroup(ncg.getId());
+ mHelper.createNotificationChannel(pkg, uid, channel1, true);
+
+ assertEquals(ncg.getId(),
+ mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false).getGroup());
+ }
+
+ @Test
+ public void testGetChannelGroups() throws Exception {
+ NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
+ mHelper.createNotificationChannelGroup(pkg, uid, unused, true);
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+ NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true);
+
+ NotificationChannel channel1 =
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel1.setGroup(ncg.getId());
+ mHelper.createNotificationChannel(pkg, uid, channel1, true);
+ NotificationChannel channel1a =
+ new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel1a.setGroup(ncg.getId());
+ mHelper.createNotificationChannel(pkg, uid, channel1a, true);
+
+ NotificationChannel channel2 =
+ new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel2.setGroup(ncg2.getId());
+ mHelper.createNotificationChannel(pkg, uid, channel2, true);
+
+ NotificationChannel channel3 =
+ new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(pkg, uid, channel3, true);
+
+ List<NotificationChannelGroup> actual =
+ mHelper.getNotificationChannelGroups(pkg, uid, true).getList();
+ assertEquals(3, actual.size());
+ for (NotificationChannelGroup group : actual) {
+ if (group.getId() == null) {
+ assertEquals(2, group.getChannels().size()); // misc channel too
+ assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
+ || channel3.getId().equals(group.getChannels().get(1).getId()));
+ } else if (group.getId().equals(ncg.getId())) {
+ assertEquals(2, group.getChannels().size());
+ if (group.getChannels().get(0).getId().equals(channel1.getId())) {
+ assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
+ } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
+ assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
+ } else {
+ fail("expected channel not found");
+ }
+ } else if (group.getId().equals(ncg2.getId())) {
+ assertEquals(1, group.getChannels().size());
+ assertEquals(channel2.getId(), group.getChannels().get(0).getId());
+ }
+ }
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index b7931d4f6a01..69724f48a111 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -33,6 +33,7 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -42,6 +43,7 @@ import static org.mockito.Matchers.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;
@SmallTest
@@ -190,6 +192,39 @@ public class SnoozeHelperTest {
verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
}
+ @Test
+ public void testGetSnoozedByUser() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+ NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ mSnoozeHelper.snooze(r3, 1000);
+ mSnoozeHelper.snooze(r4, 1000);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+ new int[] {UserHandle.USER_SYSTEM});
+ assertEquals(3, mSnoozeHelper.getSnoozed().size());
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+ new int[] {UserHandle.USER_CURRENT});
+ assertEquals(1, mSnoozeHelper.getSnoozed().size());
+ }
+
+ @Test
+ public void testGetSnoozedByUser_managedProfiles() throws Exception {
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+ new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT});
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+ NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ mSnoozeHelper.snooze(r3, 1000);
+ mSnoozeHelper.snooze(r4, 1000);
+ assertEquals(4, mSnoozeHelper.getSnoozed().size());
+ }
+
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
UserHandle user) {
Notification n = new Notification.Builder(getContext())
diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
new file mode 100644
index 000000000000..c89d35c1d84e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.IProgressListener;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.os.storage.IStorageManager;
+import android.security.KeyStore;
+import android.service.gatekeeper.GateKeeperResponse;
+import android.service.gatekeeper.IGateKeeperService;
+import android.test.AndroidTestCase;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.VerifyCredentialResponse;
+import com.android.server.LockSettingsService.SynchronizedStrongAuthTracker;
+import com.android.server.LockSettingsStorage.CredentialHash;
+import com.android.server.MockGateKeeperService.AuthToken;
+import com.android.server.MockGateKeeperService.VerifyHandle;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.util.Arrays;
+
+
+public class BaseLockSettingsServiceTests extends AndroidTestCase {
+ protected static final int PRIMARY_USER_ID = 0;
+ protected static final int MANAGED_PROFILE_USER_ID = 12;
+ protected static final int SECONDARY_USER_ID = 20;
+
+ private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER_ID, null, null,
+ UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+ private static final UserInfo MANAGED_PROFILE_INFO = new UserInfo(MANAGED_PROFILE_USER_ID, null,
+ null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
+ private static final UserInfo SECONDARY_USER_INFO = new UserInfo(SECONDARY_USER_ID, null, null,
+ UserInfo.FLAG_INITIALIZED);
+
+ LockSettingsService mService;
+
+ MockLockSettingsContext mContext;
+ LockSettingsStorageTestable mStorage;
+
+ LockPatternUtils mLockPatternUtils;
+ MockGateKeeperService mGateKeeperService;
+ NotificationManager mNotificationManager;
+ UserManager mUserManager;
+ MockStorageManager mStorageManager;
+ IActivityManager mActivityManager;
+
+ KeyStore mKeyStore;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mLockPatternUtils = mock(LockPatternUtils.class);
+ mGateKeeperService = new MockGateKeeperService();
+ mNotificationManager = mock(NotificationManager.class);
+ mUserManager = mock(UserManager.class);
+ mStorageManager = new MockStorageManager();
+ mActivityManager = mock(IActivityManager.class);
+ mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager);
+ mStorage = new LockSettingsStorageTestable(mContext,
+ new File(getContext().getFilesDir(), "locksettings"));
+ File storageDir = mStorage.mStorageDir;
+ if (storageDir.exists()) {
+ FileUtils.deleteContents(storageDir);
+ } else {
+ storageDir.mkdirs();
+ }
+
+ mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils,
+ mStorage, mGateKeeperService, mKeyStore, mStorageManager, mActivityManager);
+ when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
+ when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(Arrays.asList(
+ new UserInfo[] {PRIMARY_USER_INFO, MANAGED_PROFILE_INFO}));
+ when(mUserManager.getUserInfo(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
+ MANAGED_PROFILE_INFO);
+ when(mUserManager.getProfileParent(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
+ PRIMARY_USER_INFO);
+ when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO);
+
+ when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer(
+ new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ mStorageManager.unlockUser((int)args[0], (byte[])args[2],
+ (IProgressListener) args[3]);
+ return true;
+ }
+ });
+
+ when(mLockPatternUtils.getLockSettings()).thenReturn(mService);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mStorage.closeDatabase();
+ File db = getContext().getDatabasePath("locksettings.db");
+ assertTrue(!db.exists() || db.delete());
+
+ File storageDir = mStorage.mStorageDir;
+ assertTrue(FileUtils.deleteContents(storageDir));
+ }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTestable.java
new file mode 100644
index 000000000000..613ec0be0919
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTestable.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.IActivityManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.storage.IStorageManager;
+import android.security.KeyStore;
+import android.service.gatekeeper.IGateKeeperService;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.io.FileNotFoundException;
+
+public class LockSettingsServiceTestable extends LockSettingsService {
+
+ private static class MockInjector extends LockSettingsService.Injector {
+
+ private LockSettingsStorage mLockSettingsStorage;
+ private KeyStore mKeyStore;
+ private IActivityManager mActivityManager;
+ private LockPatternUtils mLockPatternUtils;
+ private IStorageManager mStorageManager;
+
+ public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
+ IActivityManager activityManager, LockPatternUtils lockPatternUtils,
+ IStorageManager storageManager) {
+ super(context);
+ mLockSettingsStorage = storage;
+ mKeyStore = keyStore;
+ mActivityManager = activityManager;
+ mLockPatternUtils = lockPatternUtils;
+ mStorageManager = storageManager;
+ }
+
+ @Override
+ public Handler getHandler() {
+ return mock(Handler.class);
+ }
+
+ @Override
+ public LockSettingsStorage getStorage() {
+ return mLockSettingsStorage;
+ }
+
+ @Override
+ public LockSettingsStrongAuth getStrongAuth() {
+ return mock(LockSettingsStrongAuth.class);
+ }
+
+ @Override
+ public SynchronizedStrongAuthTracker getStrongAuthTracker() {
+ return mock(SynchronizedStrongAuthTracker.class);
+ }
+
+ @Override
+ public IActivityManager getActivityManager() {
+ return mActivityManager;
+ }
+
+ @Override
+ public LockPatternUtils getLockPatternUtils() {
+ return mLockPatternUtils;
+ }
+
+ @Override
+ public KeyStore getKeyStore() {
+ return mKeyStore;
+ }
+
+ @Override
+ public IStorageManager getStorageManager() {
+ return mStorageManager;
+ }
+ }
+
+ protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils,
+ LockSettingsStorage storage, IGateKeeperService gatekeeper, KeyStore keystore,
+ IStorageManager storageManager, IActivityManager mActivityManager) {
+ super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils,
+ storageManager));
+ mGateKeeperService = gatekeeper;
+ }
+
+ @Override
+ protected void tieProfileLockToParent(int userId, String password) {
+ mStorage.writeChildProfileLock(userId, password.getBytes());
+ }
+
+ @Override
+ protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException {
+ byte[] storedData = mStorage.readChildProfileLock(userId);
+ if (storedData == null) {
+ throw new FileNotFoundException("Child profile lock file not found");
+ }
+ return new String(storedData);
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
new file mode 100644
index 000000000000..4c2e17172e76
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
+import android.os.RemoteException;
+import android.service.gatekeeper.GateKeeperResponse;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.VerifyCredentialResponse;
+import com.android.server.LockSettingsStorage.CredentialHash;
+import com.android.server.MockGateKeeperService.VerifyHandle;
+
+/**
+ * runtest frameworks-services -c com.android.server.LockSettingsServiceTests
+ */
+public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testCreatePasswordPrimaryUser() throws RemoteException {
+ testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD);
+ }
+
+ public void testCreatePatternPrimaryUser() throws RemoteException {
+ testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN);
+ }
+
+ public void testChangePasswordPrimaryUser() throws RemoteException {
+ testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
+ "asdfghjk", CREDENTIAL_TYPE_PASSWORD);
+ }
+
+ public void testChangePatternPrimaryUser() throws RemoteException {
+ testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
+ "1596321", CREDENTIAL_TYPE_PATTERN);
+ }
+
+ public void testChangePasswordFailPrimaryUser() throws RemoteException {
+ final long sid = 1234;
+ final String FAILED_MESSAGE = "Failed to enroll password";
+ initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
+
+ try {
+ mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
+ PRIMARY_USER_ID);
+ fail("Did not fail when enrolling using incorrect credential");
+ } catch (RemoteException expected) {
+ assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
+ }
+ try {
+ mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, null, PRIMARY_USER_ID);
+ fail("Did not fail when enrolling using incorrect credential");
+ } catch (RemoteException expected) {
+ assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
+ }
+ assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
+ }
+
+ public void testClearPasswordPrimaryUser() throws RemoteException {
+ final String PASSWORD = "password";
+ initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
+ mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD, PRIMARY_USER_ID);
+ assertFalse(mService.havePassword(PRIMARY_USER_ID));
+ assertFalse(mService.havePattern(PRIMARY_USER_ID));
+ assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
+ }
+
+ public void testManagedProfileUnifiedChallenge() throws RemoteException {
+ final String UnifiedPassword = "testManagedProfileUnifiedChallenge-pwd";
+ mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PRIMARY_USER_ID);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
+ final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
+ assertTrue(primarySid != 0);
+ assertTrue(profileSid != 0);
+ assertTrue(profileSid != primarySid);
+
+ // clear auth token and wait for verify challenge from primary user to re-generate it.
+ mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
+ // verify credential
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
+
+ // Verify that we have a new auth token for the profile
+ assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
+ assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+
+ /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
+ * credential as part of verifyCredential() before the new credential is committed in
+ * StorageManager. So we relax the check in our mock StorageManager to allow that.
+ */
+ mStorageManager.setIgnoreBadUnlock(true);
+ // Change primary password and verify that profile SID remains
+ mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ UnifiedPassword, PRIMARY_USER_ID);
+ mStorageManager.setIgnoreBadUnlock(false);
+ assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+ }
+
+ public void testManagedProfileSeparateChallenge() throws RemoteException {
+ final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
+ final String profilePassword = "testManagedProfileSeparateChallenge-profile";
+ mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PRIMARY_USER_ID);
+ /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
+ * credential as part of verifyCredential() before the new credential is committed in
+ * StorageManager. So we relax the check in our mock StorageManager to allow that.
+ */
+ mStorageManager.setIgnoreBadUnlock(true);
+ mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ MANAGED_PROFILE_USER_ID);
+ mStorageManager.setIgnoreBadUnlock(false);
+
+ final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
+ final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
+ assertTrue(primarySid != 0);
+ assertTrue(profileSid != 0);
+ assertTrue(profileSid != primarySid);
+
+ // clear auth token and make sure verify challenge from primary user does not regenerate it.
+ mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
+ // verify primary credential
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
+ assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
+
+ // verify profile credential
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ MANAGED_PROFILE_USER_ID).getResponseCode());
+ assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
+ assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+
+ // Change primary credential and make sure we don't affect profile
+ mStorageManager.setIgnoreBadUnlock(true);
+ mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ primaryPassword, PRIMARY_USER_ID);
+ mStorageManager.setIgnoreBadUnlock(false);
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ MANAGED_PROFILE_USER_ID).getResponseCode());
+ assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+ }
+
+ private void testCreateCredential(int userId, String credential, int type)
+ throws RemoteException {
+ mService.setLockCredential(credential, type, null, userId);
+ assertVerifyCredentials(userId, credential, type, -1);
+ }
+
+ private void testChangeCredentials(int userId, String newCredential, int newType,
+ String oldCredential, int oldType) throws RemoteException {
+ final long sid = 1234;
+ initializeStorageWithCredential(userId, oldCredential, oldType, sid);
+ mService.setLockCredential(newCredential, newType, oldCredential, userId);
+ assertVerifyCredentials(userId, newCredential, newType, sid);
+ }
+
+ private void assertVerifyCredentials(int userId, String credential, int type, long sid)
+ throws RemoteException{
+ final long challenge = 54321;
+ VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
+ userId);
+
+ assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
+ if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
+ final int incorrectType;
+ if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ assertTrue(mService.havePassword(userId));
+ assertFalse(mService.havePattern(userId));
+ incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+ } else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
+ assertFalse(mService.havePassword(userId));
+ assertTrue(mService.havePattern(userId));
+ incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+ } else {
+ assertFalse(mService.havePassword(userId));
+ assertFalse(mService.havePassword(userId));
+ incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+ }
+ // check for bad type
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
+ incorrectType, challenge, userId).getResponseCode());
+ // check for bad credential
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
+ type, challenge, userId).getResponseCode());
+ }
+
+ private void initializeStorageWithCredential(int userId, String credential, int type, long sid) {
+ byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
+ if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ mStorage.writeCredentialHash(CredentialHash.create(oldHash,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
+ } else {
+ mStorage.writeCredentialHash(CredentialHash.create(oldHash,
+ LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTestable.java
new file mode 100644
index 000000000000..e81b02f071a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTestable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.content.Context;
+
+import java.io.File;
+
+public class LockSettingsStorageTestable extends LockSettingsStorage {
+
+ public File mStorageDir;
+
+ public LockSettingsStorageTestable(Context context, File storageDir) {
+ super(context);
+ mStorageDir = storageDir;
+ }
+
+ @Override
+ String getLockPatternFilename(int userId) {
+ return new File(mStorageDir,
+ super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
+ }
+
+ @Override
+ String getLockPasswordFilename(int userId) {
+ return new File(mStorageDir,
+ super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
+ }
+
+ @Override
+ String getChildProfileLockFile(int userId) {
+ return new File(mStorageDir,
+ super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
index 9d521533d773..d110feaab3c9 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
@@ -20,6 +20,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
@@ -60,46 +61,22 @@ public class LockSettingsStorageTests extends AndroidTestCase {
assertTrue(FileUtils.deleteContents(mStorageDir));
assertTrue(!mDb.exists() || mDb.delete());
- final Context ctx = getContext();
final UserManager mockUserManager = mock(UserManager.class);
// User 2 is a profile of user 1.
when(mockUserManager.getProfileParent(eq(2))).thenReturn(new UserInfo(1, "name", 0));
// User 3 is a profile of user 0.
when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
- setContext(new ContextWrapper(ctx) {
- @Override
- public Object getSystemService(String name) {
- if (USER_SERVICE.equals(name)) {
- return mockUserManager;
- }
- return super.getSystemService(name);
- }
- });
-
- mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() {
- @Override
- public void initialize(SQLiteDatabase db) {
- mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
- }
- }) {
- @Override
- String getLockPatternFilename(int userId) {
- return new File(mStorageDir,
- super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
- }
- @Override
- String getLockPasswordFilename(int userId) {
- return new File(mStorageDir,
- super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
- }
-
- @Override
- String getChildProfileLockFile(int userId) {
- return new File(mStorageDir,
- super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath();
- }
- };
+ MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
+ mock(NotificationManager.class));
+ mStorage = new LockSettingsStorageTestable(context,
+ new File(getContext().getFilesDir(), "locksettings"));
+ mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
+ @Override
+ public void initialize(SQLiteDatabase db) {
+ mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
+ }
+ });
}
@Override
@@ -323,7 +300,7 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testFileLocation_Owner() {
- LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+ LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
@@ -332,21 +309,21 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testFileLocation_SecondaryUser() {
- LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+ LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
}
public void testFileLocation_ProfileToSecondary() {
- LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+ LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
}
public void testFileLocation_ProfileToOwner() {
- LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+ LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
diff --git a/services/tests/servicestests/src/com/android/server/MockGateKeeperService.java b/services/tests/servicestests/src/com/android/server/MockGateKeeperService.java
new file mode 100644
index 000000000000..15983cada9c2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/MockGateKeeperService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.gatekeeper.GateKeeperResponse;
+import android.service.gatekeeper.IGateKeeperService;
+import android.util.ArrayMap;
+
+import junit.framework.AssertionFailedError;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+public class MockGateKeeperService implements IGateKeeperService {
+ static class VerifyHandle {
+ public byte[] password;
+ public long sid;
+
+ public VerifyHandle(byte[] password, long sid) {
+ this.password = password;
+ this.sid = sid;
+ }
+
+ public VerifyHandle(byte[] handle) {
+ ByteBuffer buffer = ByteBuffer.allocate(handle.length);
+ buffer.put(handle, 0, handle.length);
+ buffer.flip();
+ int version = buffer.get();
+ sid = buffer.getLong();
+ password = new byte[buffer.remaining()];
+ buffer.get(password);
+ }
+
+ public byte[] toBytes() {
+ ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + password.length);
+ buffer.put((byte)0);
+ buffer.putLong(sid);
+ buffer.put(password);
+ return buffer.array();
+ }
+ }
+
+ static class AuthToken {
+ public long challenge;
+ public long sid;
+
+ public AuthToken(long challenge, long sid) {
+ this.challenge = challenge;
+ this.sid = sid;
+ }
+
+ public AuthToken(byte[] handle) {
+ ByteBuffer buffer = ByteBuffer.allocate(handle.length);
+ buffer.put(handle, 0, handle.length);
+ buffer.flip();
+ int version = buffer.get();
+ challenge = buffer.getLong();
+ sid = buffer.getLong();
+ }
+
+ public byte[] toBytes() {
+ ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + Long.BYTES);
+ buffer.put((byte)0);
+ buffer.putLong(challenge);
+ buffer.putLong(sid);
+ return buffer.array();
+ }
+ }
+
+ private ArrayMap<Integer, Long> sidMap = new ArrayMap<>();
+ private ArrayMap<Integer, AuthToken> authTokenMap = new ArrayMap<>();
+
+ private ArrayMap<Integer, byte[]> handleMap = new ArrayMap<>();
+
+ @Override
+ public GateKeeperResponse enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword,
+ byte[] desiredPassword) throws android.os.RemoteException {
+
+ if (currentPasswordHandle != null) {
+ VerifyHandle handle = new VerifyHandle(currentPasswordHandle);
+ if (Arrays.equals(currentPassword, handle.password)) {
+ // Trusted enroll
+ VerifyHandle newHandle = new VerifyHandle(desiredPassword, handle.sid);
+ refreshSid(uid, handle.sid, false);
+ handleMap.put(uid, newHandle.toBytes());
+ return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
+ } else {
+ return null;
+ }
+ } else {
+ // Untrusted enroll
+ long newSid = new Random().nextLong();
+ VerifyHandle newHandle = new VerifyHandle(desiredPassword, newSid);
+ refreshSid(uid, newSid, true);
+ handleMap.put(uid, newHandle.toBytes());
+ return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
+ }
+ }
+
+ @Override
+ public GateKeeperResponse verify(int uid, byte[] enrolledPasswordHandle,
+ byte[] providedPassword) throws android.os.RemoteException {
+ return verifyChallenge(uid, 0, enrolledPasswordHandle, providedPassword);
+ }
+
+ @Override
+ public GateKeeperResponse verifyChallenge(int uid, long challenge,
+ byte[] enrolledPasswordHandle, byte[] providedPassword) throws RemoteException {
+
+ VerifyHandle handle = new VerifyHandle(enrolledPasswordHandle);
+ if (Arrays.equals(handle.password, providedPassword)) {
+ byte[] knownHandle = handleMap.get(uid);
+ if (knownHandle != null) {
+ if (!Arrays.equals(knownHandle, enrolledPasswordHandle)) {
+ throw new AssertionFailedError("Got correct but obsolete handle");
+ }
+ }
+ refreshSid(uid, handle.sid, false);
+ AuthToken token = new AuthToken(challenge, handle.sid);
+ refreshAuthToken(uid, token);
+ return GateKeeperResponse.createOkResponse(token.toBytes(), false);
+ } else {
+ return GateKeeperResponse.createGenericResponse(GateKeeperResponse.RESPONSE_ERROR);
+ }
+ }
+
+ private void refreshAuthToken(int uid, AuthToken token) {
+ authTokenMap.put(uid, token);
+ }
+
+ public AuthToken getAuthToken(int uid) {
+ return authTokenMap.get(uid);
+ }
+
+ public void clearAuthToken(int uid) {
+ authTokenMap.remove(uid);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clearSecureUserId(int userId) throws RemoteException {
+ sidMap.remove(userId);
+ }
+
+ @Override
+ public long getSecureUserId(int userId) throws RemoteException {
+ if (sidMap.containsKey(userId)) {
+ return sidMap.get(userId);
+ } else {
+ return 0L;
+ }
+ }
+
+ private void refreshSid(int uid, long sid, boolean force) {
+ if (!sidMap.containsKey(uid) || force) {
+ sidMap.put(uid, sid);
+ } else{
+ if (sidMap.get(uid) != sid) {
+ throw new AssertionFailedError("Inconsistent SID");
+ }
+ }
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java
new file mode 100644
index 000000000000..b63936fdffdf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.UserManager;
+
+public class MockLockSettingsContext extends ContextWrapper {
+
+ private UserManager mUserManager;
+ private NotificationManager mNotificationManager;
+
+ public MockLockSettingsContext(Context base, UserManager userManager,
+ NotificationManager notificationManager) {
+ super(base);
+ mUserManager = userManager;
+ mNotificationManager = notificationManager;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (USER_SERVICE.equals(name)) {
+ return mUserManager;
+ } else if (NOTIFICATION_SERVICE.equals(name)) {
+ return mNotificationManager;
+ } else {
+ throw new RuntimeException("System service not mocked: " + name);
+ }
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ // Skip permission checks for unit tests.
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
new file mode 100644
index 000000000000..031a3b39055a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.content.pm.IPackageMoveObserver;
+import android.os.IBinder;
+import android.os.IProgressListener;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.storage.DiskInfo;
+import android.os.storage.IObbActionListener;
+import android.os.storage.IStorageEventListener;
+import android.os.storage.IStorageManager;
+import android.os.storage.IStorageShutdownObserver;
+import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+import com.android.internal.os.AppFuseMount;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class MockStorageManager implements IStorageManager {
+
+ private ArrayMap<Integer, ArrayList<Pair<byte[], byte[]>>> mAuth = new ArrayMap<>();
+ private boolean mIgnoreBadUnlock;
+
+ @Override
+ public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret)
+ throws RemoteException {
+ getUserAuth(userId).add(new Pair<>(token, secret));
+ }
+
+ @Override
+ public void fixateNewestUserKeyAuth(int userId) throws RemoteException {
+ ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
+ Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
+ auths.clear();
+ auths.add(latest);
+ }
+
+ private ArrayList<Pair<byte[], byte[]>> getUserAuth(int userId) {
+ if (!mAuth.containsKey(userId)) {
+ ArrayList<Pair<byte[], byte[]>> auths = new ArrayList<Pair<byte[], byte[]>>();
+ auths.add(new Pair(null, null));
+ mAuth.put(userId, auths);
+ }
+ return mAuth.get(userId);
+ }
+
+ public byte[] getUserUnlockToken(int userId) {
+ ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+ if (auths.size() != 1) {
+ throw new AssertionFailedError("More than one secret exists");
+ }
+ return auths.get(0).second;
+ }
+
+ public void unlockUser(int userId, byte[] secret, IProgressListener listener)
+ throws RemoteException {
+ listener.onStarted(userId, null);
+ listener.onFinished(userId, null);
+ ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+ if (secret != null) {
+ if (auths.size() > 1) {
+ throw new AssertionFailedError("More than one secret exists");
+ }
+ Pair<byte[], byte[]> auth = auths.get(0);
+ if ((!mIgnoreBadUnlock) && auth.second != null && !Arrays.equals(secret, auth.second)) {
+ throw new AssertionFailedError("Invalid secret to unlock user");
+ }
+ } else {
+ if (auths != null && auths.size() > 0) {
+ throw new AssertionFailedError("Cannot unlock encrypted user with empty token");
+ }
+ }
+ }
+
+ public void setIgnoreBadUnlock(boolean ignore) {
+ mIgnoreBadUnlock = ignore;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerListener(IStorageEventListener listener) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterListener(IStorageEventListener listener) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isUsbMassStorageConnected() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUsbMassStorageEnabled(boolean enable) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isUsbMassStorageEnabled() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int mountVolume(String mountPoint) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unmountVolume(String mountPoint, boolean force, boolean removeEncryption)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+
+ }
+
+ @Override
+ public int formatVolume(String mountPoint) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int[] getStorageUsers(String path) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getVolumeState(String mountPoint) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid,
+ boolean external) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int finalizeSecureContainer(String id) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int destroySecureContainer(String id, boolean force) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int unmountSecureContainer(String id, boolean force) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isSecureContainerMounted(String id) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int renameSecureContainer(String oldId, String newId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getSecureContainerPath(String id) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSecureContainerList() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void shutdown(IStorageShutdownObserver observer) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void finishMediaUpdate() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void mountObb(String rawPath, String canonicalPath, String key, IObbActionListener token,
+ int nonce) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isObbMounted(String rawPath) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getMountedObbPath(String rawPath) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isExternalStorageEmulated() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int decryptStorage(String password) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int encryptStorage(int type, String password) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int changeEncryptionPassword(int type, String password) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StorageVolume[] getVolumeList(int uid, String packageName, int flags)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getSecureContainerFilesystemPath(String cid) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getEncryptionState() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int verifyEncryptionPassword(String password) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int fixPermissionsSecureContainer(String id, int gid, String filename)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int mkdirs(String callingPkg, String path) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPasswordType() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPassword() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clearPassword() throws RemoteException {
+ throw new UnsupportedOperationException();
+
+ }
+
+ @Override
+ public void setField(String field, String contents) throws RemoteException {
+ throw new UnsupportedOperationException();
+
+ }
+
+ @Override
+ public String getField(String field) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long lastMaintenance() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void runMaintenance() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void waitForAsecScan() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DiskInfo[] getDisks() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public VolumeInfo[] getVolumes(int flags) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void mount(String volId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unmount(String volId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void format(String volId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void partitionPublic(String diskId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void partitionPrivate(String diskId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void partitionMixed(String diskId, int ratio) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void forgetVolume(String fsUuid) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void forgetAllVolumes() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPrimaryStorageUuid() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long benchmark(String volId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setDebugFlags(int flags, int mask) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createUserKey(int userId, int serialNumber, boolean ephemeral)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void destroyUserKey(int userId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void lockUserKey(int userId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isUserKeyUnlocked(int userId) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void destroyUserStorage(String volumeUuid, int userId, int flags)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isConvertibleToFBE() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fstrim(int flags) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode)
+ throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCacheQuotaBytes(String volumeUuid, int uid) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCacheSizeBytes(String volumeUuid, int uid) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 96459163b277..3f34d4f5133f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -76,6 +76,7 @@ import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicy;
@@ -975,7 +976,8 @@ public class NetworkPolicyManagerServiceTest {
info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
- return new NetworkState(info, prop, null, null, null, TEST_SSID);
+ final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
}
private void expectCurrentTime() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 43c895754890..fa9e9a804e61 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -63,7 +63,10 @@ import android.net.RecommendationResult;
import android.net.ScoredNetwork;
import android.net.Uri;
import android.net.WifiKey;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiSsid;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -82,6 +85,8 @@ import android.support.test.runner.AndroidJUnit4;
import com.android.server.devicepolicy.MockUtils;
+import com.google.android.collect.Lists;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -96,9 +101,12 @@ import org.mockito.stubbing.Answer;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.UnaryOperator;
/**
* Tests for {@link NetworkScoreService}.
@@ -106,19 +114,29 @@ import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class NetworkScoreServiceTest {
+ private static final String SSID = "ssid";
+ private static final String SSID_2 = "ssid_2";
+ private static final String SSID_3 = "ssid_3";
+ private static final ComponentName RECOMMENDATION_SERVICE_COMP =
+ new ComponentName("newPackageName", "newScoringServiceClass");
private static final ScoredNetwork SCORED_NETWORK =
- new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")),
+ new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
+ null /* rssiCurve*/);
+ private static final ScoredNetwork SCORED_NETWORK_2 =
+ new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
null /* rssiCurve*/);
private static final NetworkScorerAppData NEW_SCORER =
- new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass");
+ new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
- @Mock private PackageManager mPackageManager;
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
@Mock private Context mContext;
@Mock private Resources mResources;
@Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
@Mock private IBinder mIBinder, mIBinder2;
@Mock private INetworkRecommendationProvider mRecommendationProvider;
+ @Mock private UnaryOperator<List<ScoredNetwork>> mCurrentNetworkFilter;
+ @Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
+ @Mock private WifiInfo mWifiInfo;
@Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
private ContentResolver mContentResolver;
@@ -127,6 +145,11 @@ public class NetworkScoreServiceTest {
private RemoteCallback mRemoteCallback;
private OnResultListener mOnResultListener;
private HandlerThread mHandlerThread;
+ private List<ScanResult> mScanResults;
+
+ private static String quote(String str) {
+ return String.format("\"%s\"", str);
+ }
@Before
public void setUp() throws Exception {
@@ -136,6 +159,8 @@ public class NetworkScoreServiceTest {
mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources()).thenReturn(mResources);
+ when(mWifiInfo.getSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.ssid);
+ when(mWifiInfo.getBSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.bssid);
mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
mHandlerThread.start();
mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
@@ -150,6 +175,21 @@ public class NetworkScoreServiceTest {
Settings.Global.putLong(mContentResolver,
Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L);
mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
+ populateScanResults();
+ }
+
+ private void populateScanResults() {
+ mScanResults = new ArrayList<>();
+ mScanResults.add(createScanResult(SSID, SCORED_NETWORK.networkKey.wifiKey.bssid));
+ mScanResults.add(createScanResult(SSID_2, SCORED_NETWORK_2.networkKey.wifiKey.bssid));
+ mScanResults.add(createScanResult(SSID_3, "10:10:00:00:10:10"));
+ }
+
+ private ScanResult createScanResult(String ssid, String bssid) {
+ ScanResult result = new ScanResult();
+ result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
+ result.BSSID = bssid;
+ return result;
}
@After
@@ -165,8 +205,7 @@ public class NetworkScoreServiceTest {
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
- .setComponent(new ComponentName(NEW_SCORER.packageName,
- NEW_SCORER.recommendationServiceClassName))),
+ .setComponent(RECOMMENDATION_SERVICE_COMP)),
any(ServiceConnection.class),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
eq(UserHandle.SYSTEM));
@@ -619,13 +658,179 @@ public class NetworkScoreServiceTest {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
mNetworkScoreService.systemRunning();
- assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
+ assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
+ mNetworkScoreService.getActiveScorerPackage());
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_nullFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
+ NetworkScoreService.FilteringCacheUpdatingConsumer consumer =
+ new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI,
+ mCurrentNetworkFilter, mScanResultsFilter);
+
+ consumer.accept(mNetworkScoreCache, null /*cookie*/);
+
+ verify(mNetworkScoreCache).updateScores(scoredNetworkList);
+ verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_noneFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+
+ verify(mNetworkScoreCache).updateScores(scoredNetworkList);
+ verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_unknownFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ consumer.accept(mNetworkScoreCache, -1 /*cookie*/);
+
+ verify(mNetworkScoreCache).updateScores(scoredNetworkList);
+ verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_nonIntFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ consumer.accept(mNetworkScoreCache, "not an int" /*cookie*/);
+
+ verify(mNetworkScoreCache).updateScores(scoredNetworkList);
+ verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_emptyScoreList() throws Exception {
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ Collections.emptyList(),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+
+ verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_currentNetworkFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList =
+ Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
+ filteredList.remove(SCORED_NETWORK);
+ when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+
+ verify(mNetworkScoreCache).updateScores(filteredList);
+ verifyZeroInteractions(mScanResultsFilter);
+ }
+
+ @Test
+ public void testCacheUpdatingConsumer_scanResultsFilter() throws Exception {
+ List<ScoredNetwork> scoredNetworkList =
+ Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
+ NetworkScoreService.FilteringCacheUpdatingConsumer
+ consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
+ new ArrayList<>(scoredNetworkList),
+ NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
+
+ List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
+ filteredList.remove(SCORED_NETWORK);
+ when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+
+ verify(mNetworkScoreCache).updateScores(filteredList);
+ verifyZeroInteractions(mCurrentNetworkFilter);
+ }
+
+ @Test
+ public void testCurrentNetworkScoreCacheFilter_nullWifiInfo() throws Exception {
+ NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+ new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> null /*WifiInfo*/);
+
+ List<ScoredNetwork> actualList =
+ cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+ assertTrue(actualList.isEmpty());
+ }
+
+ @Test
+ public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
+ NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+ new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+ List<ScoredNetwork> actualList =
+ cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+ List<ScoredNetwork> expectedList = Collections.singletonList(SCORED_NETWORK);
+ assertEquals(expectedList, actualList);
+ }
+
+ @Test
+ public void testCurrentNetworkScoreCacheFilter_currentNetworkNotInList() throws Exception {
+ when(mWifiInfo.getSSID()).thenReturn("\"notInList\"");
+ NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+ new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+ List<ScoredNetwork> actualList =
+ cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+ assertTrue(actualList.isEmpty());
+ }
+
+ @Test
+ public void testScanResultsScoreCacheFilter_emptyScanResults() throws Exception {
+ NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
+ new NetworkScoreService.ScanResultsScoreCacheFilter(Collections::emptyList);
+
+ List<ScoredNetwork> actualList =
+ cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+ assertTrue(actualList.isEmpty());
+ }
+
+ @Test
+ public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
+ NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
+ new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);
+
+ ScoredNetwork unmatchedScore =
+ new ScoredNetwork(new NetworkKey(new WifiKey(quote("newSsid"),
+ "00:00:00:00:00:00")), null /* rssiCurve*/);
+
+ List<ScoredNetwork> actualList =
+ cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2,
+ unmatchedScore));
+
+ List<ScoredNetwork> expectedList = Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
+ assertEquals(expectedList, actualList);
}
// "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
private void injectProvider() {
- final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
- NEW_SCORER.recommendationServiceClassName);
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() {
@@ -635,7 +840,8 @@ public class NetworkScoreServiceTest {
when(mockBinder.queryLocalInterface(anyString()))
.thenReturn(mRecommendationProvider);
invocation.getArgumentAt(1, ServiceConnection.class)
- .onServiceConnected(componentName, mockBinder);
+ .onServiceConnected(NEW_SCORER.getRecommendationServiceComponent(),
+ mockBinder);
return true;
}
});
@@ -644,8 +850,8 @@ public class NetworkScoreServiceTest {
private void bindToScorer(boolean callerIsScorer) {
final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
- NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName,
- callingUid, NEW_SCORER.recommendationServiceClassName);
+ NetworkScorerAppData appData =
+ new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
isA(UserHandle.class))).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
new file mode 100644
index 000000000000..d0c2b52f4a67
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.accessibilityservice.AccessibilityService;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import java.util.ArrayList;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests for AccessibilityGestureDetector
+ */
+public class AccessibilityGestureDetectorTest {
+
+ // Constants for testRecognizeGesturePath()
+ private static final PointF PATH_START = new PointF(300f, 300f);
+ private static final int PATH_STEP_PIXELS = 200;
+ private static final long PATH_STEP_MILLISEC = 100;
+
+ /**
+ * AccessibilitGestureDetector that can mock double-tap detector.
+ */
+ private class AccessibilityGestureDetectorTestable extends AccessibilityGestureDetector {
+ public AccessibilityGestureDetectorTestable(Context context, Listener listener) {
+ super(context, listener);
+ }
+
+ protected void setDoubleTapDetector(GestureDetector gestureDetector) {
+ mGestureDetector = gestureDetector;
+ mGestureDetector.setOnDoubleTapListener(this);
+ }
+ }
+
+
+ // Data used by all tests
+ private AccessibilityGestureDetectorTestable mDetector;
+ private AccessibilityGestureDetector.Listener mResultListener;
+
+
+ @BeforeClass
+ public static void oneTimeInitialization() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ }
+
+ @Before
+ public void setUp() {
+ // Construct a mock Context.
+ DisplayMetrics displayMetricsMock = mock(DisplayMetrics.class);
+ displayMetricsMock.xdpi = 500;
+ displayMetricsMock.ydpi = 500;
+ Resources mockResources = mock(Resources.class);
+ when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock);
+ Context contextMock = mock(Context.class);
+ when(contextMock.getMainLooper()).thenReturn(Looper.myLooper());
+ when(contextMock.getResources()).thenReturn(mockResources);
+
+ // Construct a testable AccessibilityGestureDetector.
+ mResultListener = mock(AccessibilityGestureDetector.Listener.class);
+ mDetector = new AccessibilityGestureDetectorTestable(contextMock, mResultListener);
+ GestureDetector doubleTapDetectorMock = mock(GestureDetector.class);
+ mDetector.setDoubleTapDetector(doubleTapDetectorMock);
+ }
+
+
+ @Test
+ public void testRecognizeGesturePath() {
+ final int d = 1000; // Length of each segment in the test gesture, in pixels.
+
+ testPath(p(-d, +0), AccessibilityService.GESTURE_SWIPE_LEFT);
+ testPath(p(+d, +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
+ testPath(p(+0, -d), AccessibilityService.GESTURE_SWIPE_UP);
+ testPath(p(+0, +d), AccessibilityService.GESTURE_SWIPE_DOWN);
+
+ testPath(p(-d, +0), p((-d - d), +0), AccessibilityService.GESTURE_SWIPE_LEFT);
+ testPath(p(-d, +0), p(+0, +0), AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT);
+ testPath(p(-d, +0), p(-d, -d), AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP);
+ testPath(p(-d, +0), p(-d, +d), AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN);
+
+ testPath(p(+d, +0), p(+0, +0), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT);
+ testPath(p(+d, +0), p((+d + d), +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
+ testPath(p(+d, +0), p(+d, -d), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP);
+ testPath(p(+d, +0), p(+d, +d), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN);
+
+ testPath(p(+0, -d), p(-d, -d), AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT);
+ testPath(p(+0, -d), p(+d, -d), AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT);
+ testPath(p(+0, -d), p(+0, (-d - d)), AccessibilityService.GESTURE_SWIPE_UP);
+ testPath(p(+0, -d), p(+0, +0), AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN);
+
+ testPath(p(+0, +d), p(-d, +d), AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT);
+ testPath(p(+0, +d), p(+d, +d), AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT);
+ testPath(p(+0, +d), p(+0, +0), AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP);
+ testPath(p(+0, +d), p(+0, (+d + d)), AccessibilityService.GESTURE_SWIPE_DOWN);
+ }
+
+ /** Convenient short alias to make a Point. */
+ private static Point p(int x, int y) {
+ return new Point(x, y);
+ }
+
+ /** Test recognizing path from PATH_START to PATH_START+delta. */
+ private void testPath(Point delta, int gestureId) {
+ ArrayList<PointF> path = new ArrayList<>();
+ path.add(PATH_START);
+
+ PointF segmentEnd = new PointF(PATH_START.x + delta.x, PATH_START.y + delta.y);
+ fillPath(PATH_START, segmentEnd, path);
+
+ testPath(path, gestureId);
+ }
+
+ /** Test recognizing path from PATH_START to PATH_START+delta1 to PATH_START+delta2. */
+ private void testPath(Point delta1, Point delta2, int gestureId) {
+ ArrayList<PointF> path = new ArrayList<>();
+ path.add(PATH_START);
+
+ PointF startPlusDelta1 = new PointF(PATH_START.x + delta1.x, PATH_START.y + delta1.y);
+ fillPath(PATH_START, startPlusDelta1, path);
+
+ PointF startPlusDelta2 = new PointF(PATH_START.x + delta2.x, PATH_START.y + delta2.y);
+ fillPath(startPlusDelta1, startPlusDelta2, path);
+
+ testPath(path, gestureId);
+ }
+
+ /** Fill in movement points from start to end, appending points to path. */
+ private void fillPath(PointF start, PointF end, ArrayList<PointF> path) {
+ // Calculate number of path steps needed.
+ float deltaX = end.x - start.x;
+ float deltaY = end.y - start.y;
+ float distance = (float) Math.hypot(deltaX, deltaY);
+ float numSteps = distance / (float) PATH_STEP_PIXELS;
+ float stepX = (float) deltaX / numSteps;
+ float stepY = (float) deltaY / numSteps;
+
+ // For each path step from start (non-inclusive) to end ... add a motion point.
+ for (int step = 1; step < numSteps; ++step) {
+ path.add(new PointF(
+ (start.x + (stepX * (float) step)),
+ (start.y + (stepY * (float) step))));
+ }
+ }
+
+ /** Test recognizing a path made of motion event points. */
+ private void testPath(ArrayList<PointF> path, int gestureId) {
+ // Clear last recognition result.
+ reset(mResultListener);
+
+ int policyFlags = 0;
+ long eventDownTimeMs = 0;
+ long eventTimeMs = eventDownTimeMs;
+
+ // For each path point...
+ for (int pointIndex = 0; pointIndex < path.size(); ++pointIndex) {
+
+ // Create motion event.
+ PointF point = path.get(pointIndex);
+ int action = MotionEvent.ACTION_MOVE;
+ if (pointIndex == 0) {
+ action = MotionEvent.ACTION_DOWN;
+ } else if (pointIndex == path.size() - 1) {
+ action = MotionEvent.ACTION_UP;
+ }
+ MotionEvent event = MotionEvent.obtain(eventDownTimeMs, eventTimeMs, action,
+ point.x, point.y, 0);
+
+ // Send event.
+ mDetector.onMotionEvent(event, policyFlags);
+ eventTimeMs += PATH_STEP_MILLISEC;
+ }
+
+ // Check that correct gesture was recognized.
+ verify(mResultListener).onGestureCompleted(gestureId);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
new file mode 100644
index 000000000000..cf477f2b32ef
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.os.Looper;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static android.accessibilityservice.FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for FingerprintGestureController.
+ * TODO: These tests aren't really for server code, so this isn't their ideal home.
+ */
+public class FingerprintGestureControllerTest {
+ @Mock IAccessibilityServiceConnection mMockAccessibilityServiceConnection;
+ @Mock FingerprintGestureCallback mMockFingerprintGestureCallback;
+ FingerprintGestureController mFingerprintGestureController;
+
+ @BeforeClass
+ public static void oneTimeInitialization() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mFingerprintGestureController =
+ new FingerprintGestureController(mMockAccessibilityServiceConnection);
+ }
+
+ @Test
+ public void testIsGestureDetectionActive_returnsValueFromServer() throws Exception {
+ when(mMockAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable())
+ .thenReturn(true);
+ assertTrue(mFingerprintGestureController.isGestureDetectionAvailable());
+ when(mMockAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable())
+ .thenReturn(false);
+ assertFalse(mFingerprintGestureController.isGestureDetectionAvailable());
+ }
+
+ @Test
+ public void testCallbacks_withNoListeners_shouldNotCrash() {
+ mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+ mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ }
+
+ @Test
+ public void testDetectionActiveCallback_noHandler_shouldCallback() {
+ mFingerprintGestureController.registerFingerprintGestureCallback(
+ mMockFingerprintGestureCallback, null);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+ verify(mMockFingerprintGestureCallback, times(1))
+ .onGestureDetectionAvailabilityChanged(true);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+ verify(mMockFingerprintGestureCallback, times(1))
+ .onGestureDetectionAvailabilityChanged(false);
+
+ reset(mMockFingerprintGestureCallback);
+ mFingerprintGestureController.unregisterFingerprintGestureCallback(
+ mMockFingerprintGestureCallback);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+ verifyZeroInteractions(mMockFingerprintGestureCallback);
+ }
+
+ @Test
+ public void testDetectionActiveCallback_withHandler_shouldPostRunnableToHandler() {
+ MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
+ message.getCallback().run();
+ return true;
+ });
+
+ mFingerprintGestureController.registerFingerprintGestureCallback(
+ mMockFingerprintGestureCallback, messageCapturingHandler);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+ verify(mMockFingerprintGestureCallback, times(0))
+ .onGestureDetectionAvailabilityChanged(true);
+ messageCapturingHandler.sendLastMessage();
+ verify(mMockFingerprintGestureCallback, times(1))
+ .onGestureDetectionAvailabilityChanged(true);
+
+ mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+ verify(mMockFingerprintGestureCallback, times(0))
+ .onGestureDetectionAvailabilityChanged(false);
+ messageCapturingHandler.sendLastMessage();
+ verify(mMockFingerprintGestureCallback, times(1))
+ .onGestureDetectionAvailabilityChanged(false);
+
+ reset(mMockFingerprintGestureCallback);
+ mFingerprintGestureController.unregisterFingerprintGestureCallback(
+ mMockFingerprintGestureCallback);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+ mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+ assertFalse(messageCapturingHandler.hasMessages());
+ verifyZeroInteractions(mMockFingerprintGestureCallback);
+ }
+
+ @Test
+ public void testGestureCallback_noHandler_shouldCallListener() {
+ mFingerprintGestureController.registerFingerprintGestureCallback(
+ mMockFingerprintGestureCallback, null);
+ mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+
+ reset(mMockFingerprintGestureCallback);
+ mFingerprintGestureController.unregisterFingerprintGestureCallback(
+ mMockFingerprintGestureCallback);
+ mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verifyZeroInteractions(mMockFingerprintGestureCallback);
+ }
+
+ @Test
+ public void testGestureCallback_withHandler_shouldPostRunnableToHandler() {
+ MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
+ message.getCallback().run();
+ return true;
+ });
+
+ mFingerprintGestureController.registerFingerprintGestureCallback(
+ mMockFingerprintGestureCallback, messageCapturingHandler);
+ mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ verify(mMockFingerprintGestureCallback, times(0)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ messageCapturingHandler.sendLastMessage();
+ verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+
+ reset(mMockFingerprintGestureCallback);
+ mFingerprintGestureController.unregisterFingerprintGestureCallback(
+ mMockFingerprintGestureCallback);
+ mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+ assertFalse(messageCapturingHandler.hasMessages());
+ verifyZeroInteractions(mMockFingerprintGestureCallback);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
new file mode 100644
index 000000000000..98bf53c9d55f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Handler;
+import android.os.Message;
+import android.view.KeyEvent;
+
+import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for FingerprintGestureDispatcher
+ */
+public class FingerprintGestureDispatcherTest {
+
+ private @Mock IFingerprintService mMockFingerprintService;
+ private @Mock FingerprintGestureClient mNonGestureCapturingClient;
+ private @Mock FingerprintGestureClient mGestureCapturingClient;
+ private @Mock FingerprintGestureDispatcher mFingerprintGestureDispatcher;
+ private MessageCapturingHandler mMessageCapturingHandler;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mMessageCapturingHandler = new MessageCapturingHandler(
+ msg -> mFingerprintGestureDispatcher.handleMessage(msg));
+ mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(mMockFingerprintService,
+ new Object(), mMessageCapturingHandler);
+ when(mNonGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(false);
+ when(mGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(true);
+ }
+
+ @Test
+ public void testNoServices_doesNotCrashOrConsumeGestures() {
+ mFingerprintGestureDispatcher.onClientActiveChanged(true);
+ mFingerprintGestureDispatcher.onClientActiveChanged(false);
+ assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+ }
+
+ @Test
+ public void testOneNonCapturingService_doesNotCrashOrConsumeGestures() {
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mNonGestureCapturingClient));
+ mFingerprintGestureDispatcher.onClientActiveChanged(true);
+ mFingerprintGestureDispatcher.onClientActiveChanged(false);
+ assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+ verify(mNonGestureCapturingClient, times(0))
+ .onFingerprintGestureDetectionActiveChanged(anyBoolean());
+ verify(mNonGestureCapturingClient, times(0)).onFingerprintGesture(anyInt());
+ }
+
+ @Test
+ public void testOneCapturingService_notifiesClientOfActivityChanges() {
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mGestureCapturingClient));
+ mFingerprintGestureDispatcher.onClientActiveChanged(true);
+ // Client active means gesture detection isn't.
+ verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(false);
+ verify(mGestureCapturingClient, times(0)).onFingerprintGestureDetectionActiveChanged(true);
+ mFingerprintGestureDispatcher.onClientActiveChanged(false);
+ verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(false);
+ verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(true);
+ }
+
+ @Test
+ public void testOneCapturingService_consumesGesturesAndPassesThemAlong() {
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mGestureCapturingClient));
+ assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+ verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP);
+ assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
+ verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN);
+ assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT));
+ verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT);
+ assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT));
+ verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+ FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT);
+ }
+
+ @Test
+ public void testInvalidKeyCodes_areNotCaptured() {
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mGestureCapturingClient));
+ assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+ KeyEvent.KEYCODE_SPACE));
+ verify(mGestureCapturingClient, times(0)).onFingerprintGesture(anyInt());
+ }
+
+ @Test
+ public void testWithCapturingService_registersForFingerprintUpdates() throws Exception {
+ verifyNoMoreInteractions(mMockFingerprintService);
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mGestureCapturingClient));
+ mMessageCapturingHandler.sendOneMessage();
+ verify(mMockFingerprintService).addClientActiveCallback(mFingerprintGestureDispatcher);
+ }
+
+ @Test
+ public void testWhenCapturingServiceStops_unregistersForFingerprintUpdates() throws Exception {
+ verifyNoMoreInteractions(mMockFingerprintService);
+ mFingerprintGestureDispatcher.updateClientList(
+ Arrays.asList(mGestureCapturingClient));
+ mMessageCapturingHandler.sendOneMessage();
+ mFingerprintGestureDispatcher.updateClientList(Collections.emptyList());
+ mMessageCapturingHandler.sendOneMessage();
+ verify(mMockFingerprintService).removeClientActiveCallback(mFingerprintGestureDispatcher);
+ }
+
+ @Test
+ public void testIsGestureDetectionActive_dependsOnFingerprintService() throws Exception {
+ when(mMockFingerprintService.isClientActive()).thenReturn(true);
+ assertFalse(mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable());
+ when(mMockFingerprintService.isClientActive()).thenReturn(false);
+ assertTrue(mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index a600e69bd345..e433b60e1c94 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -45,9 +45,11 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.RegisteredServicesCacheListener;
import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.RegisteredServicesCache.ServiceInfo;
import android.database.Cursor;
@@ -81,11 +83,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccountManagerServiceTest extends AndroidTestCase {
private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
+ private static final long ONE_DAY_IN_MILLISECOND = 86400000;
@Mock private Context mMockContext;
@Mock private AppOpsManager mMockAppOpsManager;
@@ -104,6 +108,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
private static final String PREN_DB = "pren.db";
private static final String DE_DB = "de.db";
private static final String CE_DB = "ce.db";
+ private PackageInfo mPackageInfo;
private AccountManagerService mAms;
private TestInjector mTestInjector;
@@ -115,7 +120,16 @@ public class AccountManagerServiceTest extends AndroidTestCase {
.thenReturn(PackageManager.SIGNATURE_MATCH);
final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
when(mMockUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ mPackageInfo = new PackageInfo();
+ mPackageInfo.signatures = new Signature[1];
+ mPackageInfo.signatures[0] = new Signature(new byte[] {'a', 'b', 'c', 'd'});
+ mPackageInfo.applicationInfo = new ApplicationInfo();
+ mPackageInfo.applicationInfo.privateFlags = ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
@@ -176,6 +190,8 @@ public class AccountManagerServiceTest extends AndroidTestCase {
mAms.addAccountExplicitly(a31, "p31", null);
mAms.addAccountExplicitly(a32, "p32", null);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
Arrays.sort(accounts, new AccountSorter());
assertEquals(6, accounts.length);
@@ -292,6 +308,8 @@ public class AccountManagerServiceTest extends AndroidTestCase {
@SmallTest
public void testRemovedAccountSync() throws Exception {
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
unlockSystemUser();
Account a1 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
Account a2 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
@@ -333,6 +351,8 @@ public class AccountManagerServiceTest extends AndroidTestCase {
// Start testing
unlockSystemUser();
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
assertEquals("1 account should be migrated", 1, accounts.length);
assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
@@ -366,8 +386,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
null); // optionsIn
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -384,8 +403,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
null); // optionsIn
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -664,8 +682,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
null); // optionsIn
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -681,8 +698,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
null); // optionsIn
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -849,8 +865,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
UserHandle.USER_SYSTEM);
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -866,8 +881,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
UserHandle.USER_SYSTEM);
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -1040,7 +1054,6 @@ public class AccountManagerServiceTest extends AndroidTestCase {
// Assert finishSessionAsUser added calling uid and pid into the sessionBundle
assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID));
assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID));
- // Assert App bundle data overrides sessionBundle data
assertEquals(sessionBundle.getString(
AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package");
@@ -1142,8 +1155,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -1157,8 +1169,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -1172,8 +1183,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
null);
fail("IllegalArgumentException expected. But no exception was thrown.");
} catch (IllegalArgumentException e) {
- } catch(Exception e){
- fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ // IllegalArgumentException is expected.
}
}
@@ -1212,6 +1222,1230 @@ public class AccountManagerServiceTest extends AndroidTestCase {
assertTrue(needUpdate);
}
+ @SmallTest
+ public void testHasFeaturesWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.hasFeatures(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ new String[] {"feature1", "feature2"}, // features
+ "testPackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testHasFeaturesWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.hasFeatures(
+ mMockAccountManagerResponse, // response
+ null, // account
+ new String[] {"feature1", "feature2"}, // features
+ "testPackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testHasFeaturesWithNullFeature() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.hasFeatures(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, // account
+ null, // features
+ "testPackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testHasFeaturesReturnNullResult() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.hasFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR, // account
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES, // features
+ "testPackage"); // opPackageName
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testHasFeaturesSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.hasFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, // account
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES, // features
+ "testPackage"); // opPackageName
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ boolean hasFeatures = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+ assertTrue(hasFeatures);
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.removeAccountAsUser(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.removeAccountAsUser(
+ mMockAccountManagerResponse, // response
+ null, // account
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserAccountNotManagedByCaller() throws Exception {
+ unlockSystemUser();
+ when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+ .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+ try {
+ mAms.removeAccountAsUser(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ fail("SecurityException expected. But no exception was thrown.");
+ } catch (SecurityException e) {
+ // SecurityException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserUserCannotModifyAccount() throws Exception {
+ unlockSystemUser();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+ when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.removeAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserUserCannotModifyAccountType() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mMockDevicePolicyManager);
+ when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+ .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.removeAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserRemovalAllowed() throws Exception {
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p1", null);
+ Account[] addedAccounts =
+ mAms.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+ assertEquals(1, addedAccounts.length);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.removeAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ boolean allowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+ assertTrue(allowed);
+ Account[] accounts = mAms.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+ assertEquals(0, accounts.length);
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserRemovalNotAllowed() throws Exception {
+ unlockSystemUser();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.removeAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ boolean allowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+ assertFalse(allowed);
+ }
+
+ @SmallTest
+ public void testRemoveAccountAsUserReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.removeAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ }
+
+ @SmallTest
+ public void testGetAuthTokenLabelWithNullAccountType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAuthTokenLabel(
+ mMockAccountManagerResponse, // response
+ null, // accountType
+ "authTokenType");
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAuthTokenLabelWithNullAuthTokenType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAuthTokenLabel(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ null); // authTokenType
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAuthTokenWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAuthToken(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAuthTokenWithNullAccount() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ null, // account
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_BAD_ARGUMENTS), anyString());
+ }
+
+ @SmallTest
+ public void testGetAuthTokenWithNullAuthTokenType() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ null, // authTokenType
+ true, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_BAD_ARGUMENTS), anyString());
+ }
+
+ @SmallTest
+ public void testGetAuthTokenWithInvalidPackage() throws Exception {
+ unlockSystemUser();
+ String[] list = new String[]{"test"};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ try {
+ mAms.getAuthToken(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ fail("SecurityException expected. But no exception was thrown.");
+ } catch (SecurityException e) {
+ // SecurityException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAuthTokenFromInternal() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+
+ mAms.setAuthToken(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType", AccountManagerServiceTestFixtures.AUTH_TOKEN);
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ assertEquals(result.getString(AccountManager.KEY_AUTHTOKEN),
+ AccountManagerServiceTestFixtures.AUTH_TOKEN);
+ assertEquals(result.getString(AccountManager.KEY_ACCOUNT_NAME),
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+ assertEquals(result.getString(AccountManager.KEY_ACCOUNT_TYPE),
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ }
+
+ @SmallTest
+ public void testGetAuthTokenSuccess() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ false, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ assertEquals(result.getString(AccountManager.KEY_AUTHTOKEN),
+ AccountManagerServiceTestFixtures.AUTH_TOKEN);
+ assertEquals(result.getString(AccountManager.KEY_ACCOUNT_NAME),
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+ assertEquals(result.getString(AccountManager.KEY_ACCOUNT_TYPE),
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ }
+
+ @SmallTest
+ public void testGetAuthTokenReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ false, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testGetAuthTokenReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType", // authTokenType
+ false, // notifyOnAuthFailure
+ true, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testGetAuthTokenError() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.createPackageContextAsUser(
+ anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAuthToken(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ "authTokenType", // authTokenType
+ true, // notifyOnAuthFailure
+ false, // expectActivityLaunch
+ createGetAuthTokenOptions());
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.addAccountAsUser(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserWithNullAccountType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.addAccountAsUser(
+ mMockAccountManagerResponse, // response
+ null, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserUserCannotModifyAccountNoDPM() throws Exception {
+ unlockSystemUser();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+ when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ mAms.addAccountAsUser(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+ // verify the intent for default CantAddAccountActivity is sent.
+ Intent intent = mIntentCaptor.getValue();
+ assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+ assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+ AccountManager.ERROR_CODE_USER_RESTRICTED);
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserUserCannotModifyAccountWithDPM() throws Exception {
+ unlockSystemUser();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+ when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(
+ DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+ when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+ anyInt(), anyString())).thenReturn(new Intent());
+ when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+ anyInt(), anyBoolean())).thenReturn(new Intent());
+
+ mAms.addAccountAsUser(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+ verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+ verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent(
+ anyInt(), anyString());
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserUserCannotModifyAccountForTypeNoDPM() throws Exception {
+ unlockSystemUser();
+ when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+ .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ mAms.addAccountAsUser(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+ // verify the intent for default CantAddAccountActivity is sent.
+ Intent intent = mIntentCaptor.getValue();
+ assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+ assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+ AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserUserCannotModifyAccountForTypeWithDPM() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mMockDevicePolicyManager);
+ when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+ .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(
+ DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+ when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+ anyInt(), anyString())).thenReturn(new Intent());
+ when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+ anyInt(), anyBoolean())).thenReturn(new Intent());
+
+ mAms.addAccountAsUser(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ null, // optionsIn
+ UserHandle.USER_SYSTEM);
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+ verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+ verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent(
+ anyInt(), anyBoolean());
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.addAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ createAddAccountOptions(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+ // Verify notification is cancelled
+ verify(mMockNotificationManager).cancelNotificationWithTag(
+ anyString(), anyString(), anyInt(), anyInt());
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ // Verify response data
+ assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS,
+ result.getString(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+
+ Bundle optionBundle = result.getParcelable(
+ AccountManagerServiceTestFixtures.KEY_OPTIONS_BUNDLE);
+ // Assert addAccountAsUser added calling uid and pid into the option bundle
+ assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_UID));
+ assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_PID));
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.addAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ createAddAccountOptions(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.addAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ createAddAccountOptions(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testAddAccountAsUserError() throws Exception {
+ unlockSystemUser();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.addAccountAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ "authTokenType",
+ null, // requiredFeatures
+ true, // expectActivityLaunch
+ createAddAccountOptions(AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR),
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.confirmCredentialsAsUser(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ new Bundle(), // options
+ false, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.confirmCredentialsAsUser(
+ mMockAccountManagerResponse, // response
+ null, // account
+ new Bundle(), // options
+ false, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.confirmCredentialsAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ new Bundle(), // options
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ // Verify response data
+ assertTrue(result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS,
+ result.getString(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.confirmCredentialsAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ new Bundle(), // options
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.confirmCredentialsAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ new Bundle(), // options
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testConfirmCredentialsAsUserError() throws Exception {
+ unlockSystemUser();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.confirmCredentialsAsUser(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ new Bundle(), // options
+ true, // expectActivityLaunch
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.updateCredentials(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType",
+ false, // expectActivityLaunch
+ new Bundle()); // options
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.updateCredentials(
+ mMockAccountManagerResponse, // response
+ null, // account
+ "authTokenType",
+ false, // expectActivityLaunch
+ new Bundle()); // options
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.updateCredentials(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType",
+ false, // expectActivityLaunch
+ new Bundle()); // options
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ // Verify response data
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS,
+ result.getString(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.updateCredentials(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType",
+ true, // expectActivityLaunch
+ new Bundle()); // options
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.updateCredentials(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType",
+ true, // expectActivityLaunch
+ new Bundle()); // options
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testUpdateCredentialsError() throws Exception {
+ unlockSystemUser();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.updateCredentials(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ "authTokenType",
+ false, // expectActivityLaunch
+ new Bundle()); // options
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testEditPropertiesWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.editProperties(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ false); // expectActivityLaunch
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testEditPropertiesWithNullAccountType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.editProperties(
+ mMockAccountManagerResponse, // response
+ null, // accountType
+ false); // expectActivityLaunch
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testEditPropertiesAccountNotManagedByCaller() throws Exception {
+ unlockSystemUser();
+ when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+ .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+ try {
+ mAms.editProperties(
+ mMockAccountManagerResponse, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ false); // expectActivityLaunch
+ fail("SecurityException expected. But no exception was thrown.");
+ } catch (SecurityException e) {
+ // SecurityException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testEditPropertiesSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.editProperties(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ false); // expectActivityLaunch
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ // Verify response data
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS,
+ result.getString(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAccountsByFeatures(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesWithNullAccountType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAccountsByFeatures(
+ mMockAccountManagerResponse, // response
+ null, // accountType
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesAccountNotVisible() throws Exception {
+ unlockSystemUser();
+
+ when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+ when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+ .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAccountsByFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Account[] accounts = (Account[]) result.getParcelableArray(AccountManager.KEY_ACCOUNTS);
+ assertTrue(accounts.length == 0);
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesNullFeatureReturnsAllAccounts() throws Exception {
+ unlockSystemUser();
+
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p12", null);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAccountsByFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ null, // features
+ "testpackage"); // opPackageName
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Account[] accounts = (Account[]) result.getParcelableArray(AccountManager.KEY_ACCOUNTS);
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(2, accounts.length);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, accounts[0]);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[1]);
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesReturnsAccountsWithFeaturesOnly() throws Exception {
+ unlockSystemUser();
+
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p12", null);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAccountsByFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Account[] accounts = (Account[]) result.getParcelableArray(AccountManager.KEY_ACCOUNTS);
+ assertEquals(1, accounts.length);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[0]);
+ }
+
+ @SmallTest
+ public void testGetAccountsByFeaturesError() throws Exception {
+ unlockSystemUser();
+
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_ERROR, "p12", null);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.getAccountsByFeatures(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
private void waitForLatch(CountDownLatch latch) {
try {
latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -1220,6 +2454,21 @@ public class AccountManagerServiceTest extends AndroidTestCase {
}
}
+ private Bundle createAddAccountOptions(String accountName) {
+ Bundle options = new Bundle();
+ options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+ return options;
+ }
+
+ private Bundle createGetAuthTokenOptions() {
+ Bundle options = new Bundle();
+ options.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME,
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ options.putLong(AccountManagerServiceTestFixtures.KEY_TOKEN_EXPIRY,
+ System.currentTimeMillis() + ONE_DAY_IN_MILLISECOND);
+ return options;
+ }
+
private Bundle encryptBundleWithCryptoHelper(Bundle sessionBundle) {
Bundle encryptedBundle = null;
try {
@@ -1386,6 +2635,12 @@ public class AccountManagerServiceTest extends AndroidTestCase {
public String getOpPackageName() {
return mMockContext.getOpPackageName();
}
+
+ @Override
+ public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException {
+ return mMockContext.createPackageContextAsUser(packageName, flags, user);
+ }
}
static class TestAccountAuthenticatorCache extends AccountAuthenticatorCache {
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
index 9a2c1903fd21..614680e94cac 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -31,7 +31,8 @@ public final class AccountManagerServiceTestFixtures {
"account_manager_service_test:account_status_token_key";
public static final String KEY_ACCOUNT_PASSWORD =
"account_manager_service_test:account_password_key";
-
+ public static final String KEY_OPTIONS_BUNDLE =
+ "account_manager_service_test:option_bundle_key";
public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
public static final String ACCOUNT_NAME_INTERVENE = "intervene@fixture.com";
public static final String ACCOUNT_NAME_ERROR = "error@fixture.com";
@@ -47,7 +48,20 @@ public final class AccountManagerServiceTestFixtures {
public static final String ACCOUNT_STATUS_TOKEN =
"com.android.server.accounts.account_manager_service_test.account.status.token";
-
+ public static final String AUTH_TOKEN_LABEL =
+ "com.android.server.accounts.account_manager_service_test.auth.token.label";
+ public static final String AUTH_TOKEN =
+ "com.android.server.accounts.account_manager_service_test.auth.token";
+ public static final String KEY_TOKEN_EXPIRY =
+ "com.android.server.accounts.account_manager_service_test.auth.token.expiry";
+ public static final String ACCOUNT_FEATURE1 =
+ "com.android.server.accounts.account_manager_service_test.feature1";
+ public static final String ACCOUNT_FEATURE2 =
+ "com.android.server.accounts.account_manager_service_test.feature2";
+ public static final String[] ACCOUNT_FEATURES =
+ new String[]{ACCOUNT_FEATURE1, ACCOUNT_FEATURE2};
+ public static final String CALLER_PACKAGE =
+ "com.android.server.accounts.account_manager_service_test.caller.package";
public static final String ACCOUNT_PASSWORD =
"com.android.server.accounts.account_manager_service_test.account.password";
public static final String KEY_RESULT = "account_manager_service_test:result";
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
index 8591daee20e8..2cb8af4e97e7 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -355,49 +355,49 @@ public class AccountsDbTest {
@Test
public void testVisibilityFindSetDelete() {
long accId = 10;
- int uid1 = 100500;
- int uid2 = 100501;
+ String packageName1 = "com.example.one";
+ String packageName2 = "com.example.two";
Account account = new Account("name", "example.com");
- assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+ assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
mAccountsDb.insertDeAccount(account, accId);
- assertNull(mAccountsDb.findAccountVisibility(account, uid1));
- assertNull(mAccountsDb.findAccountVisibility(accId, uid1));
+ assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
+ assertNull(mAccountsDb.findAccountVisibility(accId, packageName1));
- mAccountsDb.setAccountVisibility(accId, uid1, 1);
- assertEquals(mAccountsDb.findAccountVisibility(account, uid1), Integer.valueOf(1));
- assertEquals(mAccountsDb.findAccountVisibility(accId, uid1), Integer.valueOf(1));
+ mAccountsDb.setAccountVisibility(accId, packageName1, 1);
+ assertEquals(mAccountsDb.findAccountVisibility(account, packageName1), Integer.valueOf(1));
+ assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1));
- mAccountsDb.setAccountVisibility(accId, uid2, 2);
- assertEquals(mAccountsDb.findAccountVisibility(accId, uid2), Integer.valueOf(2));
+ mAccountsDb.setAccountVisibility(accId, packageName2, 2);
+ assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(2));
- mAccountsDb.setAccountVisibility(accId, uid2, 3);
- assertEquals(mAccountsDb.findAccountVisibility(accId, uid2), Integer.valueOf(3));
+ mAccountsDb.setAccountVisibility(accId, packageName2, 3);
+ assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(3));
- Map<Integer, Integer> vis = mAccountsDb.findAccountVisibilityForAccountId(accId);
+ Map<String, Integer> vis = mAccountsDb.findAllVisibilityValuesForAccount(account);
assertEquals(vis.size(), 2);
- assertEquals(vis.get(uid1), Integer.valueOf(1));
- assertEquals(vis.get(uid2), Integer.valueOf(3));
+ assertEquals(vis.get(packageName1), Integer.valueOf(1));
+ assertEquals(vis.get(packageName2), Integer.valueOf(3));
- assertTrue(mAccountsDb.deleteAccountVisibilityForUid(uid1));
- assertNull(mAccountsDb.findAccountVisibility(accId, uid1));
- assertFalse(mAccountsDb.deleteAccountVisibilityForUid(uid1)); // Already deleted.
+ assertTrue(mAccountsDb.deleteAccountVisibilityForPackage(packageName1));
+ assertNull(mAccountsDb.findAccountVisibility(accId, packageName1));
+ assertFalse(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); // 2nd attempt.
}
@Test
public void testVisibilityCleanupTrigger() {
long accId = 10;
- int uid1 = 100500;
+ String packageName1 = "com.example.one";
Account account = new Account("name", "example.com");
- assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+ assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
mAccountsDb.insertDeAccount(account, accId);
- assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+ assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
- mAccountsDb.setAccountVisibility(accId, uid1, 1);
- assertEquals(mAccountsDb.findAccountVisibility(accId, uid1), Integer.valueOf(1));
+ mAccountsDb.setAccountVisibility(accId, packageName1, 1);
+ assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1));
assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility.
- assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+ assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
index 8ec61763cdb8..eb839a2668f7 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -45,8 +45,15 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
- throw new UnsupportedOperationException(
- "editProperties is not yet supported by the TestAccountAuthenticator");
+ Bundle result = new Bundle();
+ result.putString(AccountManager.KEY_ACCOUNT_NAME,
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ result.putString(
+ AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ return result;
}
@Override
@@ -59,10 +66,38 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
if (!mAccountType.equals(accountType)) {
throw new IllegalArgumentException("Request to the wrong authenticator!");
}
+ String accountName = null;
+
+ if (options != null) {
+ accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+ }
Bundle result = new Bundle();
- result.putString(AccountManager.KEY_ACCOUNT_NAME, "test_account@test.com");
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+ if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ result.putParcelable(AccountManagerServiceTestFixtures.KEY_OPTIONS_BUNDLE, options);
+ } else if (accountName.equals(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ fillResultWithError(
+ result,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ }
return result;
}
@@ -71,8 +106,38 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
AccountAuthenticatorResponse response,
Account account,
Bundle options) throws NetworkErrorException {
- throw new UnsupportedOperationException(
- "confirmCredentials is not yet supported by the TestAccountAuthenticator");
+ if (!mAccountType.equals(account.type)) {
+ throw new IllegalArgumentException("Request to the wrong authenticator!");
+ }
+ Bundle result = new Bundle();
+
+ if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ } else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_BOOLEAN_RESULT, true);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+ eventualActivityResultData);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ fillResultWithError(
+ result,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ }
+ return result;
}
@Override
@@ -81,14 +146,53 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
Account account,
String authTokenType,
Bundle options) throws NetworkErrorException {
- throw new UnsupportedOperationException(
- "getAuthToken is not yet supported by the TestAccountAuthenticator");
+ if (!mAccountType.equals(account.type)) {
+ throw new IllegalArgumentException("Request to the wrong authenticator!");
+ }
+ Bundle result = new Bundle();
+
+ long expiryMillis = (options == null)
+ ? 0 : options.getLong(AccountManagerServiceTestFixtures.KEY_TOKEN_EXPIRY);
+ if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putString(
+ AccountManager.KEY_AUTHTOKEN, AccountManagerServiceTestFixtures.AUTH_TOKEN);
+ result.putLong(
+ AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY,
+ expiryMillis);
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ } else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(
+ AccountManager.KEY_AUTHTOKEN, AccountManagerServiceTestFixtures.AUTH_TOKEN);
+ eventualActivityResultData.putExtra(
+ AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY,
+ expiryMillis);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+ eventualActivityResultData);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+
+ } else {
+ fillResultWithError(
+ result,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ }
+ return result;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
- throw new UnsupportedOperationException(
- "getAuthTokenLabel is not yet supported by the TestAccountAuthenticator");
+ return AccountManagerServiceTestFixtures.AUTH_TOKEN_LABEL;
}
@Override
@@ -101,8 +205,31 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
throw new IllegalArgumentException("Request to the wrong authenticator!");
}
Bundle result = new Bundle();
- result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+
+ if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ } else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+ eventualActivityResultData);
+ intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ fillResultWithError(
+ result,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ }
return result;
}
@@ -111,8 +238,20 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
AccountAuthenticatorResponse response,
Account account,
String[] features) throws NetworkErrorException {
- throw new UnsupportedOperationException(
- "hasFeatures is not yet supported by the TestAccountAuthenticator");
+ Bundle result = new Bundle();
+ if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // fill bundle with true.
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ } else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ // fill bundle with false.
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+ } else {
+ // return null for error
+ result = null;
+ }
+
+ response.onResult(result);
+ return null;
}
@Override
@@ -300,6 +439,22 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
return null;
}
+ @Override
+ public Bundle getAccountRemovalAllowed(
+ AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {
+ Bundle result = new Bundle();
+ if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ } else if (account.name.equals(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+ }
+ return result;
+ }
+
private void fillResultWithError(Bundle result, Bundle options) {
int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
String errorMsg = "Default Error Message";
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 677e468f6550..d7bfc44b14ca 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -36,6 +36,7 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutServiceInternal;
import android.os.Handler;
import android.os.UserHandle;
@@ -121,6 +122,18 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
assertEquals(provider, providerCaptor.getValue().provider);
}
+ public void testIsRequestPinAppWidgetSupported() {
+ ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
+ // Set up users.
+ when(mMockShortcutService.isRequestPinItemSupported(anyInt(), anyInt()))
+ .thenReturn(true, false);
+ assertTrue(mManager.isRequestPinAppWidgetSupported());
+ assertFalse(mManager.isRequestPinAppWidgetSupported());
+
+ verify(mMockShortcutService, times(2)).isRequestPinItemSupported(anyInt(),
+ eq(LauncherApps.PinItemRequest.REQUEST_TYPE_APPWIDGET));
+ }
+
public void testProviderUpdatesReceived() throws Exception {
int widgetId = setupHostAndWidget();
RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 4927f0ca873d..3b92a34b7b7a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -37,6 +37,7 @@ import android.view.IWindowManager;
import com.android.internal.widget.LockPatternUtils;
import java.io.File;
+import java.io.IOException;
import java.util.Map;
/**
@@ -264,6 +265,12 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
+ void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
+ throws IOException {
+ context.recoverySystem.rebootWipeUserData(shutdown, reason, force);
+ }
+
+ @Override
boolean systemPropertiesGetBoolean(String key, boolean def) {
return context.systemProperties.getBoolean(key, def);
}
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 8da47c8b7408..6fb65d59e31e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -68,6 +68,9 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
@@ -82,6 +85,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -1128,6 +1132,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testSetGetApplicationRestriction() {
setAsProfileOwner(admin1);
+ mContext.packageName = admin1.getPackageName();
{
Bundle rest = new Bundle();
@@ -1159,29 +1164,131 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
}
- public void testApplicationRestrictionsManagingApp() throws Exception {
- setAsProfileOwner(admin1);
-
- final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
- final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
- final int appRestrictionsManagerAppId = 20987;
- final int appRestrictionsManagerUid = UserHandle.getUid(
- DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId);
- doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser(
- eq(appRestrictionsManagerPackage),
- eq(DpmMockContext.CALLER_USER_HANDLE));
- mContext.binder.callingUid = appRestrictionsManagerUid;
-
+ /**
+ * Setup a package in the package manager mock. Useful for faking installed applications.
+ *
+ * @param packageName the name of the package to be setup
+ * @param appId the application ID to be given to the package
+ * @return the UID of the package as known by the mock package manager
+ */
+ private int setupPackageInPackageManager(final String packageName, final int appId)
+ throws Exception {
+ // Make the PackageManager return the package instead of throwing a NameNotFoundException
final PackageInfo pi = new PackageInfo();
pi.applicationInfo = new ApplicationInfo();
pi.applicationInfo.flags = ApplicationInfo.FLAG_HAS_CODE;
doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
- eq(appRestrictionsManagerPackage),
+ eq(packageName),
anyInt(),
eq(DpmMockContext.CALLER_USER_HANDLE));
+ // Setup application UID with the PackageManager
+ final int uid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, appId);
+ doReturn(uid).when(mContext.packageManager).getPackageUidAsUser(
+ eq(packageName),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+ // Associate packageName to uid
+ doReturn(packageName).when(mContext.ipackageManager).getNameForUid(eq(uid));
+ doReturn(new String[]{packageName})
+ .when(mContext.ipackageManager).getPackagesForUid(eq(uid));
+ return uid;
+ }
+
+ /**
+ * Simple test for delegate set/get and general delegation. Tests verifying that delegated
+ * privileges can acually be exercised by a delegate are not covered here.
+ */
+ public void testDelegation() throws Exception {
+ setAsProfileOwner(admin1);
+
+ final int userHandle = DpmMockContext.CALLER_USER_HANDLE;
+
+ // Given two packages
+ final String CERT_DELEGATE = "com.delegate.certs";
+ final String RESTRICTIONS_DELEGATE = "com.delegate.apprestrictions";
+ final int CERT_DELEGATE_UID = setupPackageInPackageManager(CERT_DELEGATE, 20988);
+ final int RESTRICTIONS_DELEGATE_UID = setupPackageInPackageManager(RESTRICTIONS_DELEGATE,
+ 20989);
+
+ // On delegation
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
+ dpm.setCertInstallerPackage(admin1, CERT_DELEGATE);
+ dpm.setApplicationRestrictionsManagingPackage(admin1, RESTRICTIONS_DELEGATE);
+
+ // DPMS correctly stores and retrieves the delegates
+ DevicePolicyManagerService.DevicePolicyData policy = dpms.mUserData.get(userHandle);
+ assertEquals(2, policy.mDelegationMap.size());
+ MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE),
+ DELEGATION_CERT_INSTALL);
+ MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, CERT_DELEGATE),
+ DELEGATION_CERT_INSTALL);
+ assertEquals(CERT_DELEGATE, dpm.getCertInstallerPackage(admin1));
+ MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(RESTRICTIONS_DELEGATE),
+ DELEGATION_APP_RESTRICTIONS);
+ MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, RESTRICTIONS_DELEGATE),
+ DELEGATION_APP_RESTRICTIONS);
+ assertEquals(RESTRICTIONS_DELEGATE, dpm.getApplicationRestrictionsManagingPackage(admin1));
+
+ // On calling install certificate APIs from an unauthorized process
+ mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID;
+ mContext.packageName = RESTRICTIONS_DELEGATE;
+
+ // DPMS throws a SecurityException
+ try {
+ dpm.installCaCert(null, null);
+ fail("Didn't throw SecurityException on unauthorized access");
+ } catch (SecurityException expected) {
+ }
+
+ // On calling install certificate APIs from an authorized process
+ mContext.binder.callingUid = CERT_DELEGATE_UID;
+ mContext.packageName = CERT_DELEGATE;
+
+ // DPMS executes without a SecurityException
+ try {
+ dpm.installCaCert(null, null);
+ } catch (SecurityException unexpected) {
+ fail("Threw SecurityException on authorized access");
+ } catch (NullPointerException expected) {
+ }
+
+ // On removing a delegate
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
+ dpm.setCertInstallerPackage(admin1, null);
+
+ // DPMS does not allow access to ex-delegate
+ mContext.binder.callingUid = CERT_DELEGATE_UID;
+ mContext.packageName = CERT_DELEGATE;
+ try {
+ dpm.installCaCert(null, null);
+ fail("Didn't throw SecurityException on unauthorized access");
+ } catch (SecurityException expected) {
+ }
+
+ // But still allows access to other existing delegates
+ mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID;
+ mContext.packageName = RESTRICTIONS_DELEGATE;
+ try {
+ dpm.getApplicationRestrictions(null, "pkg");
+ } catch (SecurityException expected) {
+ fail("Threw SecurityException on authorized access");
+ }
+ }
+
+ public void testApplicationRestrictionsManagingApp() throws Exception {
+ setAsProfileOwner(admin1);
+
+ final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
+ final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
+ final int appRestrictionsManagerAppId = 20987;
+ final int appRestrictionsManagerUid = setupPackageInPackageManager(
+ appRestrictionsManagerPackage, appRestrictionsManagerAppId);
// appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
// delegated that permission yet.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
Bundle rest = new Bundle();
rest.putString("KEY_STRING", "Foo1");
@@ -1190,18 +1297,21 @@ public class DevicePolicyManagerTest extends DpmTestBase {
fail("Didn't throw expected SecurityException");
} catch (SecurityException expected) {
MoreAsserts.assertContainsRegex(
- "caller cannot manage application restrictions", expected.getMessage());
+ "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.",
+ expected.getMessage());
}
try {
dpm.getApplicationRestrictions(null, "pkg1");
fail("Didn't throw expected SecurityException");
} catch (SecurityException expected) {
MoreAsserts.assertContainsRegex(
- "caller cannot manage application restrictions", expected.getMessage());
+ "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.",
+ expected.getMessage());
}
// Check via the profile owner that no restrictions were set.
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
// Check the API does not allow setting a non-existent package
@@ -1221,6 +1331,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Now that package should be able to set and retrieve app restrictions.
mContext.binder.callingUid = appRestrictionsManagerUid;
+ mContext.packageName = appRestrictionsManagerPackage;
assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage());
dpm.setApplicationRestrictions(null, "pkg1", rest);
Bundle returned = dpm.getApplicationRestrictions(null, "pkg1");
@@ -1236,12 +1347,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
fail("Didn't throw expected SecurityException");
} catch (SecurityException expected) {
MoreAsserts.assertContainsRegex(
- "caller cannot manage application restrictions", expected.getMessage());
+ "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.",
+ expected.getMessage());
}
// The DPM is still able to manage app restrictions, even if it allowed another app to do it
// too.
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1"));
dpm.setApplicationRestrictions(admin1, "pkg1", null);
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
@@ -1250,13 +1363,15 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setApplicationRestrictionsManagingPackage(admin1, null);
assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1));
mContext.binder.callingUid = appRestrictionsManagerUid;
+ mContext.packageName = appRestrictionsManagerPackage;
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
try {
dpm.setApplicationRestrictions(null, "pkg1", null);
fail("Didn't throw expected SecurityException");
} catch (SecurityException expected) {
MoreAsserts.assertContainsRegex(
- "caller cannot manage application restrictions", expected.getMessage());
+ "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.",
+ expected.getMessage());
}
}
@@ -1835,6 +1950,81 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
}
+ public void testCreateAdminSupportIntent() throws Exception {
+ // Setup device owner.
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+
+ // Nonexisting permission returns null
+ Intent intent = dpm.createAdminSupportIntent("disallow_nothing");
+ assertNull(intent);
+
+ // Existing permission that is not set returns null
+ intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
+ assertNull(intent);
+
+ // Existing permission that is not set by device/profile owner returns null
+ when(mContext.userManager.hasUserRestriction(
+ eq(UserManager.DISALLOW_ADJUST_VOLUME),
+ eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
+ .thenReturn(true);
+ intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
+ assertNull(intent);
+
+ // Permission that is set by device owner returns correct intent
+ when(mContext.userManager.getUserRestrictionSource(
+ eq(UserManager.DISALLOW_ADJUST_VOLUME),
+ eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+ intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
+ assertNotNull(intent);
+ assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction());
+ assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID),
+ intent.getIntExtra(Intent.EXTRA_USER_ID, -1));
+ assertEquals(admin1,
+ (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN));
+ assertEquals(UserManager.DISALLOW_ADJUST_VOLUME,
+ intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
+
+ // Try with POLICY_DISABLE_CAMERA and POLICY_DISABLE_SCREEN_CAPTURE, which are not
+ // user restrictions
+
+ // Camera is not disabled
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
+ assertNull(intent);
+
+ // Camera is disabled
+ dpm.setCameraDisabled(admin1, true);
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
+ assertNotNull(intent);
+ assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA,
+ intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
+
+ // Screen capture is not disabled
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
+ assertNull(intent);
+
+ // Screen capture is disabled
+ dpm.setScreenCaptureDisabled(admin1, true);
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
+ assertNotNull(intent);
+ assertEquals(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE,
+ intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
+
+ // Same checks for different user
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ // Camera should be disabled by device owner
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
+ assertNotNull(intent);
+ assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA,
+ intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
+ assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID),
+ intent.getIntExtra(Intent.EXTRA_USER_ID, -1));
+ // ScreenCapture should not be disabled by device owner
+ intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
+ assertNull(intent);
+ }
+
/**
* Test for:
* {@link DevicePolicyManager#setAffiliationIds}
@@ -1899,9 +2089,19 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
assertFalse(dpm.isAffiliatedUser());
+ // Set affiliation ids again, then clear PO to check that the user becomes unaffiliated
+ dpm.setAffiliationIds(admin2, userAffiliationIds);
+ assertTrue(dpm.isAffiliatedUser());
+ dpm.clearProfileOwner(admin2);
+ assertFalse(dpm.isAffiliatedUser());
+
// Check that the system user remains affiliated.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
assertTrue(dpm.isAffiliatedUser());
+
+ // Clear the device owner - the user becomes unaffiliated.
+ clearDeviceOwner();
+ assertFalse(dpm.isAffiliatedUser());
}
public void testGetUserProvisioningState_defaultResult() {
@@ -2358,6 +2558,23 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
}
+ private void setup_nonSplitUser_withDo_primaryUser() throws Exception {
+ setDeviceOwner();
+ setup_nonSplitUser_afterDeviceSetup_primaryUser();
+ setUpPackageManagerForFakeAdmin(adminAnotherPackage, DpmMockContext.ANOTHER_UID, admin2);
+ }
+
+ private void setup_nonSplitUser_withDo_primaryUser_ManagedProfile() throws Exception {
+ setup_nonSplitUser_withDo_primaryUser();
+ final int MANAGED_PROFILE_USER_ID = 18;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308);
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+ false /* we can't remove a managed profile */)).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+ true)).thenReturn(true);
+ }
+
public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
throws Exception {
setup_nonSplitUser_afterDeviceSetup_primaryUser();
@@ -2387,144 +2604,124 @@ public class DevicePolicyManagerTest extends DpmTestBase {
DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
}
- public void testIsProvisioningAllowed_nonSplitUser_withDo_primaryUser() throws Exception {
- setDeviceOwner();
- setup_nonSplitUser_afterDeviceSetup_primaryUser();
- setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
+ public void testProvisioning_nonSplitUser_withDo_primaryUser() throws Exception {
+ setup_nonSplitUser_withDo_primaryUser();
mContext.packageName = admin1.getPackageName();
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
- final ComponentName adminDifferentPackage =
- new ComponentName("another.package", "whatever.random.class");
- final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 948);
- setUpPackageManagerForFakeAdmin(adminDifferentPackage, ANOTHER_UID, admin2);
+ assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ DevicePolicyManager.CODE_HAS_DEVICE_OWNER);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
// COMP mode is allowed.
+ assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DevicePolicyManager.CODE_OK);
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ // And other DPCs can also provision a managed profile (DO + BYOD case).
+ assertCheckProvisioningPreCondition(
+ DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DpmMockContext.ANOTHER_PACKAGE_NAME,
+ DevicePolicyManager.CODE_OK);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
+ DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
+ }
+
+ public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception {
+ setup_nonSplitUser_withDo_primaryUser();
+ mContext.packageName = admin1.getPackageName();
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ // The DO should be allowed to initiate provisioning if it set the restriction itself, but
+ // other packages should be forbidden.
when(mContext.userManager.hasUserRestriction(
eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
.thenReturn(true);
-
- // The DO should be allowed to initiate provisioning if it set the restriction itself.
when(mContext.userManager.getUserRestrictionSource(
eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
.thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+ assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DevicePolicyManager.CODE_OK);
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertCheckProvisioningPreCondition(
+ DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DpmMockContext.ANOTHER_PACKAGE_NAME,
+ DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
+ DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
+ }
- // But another app should not
- mContext.binder.callingUid = ANOTHER_UID;
- mContext.packageName = adminDifferentPackage.getPackageName();
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
-
+ public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedBySystem()
+ throws Exception {
+ setup_nonSplitUser_withDo_primaryUser();
+ mContext.packageName = admin1.getPackageName();
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
// The DO should not be allowed to initiate provisioning if the restriction is set by
// another entity.
+ when(mContext.userManager.hasUserRestriction(
+ eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
+ eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
+ .thenReturn(true);
when(mContext.userManager.getUserRestrictionSource(
eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
.thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
- mContext.binder.callingUid = DpmMockContext.CALLER_UID;
- mContext.packageName = admin1.getPackageName();
+ assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
- mContext.binder.callingUid = ANOTHER_UID;
- mContext.packageName = adminDifferentPackage.getPackageName();
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertCheckProvisioningPreCondition(
+ DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ DpmMockContext.ANOTHER_PACKAGE_NAME,
+ DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
+ DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
}
- public void testIsProvisioningAllowed_nonSplitUser_comp() throws Exception {
- setDeviceOwner();
- setup_nonSplitUser_afterDeviceSetup_primaryUser();
- setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
-
- final ComponentName adminDifferentPackage =
- new ComponentName("another.package", "whatever.class");
- final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 948);
- setUpPackageManagerForFakeAdmin(adminDifferentPackage, ANOTHER_UID, admin2);
-
- final int MANAGED_PROFILE_USER_ID = 18;
- final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308);
- addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
-
- when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
- false /* we can't remove a managed profile */)).thenReturn(false);
- when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
- true)).thenReturn(true);
-
- // We can delete the managed profile to create a new one, so provisioning is allowed.
- mContext.packageName = admin1.getPackageName();
- mContext.binder.callingUid = DpmMockContext.CALLER_UID;
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
-
- mContext.packageName = adminDifferentPackage.getPackageName();
- mContext.binder.callingUid = ANOTHER_UID;
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
-
- when(mContext.userManager.hasUserRestriction(
- eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
- eq(UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))))
- .thenReturn(true);
-
- // Now, we can't remove the profile any more to create a new one.
+ public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception {
+ setup_nonSplitUser_withDo_primaryUser_ManagedProfile();
mContext.packageName = admin1.getPackageName();
- mContext.binder.callingUid = DpmMockContext.CALLER_UID;
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
-
- mContext.packageName = adminDifferentPackage.getPackageName();
- mContext.binder.callingUid = ANOTHER_UID;
- assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
- }
-
- public void
- testCheckProvisioningPreCondition_nonSplitUser_withDo_primaryUser() throws Exception {
- setDeviceOwner();
- setup_nonSplitUser_afterDeviceSetup_primaryUser();
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
- assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
- DevicePolicyManager.CODE_HAS_DEVICE_OWNER);
-
- // COMP mode is allowed.
+ // We can delete the managed profile to create a new one, so provisioning is allowed.
assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
DevicePolicyManager.CODE_OK);
-
- // And other DPCs can also provisioning a managed profile (DO + BYOD case).
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
assertCheckProvisioningPreCondition(
DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
- "some.other.dpc.package.name",
+ DpmMockContext.ANOTHER_PACKAGE_NAME,
DevicePolicyManager.CODE_OK);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
+ DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
+ }
+ public void testCheckProvisioningPreCondition_nonSplitUser_comp_cannot_remove_profile()
+ throws Exception {
+ setup_nonSplitUser_withDo_primaryUser_ManagedProfile();
+ mContext.packageName = admin1.getPackageName();
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
when(mContext.userManager.hasUserRestriction(
- eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
- eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
+ eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
+ eq(UserHandle.SYSTEM)))
.thenReturn(true);
-
- // The DO should be allowed to initiate provisioning if it set the restriction itself, but
- // other packages should be forbidden.
when(mContext.userManager.getUserRestrictionSource(
- eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
- eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
+ eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
+ eq(UserHandle.SYSTEM)))
.thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
- assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
- DevicePolicyManager.CODE_OK);
+
+ // We can't remove the profile to create a new one.
assertCheckProvisioningPreCondition(
DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
- "some.other.dpc.package.name",
- DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+ DpmMockContext.ANOTHER_PACKAGE_NAME,
+ DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
+ DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
- // The DO should not be allowed to initiate provisioning if the restriction is set by
- // another entity.
- when(mContext.userManager.getUserRestrictionSource(
- eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
- eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
- .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+ // But the device owner can still do it because it has set the restriction itself.
assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
- DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
- assertCheckProvisioningPreCondition(
- DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
- "some.other.dpc.package.name",
- DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+ DevicePolicyManager.CODE_OK);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
}
private void setup_splitUser_firstBoot_systemUser() throws Exception {
@@ -3145,6 +3342,75 @@ public class DevicePolicyManagerTest extends DpmTestBase {
MoreAsserts.assertEmpty(targetUsers);
}
+ public void testLockTaskPackagesAllowedForAffiliatedUsers() throws Exception {
+ // Setup a device owner.
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ // Lock task packages are updated when loading user data.
+ verify(mContext.iactivityManager)
+ .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(new String[0]));
+
+ // Set up a managed profile managed by different package (package name shouldn't matter)
+ final int MANAGED_PROFILE_USER_ID = 15;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
+ final ComponentName adminDifferentPackage =
+ new ComponentName("another.package", "whatever.class");
+ addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
+ verify(mContext.iactivityManager)
+ .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0]));
+
+ // The DO can still set lock task packages
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ final String[] doPackages = {"doPackage1", "doPackage2"};
+ dpm.setLockTaskPackages(admin1, doPackages);
+ MoreAsserts.assertEquals(doPackages, dpm.getLockTaskPackages(admin1));
+ assertTrue(dpm.isLockTaskPermitted("doPackage1"));
+ assertFalse(dpm.isLockTaskPermitted("anotherPackage"));
+ verify(mContext.iactivityManager)
+ .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(doPackages));
+
+ // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages.
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ final String[] poPackages = {"poPackage1", "poPackage2"};
+ try {
+ dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
+ fail("Didn't throw expected security exception.");
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getLockTaskPackages(adminDifferentPackage);
+ fail("Didn't throw expected security exception.");
+ } catch (SecurityException expected) {
+ }
+ assertFalse(dpm.isLockTaskPermitted("doPackage1"));
+
+ // Setting same affiliation ids
+ final List<String> userAffiliationIds = Arrays.asList("some-affiliation-id");
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ dpm.setAffiliationIds(admin1, userAffiliationIds);
+
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);
+
+ // Now the managed profile can set lock task packages.
+ dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
+ MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage));
+ assertTrue(dpm.isLockTaskPermitted("poPackage1"));
+ assertFalse(dpm.isLockTaskPermitted("doPackage2"));
+ verify(mContext.iactivityManager)
+ .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(poPackages));
+
+ // Unaffiliate the profile, lock task mode no longer available on the profile.
+ dpm.setAffiliationIds(adminDifferentPackage, Collections.<String>emptyList());
+ assertFalse(dpm.isLockTaskPermitted("poPackage1"));
+ // Lock task packages cleared when loading user data and when the user becomes unaffiliated.
+ verify(mContext.iactivityManager, times(2))
+ .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0]));
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ assertTrue(dpm.isLockTaskPermitted("doPackage1"));
+ }
+
public void testIsDeviceManaged() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -3233,6 +3499,140 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
}
+ public void testWipeDataDeviceOwner() throws Exception {
+ setDeviceOwner();
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_FACTORY_RESET,
+ UserHandle.SYSTEM))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+
+ dpm.wipeData(0);
+ verify(mContext.recoverySystem).rebootWipeUserData(
+ /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true));
+ }
+
+ public void testWipeDataDeviceOwnerDisallowed() throws Exception {
+ setDeviceOwner();
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_FACTORY_RESET,
+ UserHandle.SYSTEM))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+ try {
+ // The DO is not allowed to wipe the device if the user restriction was set
+ // by the system
+ dpm.wipeData(0);
+ fail("SecurityException not thrown");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ public void testMaximumFailedPasswordAttemptsReachedManagedProfile() throws Exception {
+ final int MANAGED_PROFILE_USER_ID = 15;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+ // Even if the caller is the managed profile, the current user is the user 0
+ when(mContext.iactivityManager.getCurrentUser())
+ .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ UserHandle.of(MANAGED_PROFILE_USER_ID)))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_PROFILE_OWNER);
+
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ dpm.setMaximumFailedPasswordsForWipe(admin1, 3);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+ // Failed password attempts on the parent user are taken into account, as there isn't a
+ // separate work challenge.
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+
+ // The profile should be wiped even if DISALLOW_REMOVE_MANAGED_PROFILE is enabled, because
+ // both the user restriction and the policy were set by the PO.
+ verify(mContext.userManagerInternal).removeUserEvenWhenDisallowed(
+ MANAGED_PROFILE_USER_ID);
+ verifyZeroInteractions(mContext.recoverySystem);
+ }
+
+ public void testMaximumFailedPasswordAttemptsReachedManagedProfileDisallowed()
+ throws Exception {
+ final int MANAGED_PROFILE_USER_ID = 15;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+ // Even if the caller is the managed profile, the current user is the user 0
+ when(mContext.iactivityManager.getCurrentUser())
+ .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ UserHandle.of(MANAGED_PROFILE_USER_ID)))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ dpm.setMaximumFailedPasswordsForWipe(admin1, 3);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+ // Failed password attempts on the parent user are taken into account, as there isn't a
+ // separate work challenge.
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+
+ // DISALLOW_REMOVE_MANAGED_PROFILE was set by the system, not the PO, so the profile is
+ // not wiped.
+ verify(mContext.userManagerInternal, never())
+ .removeUserEvenWhenDisallowed(anyInt());
+ verifyZeroInteractions(mContext.recoverySystem);
+ }
+
+ public void testMaximumFailedPasswordAttemptsReachedDeviceOwner() throws Exception {
+ setDeviceOwner();
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_FACTORY_RESET,
+ UserHandle.SYSTEM))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+
+ dpm.setMaximumFailedPasswordsForWipe(admin1, 3);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+
+ // The device should be wiped even if DISALLOW_FACTORY_RESET is enabled, because both the
+ // user restriction and the policy were set by the DO.
+ verify(mContext.recoverySystem).rebootWipeUserData(
+ /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true));
+ }
+
+ public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception {
+ setDeviceOwner();
+ when(mContext.userManager.getUserRestrictionSource(
+ UserManager.DISALLOW_FACTORY_RESET,
+ UserHandle.SYSTEM))
+ .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+
+ dpm.setMaximumFailedPasswordsForWipe(admin1, 3);
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+ dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
+
+ // DISALLOW_FACTORY_RESET was set by the system, not the DO, so the device is not wiped.
+ verifyZeroInteractions(mContext.recoverySystem);
+ verify(mContext.userManagerInternal, never())
+ .removeUserEvenWhenDisallowed(anyInt());
+ }
+
public void testGetPermissionGrantState() throws Exception {
final String permission = "some.permission";
final String app1 = "com.example.app1";
@@ -3254,20 +3654,24 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// System can retrieve permission grant state.
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ mContext.packageName = "com.example.system";
assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
dpm.getPermissionGrantState(null, app1, permission));
assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
dpm.getPermissionGrantState(null, app2, permission));
// A regular app cannot retrieve permission grant state.
- mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.binder.callingUid = setupPackageInPackageManager(app1, 1);
+ mContext.packageName = app1;
try {
dpm.getPermissionGrantState(null, app1, permission);
- fail("Didn't throw IllegalStateException");
- } catch (IllegalStateException expected) {
+ fail("Didn't throw SecurityException");
+ } catch (SecurityException expected) {
}
// Profile owner can retrieve permission grant state.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ mContext.packageName = admin1.getPackageName();
setAsProfileOwner(admin1);
assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
dpm.getPermissionGrantState(admin1, app1, permission));
@@ -3287,6 +3691,21 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.isProvisioningAllowed(action));
}
+ private void assertProvisioningAllowed(String action, boolean expected, String packageName,
+ int uid) {
+ String previousPackageName = mContext.packageName;
+ int previousUid = mMockContext.binder.callingUid;
+
+ // Call assertProvisioningAllowed with the packageName / uid passed as arguments.
+ mContext.packageName = packageName;
+ mMockContext.binder.callingUid = uid;
+ assertProvisioningAllowed(action, expected);
+
+ // Set the previous package name / calling uid to go back to the initial state.
+ mContext.packageName = previousPackageName;
+ mMockContext.binder.callingUid = previousUid;
+ }
+
private void assertCheckProvisioningPreCondition(String action, int provisioningCondition) {
assertCheckProvisioningPreCondition(action, admin1.getPackageName(), provisioningCondition);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 44bf547460dd..22cd135923bb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -55,6 +55,7 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -99,6 +100,10 @@ public class DpmMockContext extends MockContext {
*/
public static final int SYSTEM_PID = 11111;
+ public static final String ANOTHER_PACKAGE_NAME = "com.another.package.name";
+
+ public static final int ANOTHER_UID = UserHandle.getUid(UserHandle.USER_SYSTEM, 18434);
+
public static class MockBinder {
public int callingUid = CALLER_UID;
public int callingPid = CALLER_PID;
@@ -154,6 +159,12 @@ public class DpmMockContext extends MockContext {
}
}
+ public static class RecoverySystemForMock {
+ public void rebootWipeUserData(
+ boolean shutdown, String reason, boolean force) throws IOException {
+ }
+ }
+
public static class SystemPropertiesForMock {
public boolean getBoolean(String key, boolean def) {
return false;
@@ -263,6 +274,7 @@ public class DpmMockContext extends MockContext {
public final UserManagerForMock userManagerForMock;
public final PowerManagerForMock powerManager;
public final PowerManagerInternal powerManagerInternal;
+ public final RecoverySystemForMock recoverySystem;
public final NotificationManager notificationManager;
public final IIpConnectivityMetrics iipConnectivityMetrics;
public final IWindowManager iwindowManager;
@@ -308,6 +320,7 @@ public class DpmMockContext extends MockContext {
packageManagerInternal = mock(PackageManagerInternal.class);
powerManager = mock(PowerManagerForMock.class);
powerManagerInternal = mock(PowerManagerInternal.class);
+ recoverySystem = mock(RecoverySystemForMock.class);
notificationManager = mock(NotificationManager.class);
iipConnectivityMetrics = mock(IIpConnectivityMetrics.class);
iwindowManager = mock(IWindowManager.class);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 8a1197618acd..ed6779c41491 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -45,6 +45,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
public ComponentName admin1;
public ComponentName admin2;
public ComponentName admin3;
+ public ComponentName adminAnotherPackage;
public ComponentName adminNoPerm;
@Override
@@ -59,6 +60,8 @@ public abstract class DpmTestBase extends AndroidTestCase {
admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+ adminAnotherPackage = new ComponentName(DpmMockContext.ANOTHER_PACKAGE_NAME,
+ "whatever.random.class");
adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 9835c88c98c2..8c23a91d427f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -398,7 +398,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
@Override
ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
- int launcherUserId) {
+ int launcherUserId, int requestType) {
return mPinConfirmActivityFetcher.apply(launcherPackageName, launcherUserId);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e30bd5d96672..e5640c7e08c1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -309,6 +309,7 @@ public class PackageParserTest {
// Sanity check for InstrumentationInfo.
assertEquals(a.info.targetPackage, b.info.targetPackage);
+ assertEquals(a.info.targetProcess, b.info.targetProcess);
assertEquals(a.info.sourceDir, b.info.sourceDir);
assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index 96e89485874b..0310e16166d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -93,21 +93,24 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest {
Pair<ComponentName, Integer> actual;
// User 0
- actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_0);
+ actual = mProcessor.getRequestPinConfirmationActivity(USER_0,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT);
assertEquals(LAUNCHER_1, actual.first.getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
assertEquals(USER_0, (int) actual.second);
// User 10
- actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_10);
+ actual = mProcessor.getRequestPinConfirmationActivity(USER_10,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT);
assertEquals(LAUNCHER_2, actual.first.getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
assertEquals(USER_10, (int) actual.second);
// User P0 -> managed profile, return user-0's launcher.
- actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_P0);
+ actual = mProcessor.getRequestPinConfirmationActivity(USER_P0,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT);
assertEquals(LAUNCHER_1, actual.first.getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
@@ -133,15 +136,18 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest {
? null : new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
// User 10 -- still has confirm activity.
- actual = mProcessor.getRequestPinShortcutConfirmationActivity(USER_10);
+ actual = mProcessor.getRequestPinConfirmationActivity(USER_10,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT);
assertEquals(LAUNCHER_2, actual.first.getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName());
assertEquals(USER_10, (int) actual.second);
// But user-0 and user p0 no longer has a confirmation activity.
- assertNull(mProcessor.getRequestPinShortcutConfirmationActivity(USER_0));
- assertNull(mProcessor.getRequestPinShortcutConfirmationActivity(USER_P0));
+ assertNull(mProcessor.getRequestPinConfirmationActivity(USER_0,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT));
+ assertNull(mProcessor.getRequestPinConfirmationActivity(USER_P0,
+ PinItemRequest.REQUEST_TYPE_SHORTCUT));
// Check from the public API.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -204,7 +210,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest {
}
private void assertPinItemRequestIntent(Intent actualIntent, String expectedPackage) {
- assertEquals(LauncherApps.ACTION_CONFIRM_PIN_ITEM, actualIntent.getAction());
+ assertEquals(LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT, actualIntent.getAction());
assertEquals(expectedPackage, actualIntent.getComponent().getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS,
actualIntent.getComponent().getClassName());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
index cfa35c2c50a2..26033a355967 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
@@ -72,7 +72,7 @@ public class ShortcutManagerTest9 extends BaseShortcutManagerTest {
}
private void assertPinItemRequestIntent(Intent actualIntent, String expectedPackage) {
- assertEquals(LauncherApps.ACTION_CONFIRM_PIN_ITEM, actualIntent.getAction());
+ assertEquals(LauncherApps.ACTION_CONFIRM_PIN_APPWIDGET, actualIntent.getAction());
assertEquals(expectedPackage, actualIntent.getComponent().getPackageName());
assertEquals(PIN_CONFIRM_ACTIVITY_CLASS,
actualIntent.getComponent().getClassName());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
new file mode 100644
index 000000000000..7a676e258aba
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * <p>Run with:<pre>
+ * m FrameworksServicesTests &&
+ * adb install \
+ * -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ * adb shell am instrument -e class com.android.server.pm.UserDataPreparerTest \
+ * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+@SmallTest
+public class UserDataPreparerTest {
+
+ private static final int TEST_USER_SERIAL = 1000;
+ private static final int TEST_USER_ID = 10;
+
+ private TestUserDataPreparer mUserDataPreparer;
+
+ @Mock
+ private StorageManager mStorageManagerMock;
+
+ @Mock
+ private Context mContextMock;
+
+ @Mock
+ private Installer mInstaller;
+
+ private Object mInstallLock;
+
+ @Before
+ public void setup() {
+ Context ctx = InstrumentationRegistry.getContext();
+ FileUtils.deleteContents(ctx.getCacheDir());
+ mInstallLock = new Object();
+ MockitoAnnotations.initMocks(this);
+ mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock, false,
+ ctx.getCacheDir());
+ when(mContextMock.getSystemServiceName(StorageManager.class))
+ .thenReturn(Context.STORAGE_SERVICE);
+ when(mContextMock.getSystemService(eq(Context.STORAGE_SERVICE)))
+ .thenReturn(mStorageManagerMock);
+ VolumeInfo testVolume = new VolumeInfo("testuuid", VolumeInfo.TYPE_PRIVATE, null, null);
+ when(mStorageManagerMock.getWritablePrivateVolumes()).thenReturn(Arrays.asList(testVolume));
+ }
+
+ @Test
+ public void testPrepareUserData_De() throws Exception {
+ File userDeDir = mUserDataPreparer.getDataUserDeDirectory(null, TEST_USER_ID);
+ userDeDir.mkdirs();
+ File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
+ systemDeDir.mkdirs();
+ mUserDataPreparer
+ .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_DE);
+ verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
+ verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+ eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
+ int serialNumber = UserDataPreparer.getSerialNumber(userDeDir);
+ assertEquals(TEST_USER_SERIAL, serialNumber);
+ serialNumber = UserDataPreparer.getSerialNumber(systemDeDir);
+ assertEquals(TEST_USER_SERIAL, serialNumber);
+ }
+
+ @Test
+ public void testPrepareUserData_Ce() throws Exception {
+ File userCeDir = mUserDataPreparer.getDataUserCeDirectory(null, TEST_USER_ID);
+ userCeDir.mkdirs();
+ File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+ systemCeDir.mkdirs();
+ mUserDataPreparer
+ .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_CE);
+ verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
+ verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+ eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
+ int serialNumber = UserDataPreparer.getSerialNumber(userCeDir);
+ assertEquals(TEST_USER_SERIAL, serialNumber);
+ serialNumber = UserDataPreparer.getSerialNumber(systemCeDir);
+ assertEquals(TEST_USER_SERIAL, serialNumber);
+ }
+
+ @Test
+ public void testDestroyUserData() throws Exception {
+ // Add file in CE
+ File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+ systemCeDir.mkdirs();
+ File ceFile = new File(systemCeDir, "file");
+ writeFile(ceFile, "-----" );
+ testDestroyUserData_De();
+ // CE directory should be preserved
+ assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty(
+ systemCeDir)));
+
+ testDestroyUserData_Ce();
+
+ // Verify that testDir is empty
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+ mUserDataPreparer.testDir)));
+ }
+
+ @Test
+ public void testDestroyUserData_De() throws Exception {
+ File systemDir = mUserDataPreparer.getUserSystemDirectory(TEST_USER_ID);
+ systemDir.mkdirs();
+ writeFile(new File(systemDir, "file"), "-----" );
+ File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
+ systemDeDir.mkdirs();
+ writeFile(new File(systemDeDir, "file"), "-----" );
+ File miscDeDir = mUserDataPreparer.getDataMiscDeDirectory(TEST_USER_ID);
+ miscDeDir.mkdirs();
+ writeFile(new File(miscDeDir, "file"), "-----" );
+
+ mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
+
+ verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+ eq(StorageManager.FLAG_STORAGE_DE));
+ verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ eq(StorageManager.FLAG_STORAGE_DE));
+
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir)));
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+ systemDeDir)));
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+ miscDeDir)));
+ }
+
+ @Test
+ public void testDestroyUserData_Ce() throws Exception {
+ File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+ systemCeDir.mkdirs();
+ writeFile(new File(systemCeDir, "file"), "-----" );
+ File miscCeDir = mUserDataPreparer.getDataMiscCeDirectory(TEST_USER_ID);
+ miscCeDir.mkdirs();
+ writeFile(new File(miscCeDir, "file"), "-----" );
+
+ mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE);
+
+ verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+ eq(StorageManager.FLAG_STORAGE_CE));
+ verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ eq(StorageManager.FLAG_STORAGE_CE));
+
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+ systemCeDir)));
+ assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+ miscCeDir)));
+ }
+
+ @Test
+ public void testReconcileUsers() throws Exception {
+ UserInfo u1 = new UserInfo(1, "u1", 0);
+ UserInfo u2 = new UserInfo(2, "u2", 0);
+ File testDir = mUserDataPreparer.testDir;
+ File dir1 = new File(testDir, "1");
+ dir1.mkdirs();
+ File dir2 = new File(testDir, "2");
+ dir2.mkdirs();
+ File dir3 = new File(testDir, "3");
+ dir3.mkdirs();
+
+ mUserDataPreparer
+ .reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2),
+ Arrays.asList(dir1, dir2, dir3));
+ // Verify that user 3 data is removed
+ verify(mInstaller).destroyUserData(isNull(String.class), eq(3),
+ eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE));
+ }
+
+ private static void writeFile(File file, String content) throws IOException {
+ try (FileOutputStream os = new FileOutputStream(file)) {
+ os.write(content.getBytes(Charset.defaultCharset()));
+ }
+ }
+
+ private static class TestUserDataPreparer extends UserDataPreparer {
+ File testDir;
+
+ TestUserDataPreparer(Installer installer, Object installLock, Context context,
+ boolean onlyCore, File testDir) {
+ super(installer, installLock, context, onlyCore);
+ this.testDir = testDir;
+ }
+
+ @Override
+ protected File getDataMiscCeDirectory(int userId) {
+ return new File(testDir, "misc_ce_" + userId);
+ }
+
+ @Override
+ protected File getDataSystemCeDirectory(int userId) {
+ return new File(testDir, "system_ce_" + userId);
+ }
+
+ @Override
+ protected File getDataMiscDeDirectory(int userId) {
+ return new File(testDir, "misc_de_" + userId);
+ }
+
+ @Override
+ protected File getUserSystemDirectory(int userId) {
+ return new File(testDir, "user_system_" + userId);
+ }
+
+ @Override
+ protected File getDataUserCeDirectory(String volumeUuid, int userId) {
+ return new File(testDir, "user_ce_" + userId);
+ }
+
+ @Override
+ protected File getDataSystemDeDirectory(int userId) {
+ return new File(testDir, "system_de_" + userId);
+ }
+
+ @Override
+ protected File getDataUserDeDirectory(String volumeUuid, int userId) {
+ return new File(testDir, "user_de_" + userId);
+ }
+
+ @Override
+ protected boolean isFileEncryptedEmulatedOnly() {
+ return false;
+ }
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 9b2c94e0d63b..1964cad1aefc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -177,10 +177,12 @@ public class UserManagerTest extends AndroidTestCase {
UserInfo userInfo = createProfileForUser("Profile",
UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
assertNotNull(userInfo);
-
+ assertNull(mUserManager.getProfileParent(primaryUserId));
UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);
assertNotNull(parentProfileInfo);
assertEquals(parentProfileInfo.id, primaryUserId);
+ removeUser(userInfo.id);
+ assertNull(mUserManager.getProfileParent(primaryUserId));
}
// Make sure only one managed profile can be created
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index b655f3af3a24..90a2ec0c7628 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -73,8 +73,7 @@ public class DexManagerTests {
mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
-
- mDexManager = new DexManager();
+ mDexManager = new DexManager(null, null, null, null);
// Foo and Bar are available to user0.
// Only Bar is available to user1;
@@ -204,6 +203,46 @@ public class DexManagerTests {
assertNull(getPackageUseInfo(mBarUser1));
}
+ @Test
+ public void testNotifyPackageInstallUsedByOther() {
+ TestData newPackage = new TestData("newPackage",
+ VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
+
+ List<String> newSecondaries = newPackage.getSecondaryDexPaths();
+ // Before we notify about the installation of the newPackage if mFoo
+ // is trying to load something from it we should not find it.
+ notifyDexLoad(mFooUser0, newSecondaries, mUser0);
+ assertNull(getPackageUseInfo(newPackage));
+
+ // Notify about newPackage install and let mFoo load its dexes.
+ mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0);
+ notifyDexLoad(mFooUser0, newSecondaries, mUser0);
+
+ // We should get back the right info.
+ PackageUseInfo pui = getPackageUseInfo(newPackage);
+ assertNotNull(pui);
+ assertFalse(pui.isUsedByOtherApps());
+ assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
+ assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0);
+ }
+
+ @Test
+ public void testNotifyPackageInstallSelfUse() {
+ TestData newPackage = new TestData("newPackage",
+ VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
+
+ List<String> newSecondaries = newPackage.getSecondaryDexPaths();
+ // Packages should be able to find their own dex files even if the notification about
+ // their installation is delayed.
+ notifyDexLoad(newPackage, newSecondaries, mUser0);
+
+ PackageUseInfo pui = getPackageUseInfo(newPackage);
+ assertNotNull(pui);
+ assertFalse(pui.isUsedByOtherApps());
+ assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
+ assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0);
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
for (String dex : secondaries) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 5a428414a970..19e0bcf6ba56 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -256,6 +256,32 @@ public class PackageDexUsageTests {
assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName));
}
+ @Test
+ public void testRemoveUserPackage() {
+ // Record Bar secondaries for two different users.
+ assertTrue(record(mBarSecondary1User0));
+ assertTrue(record(mBarSecondary2User1));
+
+ // Remove user 0 files.
+ assertTrue(mPackageDexUsage.removeUserPackage(mBarSecondary1User0.mPackageName,
+ mBarSecondary1User0.mOwnerUserId));
+ // Assert that only user 1 files are there.
+ assertPackageDexUsage(null, mBarSecondary2User1);
+ }
+
+ @Test
+ public void testRemoveDexFile() {
+ // Record Bar secondaries for two different users.
+ assertTrue(record(mBarSecondary1User0));
+ assertTrue(record(mBarSecondary2User1));
+
+ // Remove mBarSecondary1User0 file.
+ assertTrue(mPackageDexUsage.removeDexFile(mBarSecondary1User0.mPackageName,
+ mBarSecondary1User0.mDexFile, mBarSecondary1User0.mOwnerUserId));
+ // Assert that only user 1 files are there.
+ assertPackageDexUsage(null, mBarSecondary2User1);
+ }
+
private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps;
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
index d53fdf6c4aa9..e1dda5198a36 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -449,6 +449,11 @@ public class RetailDemoModeServiceTest {
}
@Override
+ File getDataPreloadsFileCacheDirectory() {
+ return new File(mTestPreloadsDir, "file_cache");
+ }
+
+ @Override
void publishLocalService(RetailDemoModeService service,
RetailDemoModeServiceInternal localService) {
}
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
index 2aca702b809c..13a3c2f23988 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java
@@ -155,7 +155,7 @@ public class DiskStatsFileLoggerTest extends AndroidTestCase {
}
@Test
- public void testDuplicatePackageNameIsMergedAcrossMultipleUsers() throws Exception {
+ public void testDuplicatePackageNameIsNotMergedAcrossMultipleUsers() throws Exception {
PackageStats app = new PackageStats("com.test.app");
app.dataSize = 1000;
app.externalDataSize = 1000;
@@ -175,19 +175,19 @@ public class DiskStatsFileLoggerTest extends AndroidTestCase {
logger.dumpToFile(mOutputFile);
JSONObject output = getOutputFileAsJson();
- assertThat(output.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(2200);
- assertThat(output.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)).isEqualTo(22);
+ assertThat(output.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(2000);
+ assertThat(output.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)).isEqualTo(20);
JSONArray packageNames = output.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
assertThat(packageNames.length()).isEqualTo(1);
assertThat(packageNames.getString(0)).isEqualTo("com.test.app");
JSONArray appSizes = output.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
assertThat(appSizes.length()).isEqualTo(1);
- assertThat(appSizes.getLong(0)).isEqualTo(2200);
+ assertThat(appSizes.getLong(0)).isEqualTo(2000);
JSONArray cacheSizes = output.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
assertThat(cacheSizes.length()).isEqualTo(1);
- assertThat(cacheSizes.getLong(0)).isEqualTo(22);
+ assertThat(cacheSizes.getLong(0)).isEqualTo(20);
}
private JSONObject getOutputFileAsJson() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 67e78d4a2108..cd3ae1ae8b03 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -38,16 +38,18 @@ public class TestSystemImpl implements SystemInterface {
private final int mNumRelros;
private final boolean mIsDebuggable;
private int mMultiProcessSetting;
+ private final boolean mMultiProcessDefault;
public static final int PRIMARY_USER_ID = 0;
public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
- int numRelros, boolean isDebuggable) {
+ int numRelros, boolean isDebuggable, boolean multiProcessDefault) {
mPackageConfigs = packageConfigs;
mFallbackLogicEnabled = fallbackLogicEnabled;
mNumRelros = numRelros;
mIsDebuggable = isDebuggable;
mUsers.add(PRIMARY_USER_ID);
+ mMultiProcessDefault = multiProcessDefault;
}
public void addUser(int userId) {
@@ -187,4 +189,9 @@ public class TestSystemImpl implements SystemInterface {
@Override
public void notifyZygote(boolean enableMultiProcess) {}
+
+ @Override
+ public boolean isMultiProcessDefaultEnabled() {
+ return mMultiProcessDefault;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 33cedfa41e51..e4b74eb07264 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -16,13 +16,16 @@
package com.android.server.webkit;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
+import android.os.Build;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -84,8 +87,15 @@ public class WebViewUpdateServiceTest {
private void setupWithPackages(WebViewProviderInfo[] packages,
boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) {
+ setupWithPackages(packages, fallbackLogicEnabled, numRelros, isDebuggable,
+ false /* multiProcessDefault */);
+ }
+
+ private void setupWithPackages(WebViewProviderInfo[] packages,
+ boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable,
+ boolean multiProcessDefault) {
TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros,
- isDebuggable);
+ isDebuggable, multiProcessDefault);
mTestSystemImpl = Mockito.spy(testing);
mWebViewUpdateServiceImpl =
new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
@@ -166,6 +176,8 @@ public class WebViewUpdateServiceTest {
// no flag means invalid
p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
}
+ // Default to this package being valid in terms of targetSdkVersion.
+ p.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
return p;
}
@@ -1521,4 +1533,127 @@ public class WebViewUpdateServiceTest {
assertEquals(firstPackage.versionName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
}
+
+ @Test
+ public void testMultiProcessEnabledByDefault() {
+ String primaryPackage = "primary";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ primaryPackage, "", true /* default available */, false /* fallback */, null)};
+ setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
+ true /* debuggable */, true /* multiprocess by default */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */,
+ false /* isSystemApp */));
+
+ runWebViewBootPreparationOnMainSync();
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
+
+ // Check it's on by default
+ assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+
+ // Test toggling it
+ mWebViewUpdateServiceImpl.enableMultiProcess(false);
+ assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ mWebViewUpdateServiceImpl.enableMultiProcess(true);
+ assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+
+ // Disable, then upgrade provider, which should re-enable it
+ mWebViewUpdateServiceImpl.enableMultiProcess(false);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 20 /* lastUpdateTime*/, false /* not hidden */, 2000 /* versionCode */,
+ false /* isSystemApp */));
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+ checkPreparationPhasesForPackage(primaryPackage, 2);
+ assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ }
+
+ @Test
+ public void testMultiProcessDisabledByDefault() {
+ String primaryPackage = "primary";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ primaryPackage, "", true /* default available */, false /* fallback */, null)};
+ setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
+ true /* debuggable */, false /* not multiprocess by default */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */,
+ false /* isSystemApp */));
+
+ runWebViewBootPreparationOnMainSync();
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
+
+ // Check it's off by default
+ assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+
+ // Test toggling it
+ mWebViewUpdateServiceImpl.enableMultiProcess(true);
+ assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ mWebViewUpdateServiceImpl.enableMultiProcess(false);
+ assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+
+ // Disable, then upgrade provider, which should not re-enable it
+ mWebViewUpdateServiceImpl.enableMultiProcess(false);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 20 /* lastUpdateTime*/, false /* not hidden */, 2000 /* versionCode */,
+ false /* isSystemApp */));
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+ checkPreparationPhasesForPackage(primaryPackage, 2);
+ assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+
+ // Enable, then upgrade provider, which should leave it on
+ mWebViewUpdateServiceImpl.enableMultiProcess(true);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 30 /* lastUpdateTime*/, false /* not hidden */, 3000 /* versionCode */,
+ false /* isSystemApp */));
+ mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+ checkPreparationPhasesForPackage(primaryPackage, 3);
+ assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ }
+
+ /**
+ * Ensure that packages with a targetSdkVersion targeting the current platform are valid, and
+ * that packages targeting an older version are not valid.
+ */
+ @Test
+ public void testTargetSdkVersionValidity() {
+ PackageInfo newSdkPackage = createPackageInfo("newTargetSdkPackage",
+ true /* enabled */, true /* valid */, true /* installed */);
+ newSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ PackageInfo currentSdkPackage = createPackageInfo("currentTargetSdkPackage",
+ true /* enabled */, true /* valid */, true /* installed */);
+ currentSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1+1;
+ PackageInfo oldSdkPackage = createPackageInfo("oldTargetSdkPackage",
+ true /* enabled */, true /* valid */, true /* installed */);
+ oldSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+
+ WebViewProviderInfo newSdkProviderInfo =
+ new WebViewProviderInfo(newSdkPackage.packageName, "", true, false, null);
+ WebViewProviderInfo currentSdkProviderInfo =
+ new WebViewProviderInfo(currentSdkPackage.packageName, "", true, false, null);
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(oldSdkPackage.packageName, "", true, false, null),
+ currentSdkProviderInfo, newSdkProviderInfo};
+ setupWithPackages(packages, true);
+;
+ mTestSystemImpl.setPackageInfo(newSdkPackage);
+ mTestSystemImpl.setPackageInfo(currentSdkPackage);
+ mTestSystemImpl.setPackageInfo(oldSdkPackage);
+
+ assertArrayEquals(new WebViewProviderInfo[]{currentSdkProviderInfo, newSdkProviderInfo},
+ mWebViewUpdateServiceImpl.getValidWebViewPackages());
+
+ runWebViewBootPreparationOnMainSync();
+
+ checkPreparationPhasesForPackage(currentSdkPackage.packageName,
+ 1 /* first preparation phase */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 2af4163770ae..04e55836a706 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -29,6 +29,7 @@ import static android.content.res.Configuration.EMPTY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
/**
* Test class for {@link AppWindowContainerController}.
@@ -135,9 +136,50 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
assertHasStartingWindow(controller2.getAppWindowToken());
}
+ @Test
+ public void testReparent() throws Exception {
+ final TestTaskWindowContainerController taskController1 =
+ new TestTaskWindowContainerController(
+ createStackControllerOnDisplay(sDisplayContent));
+ final TestAppWindowContainerController appWindowController1 = createAppWindowController(
+ taskController1);
+ final TestTaskWindowContainerController taskController2 =
+ new TestTaskWindowContainerController(
+ createStackControllerOnDisplay(sDisplayContent));
+ final TestAppWindowContainerController appWindowController2 = createAppWindowController(
+ taskController2);
+ final TestTaskWindowContainerController taskController3 =
+ new TestTaskWindowContainerController(
+ createStackControllerOnDisplay(sDisplayContent));
+
+ try {
+ appWindowController1.reparent(taskController1, 0);
+ fail("Should not be able to reparent to the same parent");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ taskController3.setContainer(null);
+ appWindowController1.reparent(taskController3, 0);
+ fail("Should not be able to reparent to a task that doesn't have a container");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ // Reparent the app window and ensure that it is moved
+ appWindowController1.reparent(taskController2, 0);
+ assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent());
+ assertEquals(0, ((TestAppWindowToken) appWindowController1.mContainer).positionInParent());
+ assertEquals(1, ((TestAppWindowToken) appWindowController2.mContainer).positionInParent());
+ }
+
private TestAppWindowContainerController createAppWindowController() {
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController();
+ return createAppWindowController(new TestTaskWindowContainerController());
+ }
+
+ private TestAppWindowContainerController createAppWindowController(
+ TestTaskWindowContainerController taskController) {
return new TestAppWindowContainerController(taskController);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 1d9875f308e9..154fa9140d82 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -119,6 +119,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, sWm.mLastOrientation);
assertTrue(appWindow.resizeReported);
+ appWindow.removeImmediately();
}
@Test
@@ -148,5 +149,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
sWm.updateRotation(false, false);
sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertTrue(appWindow.resizeReported);
+ appWindow.removeImmediately();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimLayerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimLayerControllerTests.java
new file mode 100644
index 000000000000..c3a471a828b0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DimLayerControllerTests.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.hardware.display.DisplayManagerGlobal;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link DimLayerController} class.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.DimLayerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class DimLayerControllerTests extends WindowTestsBase {
+
+ /**
+ * This tests if shared fullscreen dim layer is added when stack is added to display
+ * and is removed when the only stack on the display is removed.
+ */
+ @Test
+ public void testSharedFullScreenDimLayer() throws Exception {
+ // Create a display.
+ final DisplayContent dc = createNewDisplay();
+ assertFalse(dc.mDimLayerController.hasSharedFullScreenDimLayer());
+
+ // Add stack with activity.
+ final TaskStack stack = createTaskStackOnDisplay(dc);
+ assertTrue(dc.mDimLayerController.hasDimLayerUser(stack));
+ assertTrue(dc.mDimLayerController.hasSharedFullScreenDimLayer());
+
+ // Remove the only stack on the display and check if the shared dim layer clears.
+ stack.removeImmediately();
+ assertFalse(dc.mDimLayerController.hasDimLayerUser(stack));
+ assertFalse(dc.mDimLayerController.hasSharedFullScreenDimLayer());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 85931e8ac878..30f99e58d887 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -29,6 +29,7 @@ import android.view.DisplayInfo;
import java.util.ArrayList;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
@@ -215,13 +216,8 @@ public class DisplayContentTests extends WindowTestsBase {
*/
@Test
public void testMoveStackBetweenDisplays() throws Exception {
- // Create second display.
- final Display display = new Display(DisplayManagerGlobal.getInstance(),
- sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
- DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
- new WallpaperController(sWm));
- sWm.mRoot.addChild(dc, 1);
+ // Create a second display.
+ final DisplayContent dc = createNewDisplay();
// Add stack with activity.
final TaskStack stack = createTaskStackOnDisplay(dc);
@@ -236,7 +232,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(dc, token.getDisplayContent());
// Move stack to first display.
- sWm.moveStackToDisplay(stack.mStackId, sDisplayContent.getDisplayId());
+ sDisplayContent.moveStackToDisplay(stack);
assertEquals(sDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
assertEquals(sDisplayContent, stack.getParent().getParent());
assertEquals(sDisplayContent, stack.getDisplayContent());
@@ -261,10 +257,31 @@ public class DisplayContentTests extends WindowTestsBase {
// Check that override config is applied.
assertEquals(newOverrideConfig, sDisplayContent.getOverrideConfiguration());
+ }
+
+ /**
+ * This tests global configuration updates when default display config is updated.
+ */
+ @Test
+ public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
+ final Configuration currentOverrideConfig = sDisplayContent.getOverrideConfiguration();
+
+ // Create new, slightly changed override configuration and apply it to the display.
+ final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
+ newOverrideConfig.densityDpi += 120;
+ newOverrideConfig.fontScale += 0.3;
+
+ sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
// Check that global configuration is updated, as we've updated default display's config.
- final Configuration globalConfig = sWm.mRoot.getConfiguration();
+ Configuration globalConfig = sWm.mRoot.getConfiguration();
assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
+
+ // Return back to original values.
+ sWm.setNewDisplayOverrideConfiguration(currentOverrideConfig, DEFAULT_DISPLAY);
+ globalConfig = sWm.mRoot.getConfiguration();
+ assertEquals(currentOverrideConfig.densityDpi, globalConfig.densityDpi);
+ assertEquals(currentOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
new file mode 100644
index 000000000000..b0eba0b99567
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.view.Display;
+import android.view.DisplayInfo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link StackWindowController}.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.StackWindowControllerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class StackWindowControllerTests extends WindowTestsBase {
+ @Test
+ public void testRemoveContainer() throws Exception {
+ final StackWindowController stackController =
+ createStackControllerOnDisplay(sDisplayContent);
+ final TestTaskWindowContainerController taskController =
+ new TestTaskWindowContainerController(stackController);
+
+ final TaskStack stack = stackController.mContainer;
+ final Task task = taskController.mContainer;
+ assertNotNull(stack);
+ assertNotNull(task);
+ stackController.removeContainer();
+ // Assert that the container was removed.
+ assertNull(stackController.mContainer);
+ assertNull(taskController.mContainer);
+ assertNull(stack.getDisplayContent());
+ assertNull(task.getDisplayContent());
+ assertNull(task.mStack);
+ }
+
+ @Test
+ public void testRemoveContainer_deferRemoval() throws Exception {
+ final StackWindowController stackController =
+ createStackControllerOnDisplay(sDisplayContent);
+ final TestTaskWindowContainerController taskController =
+ new TestTaskWindowContainerController(stackController);
+
+ final TaskStack stack = stackController.mContainer;
+ final TestTask task = (TestTask) taskController.mContainer;
+ // Stack removal is deferred if one of its child is animating.
+ task.setLocalIsAnimating(true);
+
+ stackController.removeContainer();
+ // For the case of deferred removal the stack controller will no longer be connected to the
+ // container, but the task controller will still be connected to the its container until
+ // the stack window container is removed.
+ assertNull(stackController.mContainer);
+ assertNull(stack.getController());
+ assertNotNull(taskController.mContainer);
+ assertNotNull(task.getController());
+
+ stack.removeImmediately();
+ assertNull(taskController.mContainer);
+ assertNull(task.getController());
+ }
+
+ @Test
+ public void testReparent() throws Exception {
+ // Create first stack on primary display.
+ final StackWindowController stack1Controller =
+ createStackControllerOnDisplay(sDisplayContent);
+ final TaskStack stack1 = stack1Controller.mContainer;
+ final TestTaskWindowContainerController taskController =
+ new TestTaskWindowContainerController(stack1Controller);
+ final TestTask task1 = (TestTask) taskController.mContainer;
+ task1.mOnDisplayChangedCalled = false;
+
+ // Create second display and put second stack on it.
+ final DisplayContent dc = createNewDisplay();
+ final StackWindowController stack2Controller =
+ createStackControllerOnDisplay(dc);
+ final TaskStack stack2 = stack2Controller.mContainer;
+
+ // Reparent
+ stack1Controller.reparent(dc.getDisplayId(), new Rect());
+ assertEquals(dc, stack1.getDisplayContent());
+ final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+ final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+ assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+ assertTrue(task1.mOnDisplayChangedCalled);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index bb9bc9eef97a..462bd68dc420 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -17,17 +17,16 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.After;
-import android.hardware.display.DisplayManagerGlobal;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.Display;
-import android.view.DisplayInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -46,95 +45,69 @@ import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
public class TaskStackContainersTests extends WindowTestsBase {
+ private TaskStack mPinnedStack;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mPinnedStack = new StackWindowController(PINNED_STACK_ID, null,
+ sDisplayContent.getDisplayId(), true /* onTop */, new Rect(), sWm).mContainer;
+
+ // Stack should contain visible app window to be considered visible.
+ final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
+ assertFalse(mPinnedStack.isVisible());
+ final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent);
+ pinnedTask.addChild(pinnedApp, 0 /* addPos */);
+ assertTrue(mPinnedStack.isVisible());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mPinnedStack.removeImmediately();
+ }
+
@Test
public void testStackPositionChildAt() throws Exception {
// Test that always-on-top stack can't be moved to position other than top.
final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
final TaskStack stack2 = createTaskStackOnDisplay(sDisplayContent);
- final TaskStack pinnedStack = addPinnedStack();
final WindowContainer taskStackContainer = stack1.getParent();
final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
- final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack);
+ final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
assertGreaterThan(pinnedStackPos, stack2Pos);
assertGreaterThan(stack2Pos, stack1Pos);
- taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, pinnedStack, false);
+ taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
- taskStackContainer.positionChildAt(1, pinnedStack, false);
+ taskStackContainer.positionChildAt(1, mPinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
}
+
@Test
public void testStackPositionBelowPinnedStack() throws Exception {
// Test that no stack can be above pinned stack.
- final TaskStack pinnedStack = addPinnedStack();
final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
final WindowContainer taskStackContainer = stack1.getParent();
final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
- final int pinnedStackPos = taskStackContainer.mChildren.indexOf(pinnedStack);
+ final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
assertGreaterThan(pinnedStackPos, stackPos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
taskStackContainer.positionChildAt(taskStackContainer.mChildren.size() - 1, stack1, false);
assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
- }
-
- @Test
- public void testReparentBetweenDisplays() throws Exception {
- // Create first stack on primary display.
- final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stack1.mStackId);
- final TestTask task1 = (TestTask) taskController.mContainer;
- task1.mOnDisplayChangedCalled = false;
-
- // Create second display and put second stack on it.
- final Display display = new Display(DisplayManagerGlobal.getInstance(),
- sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
- DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
- new WallpaperController(sWm));
- sWm.mRoot.addChild(dc, 1);
- final TaskStack stack2 = createTaskStackOnDisplay(dc);
-
- // Reparent and check state.DisplayContent.java:2572
- sWm.moveStackToDisplay(stack1.mStackId, dc.getDisplayId());
- assertEquals(dc, stack1.getDisplayContent());
- final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
- final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
- assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
- assertTrue(task1.mOnDisplayChangedCalled);
- }
-
- private TaskStack addPinnedStack() {
- TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
- if (pinnedStack == null) {
- sDisplayContent.addStackToDisplay(PINNED_STACK_ID, true);
- pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
- }
-
- if (!pinnedStack.isVisible()) {
- // Stack should contain visible app window to be considered visible.
- final Task pinnedTask = createTaskInStack(pinnedStack, 0 /* userId */);
- assertFalse(pinnedStack.isVisible());
- final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent);
- pinnedTask.addChild(pinnedApp, 0 /* addPos */);
- assertTrue(pinnedStack.isVisible());
- }
-
- return pinnedStack;
+ assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index 7cd3f648d8b1..f79908e906c7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -18,14 +18,14 @@ package com.android.server.wm;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-import org.junit.Test;
-
import android.hardware.display.DisplayManagerGlobal;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Display;
import android.view.DisplayInfo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -40,7 +40,7 @@ import static org.junit.Assert.assertTrue;
*/
@SmallTest
@Presubmit
-@org.junit.runner.RunWith(AndroidJUnit4.class)
+@RunWith(AndroidJUnit4.class)
public class TaskWindowContainerControllerTests extends WindowTestsBase {
@Test
@@ -57,7 +57,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
}
@Test
- public void testRemoveContainer_DeferRemoval() throws Exception {
+ public void testRemoveContainer_deferRemoval() throws Exception {
final TestTaskWindowContainerController taskController =
new TestTaskWindowContainerController();
final TestAppWindowContainerController appController =
@@ -83,58 +83,63 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testReparent() throws Exception {
- final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+ final StackWindowController stackController1 =
+ createStackControllerOnDisplay(sDisplayContent);
final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stack1.mStackId);
- final TaskStack stack2 = createTaskStackOnDisplay(sDisplayContent);
+ new TestTaskWindowContainerController(stackController1);
+ final StackWindowController stackController2 =
+ createStackControllerOnDisplay(sDisplayContent);
final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(stack2.mStackId);
+ new TestTaskWindowContainerController(stackController2);
boolean gotException = false;
try {
- taskController.reparent(stack1.mStackId, 0);
+ taskController.reparent(stackController1, 0);
} catch (IllegalArgumentException e) {
gotException = true;
}
assertTrue("Should not be able to reparent to the same parent", gotException);
+ final StackWindowController stackController3 =
+ createStackControllerOnDisplay(sDisplayContent);
+ stackController3.setContainer(null);
gotException = false;
try {
- taskController.reparent(sNextStackId + 1, 0);
+ taskController.reparent(stackController3, 0);
} catch (IllegalArgumentException e) {
gotException = true;
}
- assertTrue("Should not be able to reparent to a stackId that doesn't exist", gotException);
+ assertTrue("Should not be able to reparent to a stack that doesn't have a container",
+ gotException);
- taskController.reparent(stack2.mStackId, 0);
- assertEquals(stack2, taskController.mContainer.getParent());
+ taskController.reparent(stackController2, 0);
+ assertEquals(stackController2.mContainer, taskController.mContainer.getParent());
assertEquals(0, ((TestTask) taskController.mContainer).positionInParent());
assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent());
}
@Test
- public void testReparentBetweenDisplays() throws Exception {
+ public void testReparent_BetweenDisplays() throws Exception {
// Create first stack on primary display.
- final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+ final StackWindowController stack1Controller =
+ createStackControllerOnDisplay(sDisplayContent);
+ final TaskStack stack1 = stack1Controller.mContainer;
final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stack1.mStackId);
+ new TestTaskWindowContainerController(stack1Controller);
final TestTask task1 = (TestTask) taskController.mContainer;
task1.mOnDisplayChangedCalled = false;
+ assertEquals(sDisplayContent, stack1.getDisplayContent());
// Create second display and put second stack on it.
- final Display display = new Display(DisplayManagerGlobal.getInstance(),
- sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
- DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
- new WallpaperController(sWm));
- sWm.mRoot.addChild(dc, 1);
- final TaskStack stack2 = createTaskStackOnDisplay(dc);
+ final DisplayContent dc = createNewDisplay();
+ final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
+ final TaskStack stack2 = stack2Controller.mContainer;
final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(stack2.mStackId);
+ new TestTaskWindowContainerController(stack2Controller);
final TestTask task2 = (TestTask) taskController2.mContainer;
// Reparent and check state
- taskController.reparent(stack2.mStackId, 0);
+ taskController.reparent(stack2Controller, 0);
assertEquals(stack2, task1.getParent());
assertEquals(0, task1.positionInParent());
assertEquals(1, task2.positionInParent());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index 1514e692784e..c029a9f40e48 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -107,4 +107,8 @@ public class TestIWindow extends IWindow.Stub {
throws RemoteException {
}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ec429a05e3ca..1e471e3322d5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,49 +16,7 @@
package com.android.server.wm;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_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_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
-import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static org.mockito.Mockito.mock;
import android.annotation.Nullable;
@@ -70,12 +28,10 @@ import android.hardware.display.DisplayManagerInternal;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
import android.os.PowerManagerInternal;
@@ -163,127 +119,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public int windowTypeToLayerLw(int type) {
- // TODO: figure-out a good way to keep this in-sync with PhoneWindowManager...sigh!
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return 2;
- }
- switch (type) {
- case TYPE_PRESENTATION:
- case TYPE_PRIVATE_PRESENTATION:
- return 2;
- case TYPE_WALLPAPER:
- // wallpaper is at the bottom, though the window manager may move it.
- return 2;
- case TYPE_DOCK_DIVIDER:
- return 2;
- case TYPE_QS_DIALOG:
- return 2;
- case TYPE_PHONE:
- return 3;
- case TYPE_SEARCH_BAR:
- case TYPE_VOICE_INTERACTION_STARTING:
- return 4;
- case TYPE_VOICE_INTERACTION:
- // voice interaction layer is almost immediately above apps.
- return 5;
- case TYPE_INPUT_CONSUMER:
- return 6;
- case TYPE_SYSTEM_DIALOG:
- return 7;
- case TYPE_TOAST:
- // toasts and the plugged-in battery thing
- return 8;
- case TYPE_PRIORITY_PHONE:
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- return 9;
- case TYPE_DREAM:
- // used for Dreams (screensavers with TYPE_DREAM windows)
- return 10;
- case TYPE_SYSTEM_ALERT:
- // like the ANR / app crashed dialogs
- return 11;
- case TYPE_INPUT_METHOD:
- // on-screen keyboards and other such input method user interfaces go here.
- return 12;
- case TYPE_INPUT_METHOD_DIALOG:
- // on-screen keyboards and other such input method user interfaces go here.
- return 13;
- case TYPE_STATUS_BAR_SUB_PANEL:
- return 15;
- case TYPE_STATUS_BAR:
- return 16;
- case TYPE_STATUS_BAR_PANEL:
- return 17;
- case TYPE_KEYGUARD_DIALOG:
- return 18;
- case TYPE_VOLUME_OVERLAY:
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- return 19;
- case TYPE_SYSTEM_OVERLAY:
- // the on-screen volume indicator and controller shown when the user
- // changes the device volume
- return 20;
- case TYPE_NAVIGATION_BAR:
- // the navigation bar, if available, shows atop most things
- return 21;
- case TYPE_NAVIGATION_BAR_PANEL:
- // some panels (e.g. search) need to show on top of the navigation bar
- return 22;
- case TYPE_SCREENSHOT:
- // screenshot selection layer shouldn't go above system error, but it should cover
- // navigation bars at the very least.
- return 23;
- case TYPE_SYSTEM_ERROR:
- // system-level error dialogs
- return 24;
- case TYPE_MAGNIFICATION_OVERLAY:
- // used to highlight the magnified portion of a display
- return 25;
- case TYPE_DISPLAY_OVERLAY:
- // used to simulate secondary display devices
- return 26;
- case TYPE_DRAG:
- // the drag layer: input for drag-and-drop is associated with this window,
- // which sits above all other focusable windows
- return 27;
- case TYPE_ACCESSIBILITY_OVERLAY:
- // overlay put by accessibility services to intercept user interaction
- return 28;
- case TYPE_SECURE_SYSTEM_OVERLAY:
- return 29;
- case TYPE_BOOT_PROGRESS:
- return 30;
- case TYPE_POINTER:
- // the (mouse) pointer layer
- return 31;
- }
- Log.e(TAG, "Unknown window type: " + type);
- return 2;
- }
-
- @Override
- public int subWindowTypeToLayerLw(int type) {
- // TODO: figure-out a good way to keep this in-sync with PhoneWindowManager...
- switch (type) {
- case TYPE_APPLICATION_PANEL:
- case TYPE_APPLICATION_ATTACHED_DIALOG:
- return 1;
- case TYPE_APPLICATION_MEDIA:
- return -2;
- case TYPE_APPLICATION_MEDIA_OVERLAY:
- return -1;
- case TYPE_APPLICATION_SUB_PANEL:
- return 2;
- case TYPE_APPLICATION_ABOVE_SUB_PANEL:
- return 3;
- }
- Log.e(TAG, "Unknown sub-window type: " + type);
- return 0;
- }
-
- @Override
public int getMaxWallpaperLayer() {
return 0;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 4f740ac46646..4f9cd9547a52 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -388,6 +388,32 @@ public class WindowContainerTests extends WindowTestsBase {
}
@Test
+ public void testGetOrientation_childSpecified() throws Exception {
+ testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
+ SCREEN_ORIENTATION_LANDSCAPE);
+ testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
+ SCREEN_ORIENTATION_UNSET);
+ }
+
+ private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
+ int expectedOrientation) {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).build();
+ root.setFillsParent(true);
+
+ builder.setIsVisible(childVisible);
+
+ if (childOrientation != SCREEN_ORIENTATION_UNSET) {
+ builder.setOrientation(childOrientation);
+ }
+
+ final TestWindowContainer child1 = root.addChildWindow(builder);
+ child1.setFillsParent(true);
+
+ assertTrue(root.getOrientation() == expectedOrientation);
+ }
+
+ @Test
public void testGetOrientation_Unset() throws Exception {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
@@ -407,18 +433,17 @@ public class WindowContainerTests extends WindowTestsBase {
invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
// Landscape well because the container is visible and that is what we set on it above.
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
- // Unset because the container isn't visible even though it has a child that thinks it is
- // visible.
- assertEquals(SCREEN_ORIENTATION_UNSET, invisible.getOrientation());
- // Unspecified because we are visible and we didn't specify an orientation and there isn't
- // a visible child.
- assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+ // Landscape because even though the container isn't visible it has a child that is
+ // specifying it can influence the orientation by being visible.
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation());
+ // Landscape because the grandchild is visible and therefore can participate.
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
builder.setIsVisible(true).setLayer(-3);
final TestWindowContainer visibleUnset = root.addChildWindow(builder);
visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
- assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
}
@@ -690,6 +715,7 @@ public class WindowContainerTests extends WindowTestsBase {
private boolean mIsAnimating;
private boolean mIsVisible;
private boolean mFillsParent;
+ private Integer mOrientation;
private boolean mOnParentSetCalled;
@@ -708,11 +734,13 @@ public class WindowContainerTests extends WindowTestsBase {
return 1;
};
- TestWindowContainer(int layer, boolean isAnimating, boolean isVisible) {
+ TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
+ Integer orientation) {
mLayer = layer;
mIsAnimating = isAnimating;
mIsVisible = isVisible;
mFillsParent = true;
+ mOrientation = orientation;
}
TestWindowContainer getParentWindow() {
@@ -758,6 +786,11 @@ public class WindowContainerTests extends WindowTestsBase {
}
@Override
+ int getOrientation() {
+ return mOrientation != null ? mOrientation : super.getOrientation();
+ }
+
+ @Override
boolean fillsParent() {
return mFillsParent;
}
@@ -771,6 +804,7 @@ public class WindowContainerTests extends WindowTestsBase {
private int mLayer;
private boolean mIsAnimating;
private boolean mIsVisible;
+ private Integer mOrientation;
public TestWindowContainerBuilder() {
reset();
@@ -791,15 +825,21 @@ public class WindowContainerTests extends WindowTestsBase {
return this;
}
+ TestWindowContainerBuilder setOrientation(int orientation) {
+ mOrientation = orientation;
+ return this;
+ }
+
TestWindowContainerBuilder reset() {
mLayer = 0;
mIsAnimating = false;
mIsVisible = false;
+ mOrientation = null;
return this;
}
TestWindowContainer build() {
- return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible);
+ return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 085cfd8b1ef0..98ff0e254a19 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -57,7 +57,8 @@ public class WindowFrameTests {
final Task mTask;
boolean mDockedResizingForTest = false;
WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
- super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0);
+ super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0,
+ false /* ownerCanAddInternalSystemWindow */);
mTask = t;
}
@@ -77,7 +78,7 @@ public class WindowFrameTests {
final Rect mInsetBounds = new Rect();
boolean mFullscreenForTest = true;
TaskWithBounds(Rect bounds) {
- super(0, mStubStack, 0, sWm, null, null, false, 0, false, new TaskDescription(), null);
+ super(0, mStubStack, 0, sWm, null, null, 0, false, false, new TaskDescription(), null);
mBounds = bounds;
}
@Override
@@ -105,7 +106,7 @@ public class WindowFrameTests {
sWm.mSystemDecorLayer = 10000;
mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
- sWm.getDefaultDisplayContentLocked());
+ sWm.getDefaultDisplayContentLocked(), false /* ownerCanManageAppTokens */);
mStubStack = new TaskStack(sWm, 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index ae344ddb38f3..bc850170d4b2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -20,7 +20,10 @@ import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManagerInternal;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
+import android.view.Display;
+import android.view.DisplayInfo;
import android.view.IApplicationToken;
import org.junit.Assert;
import org.junit.Before;
@@ -28,6 +31,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import android.app.ActivityManager.TaskSnapshot;
import android.content.Context;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
@@ -39,6 +43,7 @@ import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.EMPTY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -64,11 +69,13 @@ class WindowTestsBase {
static TestWindowManagerPolicy sPolicy = null;
private final static IWindow sIWindow = new TestIWindow();
private final static Session sMockSession = mock(Session.class);
+ private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
private static int sNextTaskId = 0;
private static boolean sOneTimeSetupDone = false;
static DisplayContent sDisplayContent;
+ static DisplayInfo sDisplayInfo = new DisplayInfo();
static WindowLayersController sLayersController;
static WindowState sWallpaperWindow;
static WindowState sImeWindow;
@@ -95,9 +102,19 @@ class WindowTestsBase {
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
sPolicy = (TestWindowManagerPolicy) sWm.mPolicy;
sLayersController = new WindowLayersController(sWm);
- sDisplayContent = new DisplayContent(context.getDisplay(), sWm, sLayersController,
- new WallpaperController(sWm));
- sWm.mRoot.addChild(sDisplayContent, 0);
+ sDisplayContent = sWm.mRoot.getDisplayContent(context.getDisplay().getDisplayId());
+ if (sDisplayContent != null) {
+ sDisplayContent.removeImmediately();
+ }
+ // Make sure that display ids don't overlap, so there won't be several displays with same
+ // ids among RootWindowContainer children.
+ for (DisplayContent dc : sWm.mRoot.mChildren) {
+ if (dc.getDisplayId() >= sNextDisplayId) {
+ sNextDisplayId = dc.getDisplayId() + 1;
+ }
+ }
+ context.getDisplay().getDisplayInfo(sDisplayInfo);
+ sDisplayContent = createNewDisplay();
sWm.mDisplayEnabled = true;
sWm.mDisplayReady = true;
@@ -164,7 +181,7 @@ class WindowTestsBase {
attrs.setTitle(name);
final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
- 0, attrs, 0, 0);
+ 0, attrs, 0, 0, false /* ownerCanAddInternalSystemWindow */);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
// adding it to the token...
token.addWindow(w);
@@ -173,19 +190,31 @@ class WindowTestsBase {
/** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
static TaskStack createTaskStackOnDisplay(DisplayContent dc) {
- final int stackId = sNextStackId++;
- dc.addStackToDisplay(stackId, true);
- return sWm.mStackIdToStack.get(stackId);
+ return createStackControllerOnDisplay(dc).mContainer;
+ }
+
+ static StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
+ final int stackId = ++sNextStackId;
+ return new StackWindowController(stackId, null, dc.getDisplayId(),
+ true /* onTop */, new Rect(), sWm);
}
- /**Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
+ /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
static Task createTaskInStack(TaskStack stack, int userId) {
- final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, false, 0,
+ final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false,
false, new TaskDescription(), null);
stack.addTask(newTask, POSITION_TOP);
return newTask;
}
+ /** Creates a {@link DisplayContent} and adds it to the system. */
+ DisplayContent createNewDisplay() {
+ final int displayId = sNextDisplayId++;
+ final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+ sDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+ return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm));
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
static class TestWindowToken extends WindowToken {
@@ -194,7 +223,8 @@ class WindowTestsBase {
}
TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
- super(sWm, mock(IBinder.class), type, persistOnEmpty, dc);
+ super(sWm, mock(IBinder.class), type, persistOnEmpty, dc,
+ false /* ownerCanManageAppTokens */);
}
int getWindowsCount() {
@@ -213,6 +243,16 @@ class WindowTestsBase {
super(sWm, null, false, dc);
}
+ TestAppWindowToken(WindowManagerService service, IApplicationToken token,
+ boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+ boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+ int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ boolean alwaysFocusable, AppWindowContainerController controller) {
+ super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
+ showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
+ launchTaskBehind, alwaysFocusable, controller);
+ }
+
int getWindowsCount() {
return mChildren.size();
}
@@ -228,6 +268,10 @@ class WindowTestsBase {
WindowState getLastChild() {
return mChildren.getLast();
}
+
+ int positionInParent() {
+ return getParent().mChildren.indexOf(this);
+ }
}
/* Used so we can gain access to some protected members of the {@link Task} class */
@@ -235,12 +279,14 @@ class WindowTestsBase {
boolean mShouldDeferRemoval = false;
boolean mOnDisplayChangedCalled = false;
+ private boolean mUseLocalIsAnimating = false;
+ private boolean mIsAnimating = false;
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
- Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
boolean homeTask, TaskWindowContainerController controller) {
- super(taskId, stack, userId, service, bounds, overrideConfig, isOnTopLauncher,
- resizeMode, homeTask, new TaskDescription(), controller);
+ super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, new TaskDescription(), controller);
}
boolean shouldDeferRemoval() {
@@ -256,6 +302,16 @@ class WindowTestsBase {
super.onDisplayChanged(dc);
mOnDisplayChangedCalled = true;
}
+
+ @Override
+ boolean isAnimating() {
+ return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+ }
+
+ void setLocalIsAnimating(boolean isAnimating) {
+ mUseLocalIsAnimating = true;
+ mIsAnimating = isAnimating;
+ }
}
/**
@@ -265,22 +321,32 @@ class WindowTestsBase {
class TestTaskWindowContainerController extends TaskWindowContainerController {
TestTaskWindowContainerController() {
- this(createTaskStackOnDisplay(sDisplayContent).mStackId);
+ this(createStackControllerOnDisplay(sDisplayContent));
}
- TestTaskWindowContainerController(int stackId) {
- super(sNextTaskId++, snapshot -> {}, stackId, 0 /* userId */, null /* bounds */,
- EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, false /* homeTask*/,
- false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */,
- new TaskDescription());
+ TestTaskWindowContainerController(StackWindowController stackController) {
+ super(sNextTaskId++, new TaskWindowContainerListener() {
+ @Override
+ public void onSnapshotChanged(TaskSnapshot snapshot) {
+
+ }
+
+ @Override
+ public void requestResize(Rect bounds, int resizeMode) {
+
+ }
+ }, stackController, 0 /* userId */, null /* bounds */,
+ EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
+ false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
+ true /* showForAllUsers */, new TaskDescription(), sWm);
}
@Override
TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
- Configuration overrideConfig, int resizeMode, boolean homeTask,
- boolean isOnTopLauncher, TaskDescription taskDescription) {
- return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig,
- isOnTopLauncher, resizeMode, homeTask, this);
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, TaskDescription taskDescription) {
+ return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, this);
}
}
@@ -303,6 +369,19 @@ class WindowTestsBase {
mToken = token;
}
+ @Override
+ AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
+ boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+ boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+ int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ boolean alwaysFocusable, AppWindowContainerController controller) {
+ return new TestAppWindowToken(service, token, voiceInteraction, dc,
+ inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
+ orientation,
+ rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+ controller);
+ }
+
AppWindowToken getAppWindowToken() {
return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder());
}
@@ -322,7 +401,8 @@ class WindowTestsBase {
boolean resizeReported;
TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
- super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0);
+ super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
+ false /* ownerCanAddInternalSystemWindow */);
}
@Override
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 6dfb48bfbcf9..7a69803c8463 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -106,7 +106,7 @@ public class UsageStatsService extends SystemService implements
private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
- private static final boolean ENABLE_KERNEL_UPDATES = false;
+ private static final boolean ENABLE_KERNEL_UPDATES = true;
private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
long mAppIdleScreenThresholdMillis;
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
index feabf0a970c2..f560e71ebe6a 100644
--- a/services/usb/Android.mk
+++ b/services/usb/Android.mk
@@ -8,5 +8,7 @@ LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
LOCAL_JAVA_LIBRARIES := services.core
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb@1.0-java-static \
+android.hidl.manager@1.0-java-static
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index fbbe636e6220..07b4ca12171f 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -17,6 +17,7 @@
package com.android.server.usb;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -134,6 +135,8 @@ public class UsbDeviceManager {
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+ private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
+
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -157,6 +160,7 @@ public class UsbDeviceManager {
private final UsbAlsaManager mUsbAlsaManager;
private final UsbSettingsManager mSettingsManager;
private Intent mBroadcastedIntent;
+ private boolean mPendingBootBroadcast;
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -238,6 +242,16 @@ public class UsbDeviceManager {
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ // Ensure that the notification channels are set up
+ if (isTv()) {
+ // TV-specific notification channel
+ mNotificationManager.createNotificationChannel(
+ new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV,
+ mContext.getString(
+ com.android.internal.R.string.adb_debugging_notification_channel_tv),
+ NotificationManager.IMPORTANCE_HIGH));
+ }
+
// We do not show the USB notification if the primary volume supports mass storage.
// The legacy mass storage UI will be used instead.
boolean massStorageSupported = false;
@@ -324,6 +338,10 @@ public class UsbDeviceManager {
}
}
+ private boolean isTv() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
private final class UsbHandler extends Handler {
// current USB state
@@ -755,13 +773,16 @@ public class UsbDeviceManager {
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
- } else if (!mConnected) {
- // restore defaults when USB is disconnected
- setEnabledFunctions(null, false, false);
}
if (mBootCompleted) {
+ if (!mConnected) {
+ // restore defaults when USB is disconnected
+ setEnabledFunctions(null, false, false);
+ }
updateUsbStateBroadcastIfNeeded(false);
updateUsbFunctions();
+ } else {
+ mPendingBootBroadcast = true;
}
break;
case MSG_UPDATE_HOST_STATE:
@@ -773,6 +794,8 @@ public class UsbDeviceManager {
updateUsbNotification();
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded(false);
+ } else {
+ mPendingBootBroadcast = true;
}
break;
case MSG_ENABLE_ADB:
@@ -792,6 +815,10 @@ public class UsbDeviceManager {
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
+ if (mPendingBootBroadcast) {
+ updateUsbStateBroadcastIfNeeded(false);
+ mPendingBootBroadcast = false;
+ }
setEnabledFunctions(null, false, false);
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -918,9 +945,9 @@ public class UsbDeviceManager {
CharSequence message = r.getText(
com.android.internal.R.string.adb_active_notification_message);
- Intent intent = Intent.makeRestartActivityTask(
- new ComponentName("com.android.settings",
- "com.android.settings.DevelopmentSettings"));
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
@@ -937,6 +964,8 @@ public class UsbDeviceManager {
.setContentText(message)
.setContentIntent(pi)
.setVisibility(Notification.VISIBILITY_PUBLIC)
+ .extend(new Notification.TvExtender()
+ .setChannel(ADB_NOTIFICATION_CHANNEL_ID_TV))
.build();
mAdbNotificationShown = true;
mNotificationManager.notifyAsUser(null, id, notification,
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 4aff3d54834a..4b8e4c8ab13a 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,36 +16,40 @@
package com.android.server.usb;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.FgThread;
-
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.V1_0.IUsb;
+import android.hardware.usb.V1_0.IUsbCallback;
+import android.hardware.usb.V1_0.PortRole;
+import android.hardware.usb.V1_0.PortRoleType;
+import android.hardware.usb.V1_0.PortStatus;
+import android.hardware.usb.V1_0.Status;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.HwBinder;
import android.os.Message;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UEventObserver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
-import libcore.io.IoUtils;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
/**
* Allows trusted components to control the properties of physical USB ports
- * via the "/sys/class/dual_role_usb" kernel interface.
+ * via the IUsb.hal.
* <p>
* Note: This interface may not be supported on all chipsets since the USB drivers
* must be changed to publish this information through the module. At the moment
@@ -60,43 +64,6 @@ public class UsbPortManager {
private static final int MSG_UPDATE_PORTS = 1;
- // UEvent path to watch.
- private static final String UEVENT_FILTER = "SUBSYSTEM=dual_role_usb";
-
- // SysFS directory that contains USB ports as subdirectories.
- private static final String SYSFS_CLASS = "/sys/class/dual_role_usb";
-
- // SysFS file that contains a USB port's supported modes. (read-only)
- // Contents: "", "ufp", "dfp", or "ufp dfp".
- private static final String SYSFS_PORT_SUPPORTED_MODES = "supported_modes";
-
- // SysFS file that contains a USB port's current mode. (read-write if configurable)
- // Contents: "", "ufp", or "dfp".
- private static final String SYSFS_PORT_MODE = "mode";
-
- // SysFS file that contains a USB port's current power role. (read-write if configurable)
- // Contents: "", "source", or "sink".
- private static final String SYSFS_PORT_POWER_ROLE = "power_role";
-
- // SysFS file that contains a USB port's current data role. (read-write if configurable)
- // Contents: "", "host", or "device".
- private static final String SYSFS_PORT_DATA_ROLE = "data_role";
-
- // Port modes: upstream facing port or downstream facing port.
- private static final String PORT_MODE_DFP = "dfp";
- private static final String PORT_MODE_UFP = "ufp";
-
- // Port power roles: source or sink.
- private static final String PORT_POWER_ROLE_SOURCE = "source";
- private static final String PORT_POWER_ROLE_SINK = "sink";
-
- // Port data roles: host or device.
- private static final String PORT_DATA_ROLE_HOST = "host";
- private static final String PORT_DATA_ROLE_DEVICE = "device";
-
- private static final String USB_TYPEC_PROP_PREFIX = "sys.usb.typec.";
- private static final String USB_TYPEC_STATE = "sys.usb.typec.state";
-
// All non-trivial role combinations.
private static final int COMBO_SOURCE_HOST =
UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
@@ -110,8 +77,29 @@ public class UsbPortManager {
// The system context.
private final Context mContext;
- // True if we have kernel support.
- private final boolean mHaveKernelSupport;
+ // Proxy object for the usb hal daemon.
+ // @GuardedBy("mLock")
+ private IUsb mProxy = null;
+
+ // Callback when the UsbPort status is changed by the kernel.
+ // Mostly due a command sent by the remote Usb device.
+ private HALCallback mHALCallback = new HALCallback(null, this);
+
+ // Notification object used to listen to the start of the usb daemon.
+ private final ServiceNotification mServiceNotification = new ServiceNotification();
+
+ // Cookie sent for usb hal death notification.
+ private static final int USB_HAL_DEATH_COOKIE = 1000;
+
+ // Usb hal service name.
+ private static String sSERVICENAME = "usb_hal";
+
+ // Used as the key while sending the bundle to Main thread.
+ private static final String PORT_INFO = "port_info";
+
+ // This is monitored to prevent updating the protInfo before the system
+ // is ready.
+ private boolean mSystemReady;
// Mutex for all mutable shared state.
private final Object mLock = new Object();
@@ -123,17 +111,37 @@ public class UsbPortManager {
private final ArrayMap<String, PortInfo> mPorts = new ArrayMap<String, PortInfo>();
// List of all simulated ports, indexed by id.
- private final ArrayMap<String, SimulatedPortInfo> mSimulatedPorts =
- new ArrayMap<String, SimulatedPortInfo>();
+ private final ArrayMap<String, RawPortInfo> mSimulatedPorts =
+ new ArrayMap<String, RawPortInfo>();
public UsbPortManager(Context context) {
mContext = context;
- mHaveKernelSupport = new File(SYSFS_CLASS).exists();
+ try {
+ boolean ret = IServiceManager.getService("manager")
+ .registerForNotifications("android.hardware.usb@1.0::IUsb",
+ "", mServiceNotification);
+ if (!ret) {
+ logAndPrint(Log.ERROR, null, "Failed to register service start notification");
+ }
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, null, "Failed to register service start notification");
+ Thread.dumpStack();
+ return;
+ }
+ connectToProxy(null);
}
public void systemReady() {
- mUEventObserver.startObserving(UEVENT_FILTER);
- scheduleUpdatePorts();
+ if (mProxy != null) {
+ try {
+ mProxy.queryPortStatus();
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, null,
+ "ServiceStart: Failed to query port status");
+ Thread.dumpStack();
+ }
+ }
+ mSystemReady = true;
}
public UsbPort[] getPorts() {
@@ -223,20 +231,14 @@ public class UsbPortManager {
+ ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
- SimulatedPortInfo sim = mSimulatedPorts.get(portId);
+ RawPortInfo sim = mSimulatedPorts.get(portId);
if (sim != null) {
// Change simulated state.
sim.mCurrentMode = newMode;
sim.mCurrentPowerRole = newPowerRole;
sim.mCurrentDataRole = newDataRole;
- } else if (mHaveKernelSupport) {
- // Change actual state.
- final File portDir = new File(SYSFS_CLASS, portId);
- if (!portDir.exists()) {
- logAndPrint(Log.ERROR, pw, "USB port not found: portId=" + portId);
- return;
- }
-
+ updatePortsLocked(pw, null);
+ } else if (mProxy != null) {
if (currentMode != newMode) {
// Changing the mode will have the side-effect of also changing
// the power and data roles but it might take some time to apply
@@ -244,38 +246,54 @@ public class UsbPortManager {
// hardware, we have no way of knowing whether it will work apriori
// which is why we would prefer to set the power and data roles
// directly instead.
- if (!writeFile(portDir, SYSFS_PORT_MODE,
- newMode == UsbPort.MODE_DFP ? PORT_MODE_DFP : PORT_MODE_UFP)) {
- logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: "
+
+ logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newMode));
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.MODE;
+ newRole.role = newMode;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: "
+ + "portId=" + portId
+ + ", newMode=" + UsbPort.modeToString(newRole.role));
+ Thread.dumpStack();
return;
}
} else {
// Change power and data role independently as needed.
if (currentPowerRole != newPowerRole) {
- if (!writeFile(portDir, SYSFS_PORT_POWER_ROLE,
- newPowerRole == UsbPort.POWER_ROLE_SOURCE
- ? PORT_POWER_ROLE_SOURCE : PORT_POWER_ROLE_SINK)) {
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.POWER_ROLE;
+ newRole.role = newPowerRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
logAndPrint(Log.ERROR, pw, "Failed to set the USB port power role: "
+ "portId=" + portId
- + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole));
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newRole.role));
+ Thread.dumpStack();
return;
}
}
if (currentDataRole != newDataRole) {
- if (!writeFile(portDir, SYSFS_PORT_DATA_ROLE,
- newDataRole == UsbPort.DATA_ROLE_HOST
- ? PORT_DATA_ROLE_HOST : PORT_DATA_ROLE_DEVICE)) {
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.DATA_ROLE;
+ newRole.role = newDataRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
logAndPrint(Log.ERROR, pw, "Failed to set the USB port data role: "
+ "portId=" + portId
- + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+ + ", newDataRole=" + UsbPort.dataRoleToString(newRole.role));
+ Thread.dumpStack();
return;
}
}
}
}
- updatePortsLocked(pw);
}
}
@@ -289,8 +307,8 @@ public class UsbPortManager {
pw.println("Adding simulated port: portId=" + portId
+ ", supportedModes=" + UsbPort.modeToString(supportedModes));
mSimulatedPorts.put(portId,
- new SimulatedPortInfo(portId, supportedModes));
- updatePortsLocked(pw);
+ new RawPortInfo(portId, supportedModes));
+ updatePortsLocked(pw, null);
}
}
@@ -298,7 +316,7 @@ public class UsbPortManager {
int powerRole, boolean canChangePowerRole,
int dataRole, boolean canChangeDataRole, IndentingPrintWriter pw) {
synchronized (mLock) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ final RawPortInfo portInfo = mSimulatedPorts.get(portId);
if (portInfo == null) {
pw.println("Cannot connect simulated port which does not exist.");
return;
@@ -328,13 +346,13 @@ public class UsbPortManager {
portInfo.mCanChangePowerRole = canChangePowerRole;
portInfo.mCurrentDataRole = dataRole;
portInfo.mCanChangeDataRole = canChangeDataRole;
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
synchronized (mLock) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ final RawPortInfo portInfo = mSimulatedPorts.get(portId);
if (portInfo == null) {
pw.println("Cannot disconnect simulated port which does not exist.");
return;
@@ -347,7 +365,7 @@ public class UsbPortManager {
portInfo.mCanChangePowerRole = false;
portInfo.mCurrentDataRole = 0;
portInfo.mCanChangeDataRole = false;
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
@@ -361,7 +379,7 @@ public class UsbPortManager {
pw.println("Disconnecting simulated port: portId=" + portId);
mSimulatedPorts.removeAt(index);
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
@@ -370,7 +388,7 @@ public class UsbPortManager {
pw.println("Removing all simulated ports and ending simulation.");
if (!mSimulatedPorts.isEmpty()) {
mSimulatedPorts.clear();
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
}
@@ -393,9 +411,108 @@ public class UsbPortManager {
}
}
- private void updatePortsLocked(IndentingPrintWriter pw) {
- // Assume all ports are gone unless informed otherwise.
- // Kind of pessimistic but simple.
+ private static class HALCallback extends IUsbCallback.Stub {
+ public IndentingPrintWriter pw;
+ public UsbPortManager portManager;
+
+ HALCallback() {
+ super();
+ }
+
+ HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
+ this.pw = pw;
+ this.portManager = portManager;
+ }
+
+ public void notifyPortStatusChange(ArrayList<PortStatus> currentPortStatus, int retval) {
+ if (!portManager.mSystemReady) return;
+
+ if (retval != Status.SUCCESS) {
+ logAndPrint(Log.ERROR, pw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<RawPortInfo>();
+
+ for (PortStatus current : currentPortStatus) {
+ RawPortInfo temp = new RawPortInfo(current.portName,
+ current.supportedModes, current.currentMode,
+ current.canChangeMode, current.currentPowerRole,
+ current.canChangePowerRole,
+ current.currentDataRole, current.canChangeDataRole);
+ newPortInfo.add(temp);
+ logAndPrint(Log.INFO, pw, "ClientCallback: " + current.portName);
+ }
+
+ Message message = portManager.mHandler.obtainMessage();
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
+ message.what = MSG_UPDATE_PORTS;
+ message.setData(bundle);
+ portManager.mHandler.sendMessage(message);
+ return;
+ }
+
+ public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
+ if (retval == Status.SUCCESS) {
+ logAndPrint(Log.INFO, pw, portName + "role switch successful");
+ } else {
+ logAndPrint(Log.ERROR, pw, portName + "role switch failed");
+ }
+ }
+ };
+
+ final class DeathRecipient implements HwBinder.DeathRecipient {
+ public IndentingPrintWriter pw;
+
+ DeathRecipient(IndentingPrintWriter pw) {
+ this.pw = pw;
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_HAL_DEATH_COOKIE) {
+ logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
+ synchronized (mLock) {
+ mProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
+ connectToProxy(null);
+ }
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ if (mProxy != null) return;
+
+ try {
+ mProxy = IUsb.getService(sSERVICENAME);
+ mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
+ mProxy.setCallback(mHALCallback);
+ mProxy.queryPortStatus();
+ } catch (NoSuchElementException e) {
+ logAndPrint(Log.ERROR, pw, sSERVICENAME + "not found."
+ + " Did the service failed to start ?");
+ Thread.dumpStack();
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, pw, sSERVICENAME + "connectToProxy: Service not responding");
+ Thread.dumpStack();
+ }
+ }
+ }
+
+ /**
+ * Simulated ports directly add the new roles to mSimulatedPorts before calling.
+ * USB hal callback populates and sends the newPortInfo.
+ */
+ private void updatePortsLocked(IndentingPrintWriter pw, ArrayList<RawPortInfo> newPortInfo) {
for (int i = mPorts.size(); i-- > 0; ) {
mPorts.valueAt(i).mDisposition = PortInfo.DISPOSITION_REMOVED;
}
@@ -404,34 +521,18 @@ public class UsbPortManager {
if (!mSimulatedPorts.isEmpty()) {
final int count = mSimulatedPorts.size();
for (int i = 0; i < count; i++) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.valueAt(i);
+ final RawPortInfo portInfo = mSimulatedPorts.valueAt(i);
addOrUpdatePortLocked(portInfo.mPortId, portInfo.mSupportedModes,
portInfo.mCurrentMode, portInfo.mCanChangeMode,
portInfo.mCurrentPowerRole, portInfo.mCanChangePowerRole,
portInfo.mCurrentDataRole, portInfo.mCanChangeDataRole, pw);
}
- } else if (mHaveKernelSupport) {
- final File[] portDirs = new File(SYSFS_CLASS).listFiles();
- if (portDirs != null) {
- for (File portDir : portDirs) {
- if (!portDir.isDirectory()) {
- continue;
- }
-
- // Parse the sysfs file contents.
- final String portId = portDir.getName();
- final int supportedModes = readSupportedModes(portDir);
- final int currentMode = readCurrentMode(portDir);
- final boolean canChangeMode = canChangeMode(portDir);
- final int currentPowerRole = readCurrentPowerRole(portDir);
- final boolean canChangePowerRole = canChangePowerRole(portDir);
- final int currentDataRole = readCurrentDataRole(portDir);
- final boolean canChangeDataRole = canChangeDataRole(portDir);
- addOrUpdatePortLocked(portId, supportedModes,
- currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole, pw);
- }
+ } else {
+ for (RawPortInfo currentPortInfo : newPortInfo) {
+ addOrUpdatePortLocked(currentPortInfo.mPortId, currentPortInfo.mSupportedModes,
+ currentPortInfo.mCurrentMode, currentPortInfo.mCanChangeMode,
+ currentPortInfo.mCurrentPowerRole, currentPortInfo.mCanChangePowerRole,
+ currentPortInfo.mCurrentDataRole, currentPortInfo.mCanChangeDataRole, pw);
}
}
@@ -457,20 +558,21 @@ public class UsbPortManager {
}
}
+
// Must only be called by updatePortsLocked.
private void addOrUpdatePortLocked(String portId, int supportedModes,
- int currentMode, boolean canChangeMode,
- int currentPowerRole, boolean canChangePowerRole,
- int currentDataRole, boolean canChangeDataRole,
- IndentingPrintWriter pw) {
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole,
+ IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
if (supportedModes != UsbPort.MODE_DUAL) {
canChangeMode = false;
if (currentMode != 0 && currentMode != supportedModes) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB "
- + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes)
- + ", currentMode=" + UsbPort.modeToString(currentMode));
+ + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes)
+ + ", currentMode=" + UsbPort.modeToString(currentMode));
currentMode = 0;
}
}
@@ -485,8 +587,8 @@ public class UsbPortManager {
// Can change both power and data role independently.
// Assume all combinations are possible.
supportedRoleCombinations |=
- COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE
- | COMBO_SINK_HOST | COMBO_SINK_DEVICE;
+ COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE
+ | COMBO_SINK_HOST | COMBO_SINK_DEVICE;
} else if (canChangePowerRole) {
// Can only change power role.
// Assume data role must remain at its current value.
@@ -514,24 +616,24 @@ public class UsbPortManager {
if (portInfo == null) {
portInfo = new PortInfo(portId, supportedModes);
portInfo.setStatus(currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole,
- supportedRoleCombinations);
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations);
mPorts.put(portId, portInfo);
} else {
// Sanity check that ports aren't changing definition out from under us.
if (supportedModes != portInfo.mUsbPort.getSupportedModes()) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from "
- + "USB port driver (should be immutable): "
- + "previous=" + UsbPort.modeToString(
- portInfo.mUsbPort.getSupportedModes())
- + ", current=" + UsbPort.modeToString(supportedModes));
+ + "USB port driver (should be immutable): "
+ + "previous=" + UsbPort.modeToString(
+ portInfo.mUsbPort.getSupportedModes())
+ + ", current=" + UsbPort.modeToString(supportedModes));
}
if (portInfo.setStatus(currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole,
- supportedRoleCombinations)) {
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -572,120 +674,6 @@ public class UsbPortManager {
});
}
- private void scheduleUpdatePorts() {
- if (!mHandler.hasMessages(MSG_UPDATE_PORTS)) {
- mHandler.sendEmptyMessage(MSG_UPDATE_PORTS);
- }
- }
-
- private static int readSupportedModes(File portDir) {
- int modes = 0;
- final String contents = readFile(portDir, SYSFS_PORT_SUPPORTED_MODES);
- if (contents != null) {
- if (contents.contains(PORT_MODE_DFP)) {
- modes |= UsbPort.MODE_DFP;
- }
- if (contents.contains(PORT_MODE_UFP)) {
- modes |= UsbPort.MODE_UFP;
- }
- }
- return modes;
- }
-
- private static int readCurrentMode(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_MODE);
- if (contents != null) {
- if (contents.equals(PORT_MODE_DFP)) {
- return UsbPort.MODE_DFP;
- }
- if (contents.equals(PORT_MODE_UFP)) {
- return UsbPort.MODE_UFP;
- }
- }
- return 0;
- }
-
- private static int readCurrentPowerRole(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_POWER_ROLE);
- if (contents != null) {
- if (contents.equals(PORT_POWER_ROLE_SOURCE)) {
- return UsbPort.POWER_ROLE_SOURCE;
- }
- if (contents.equals(PORT_POWER_ROLE_SINK)) {
- return UsbPort.POWER_ROLE_SINK;
- }
- }
- return 0;
- }
-
- private static int readCurrentDataRole(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_DATA_ROLE);
- if (contents != null) {
- if (contents.equals(PORT_DATA_ROLE_HOST)) {
- return UsbPort.DATA_ROLE_HOST;
- }
- if (contents.equals(PORT_DATA_ROLE_DEVICE)) {
- return UsbPort.DATA_ROLE_DEVICE;
- }
- }
- return 0;
- }
-
- private static boolean fileIsRootWritable(String path) {
- try {
- // If the file is user writable, then it is root writable.
- return (Os.stat(path).st_mode & OsConstants.S_IWUSR) != 0;
- } catch (ErrnoException e) {
- return false;
- }
- }
-
- private static boolean canChangeMode(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_MODE).getPath());
- }
-
- private static boolean canChangePowerRole(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_POWER_ROLE).getPath());
- }
-
- private static boolean canChangeDataRole(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_DATA_ROLE).getPath());
- }
-
- private static String readFile(File dir, String filename) {
- final File file = new File(dir, filename);
- try {
- return IoUtils.readFileAsString(file.getAbsolutePath()).trim();
- } catch (IOException ex) {
- return null;
- }
- }
-
- private static boolean waitForState(String property, String state) {
- // wait for the transition to complete.
- // give up after 5 seconds.
- // 5 seconds is probably too long, but we have seen hardware that takes
- // over 3 seconds to change states.
- String value = null;
- for (int i = 0; i < 100; i++) {
- // State transition is done when property is set to the new configuration
- value = SystemProperties.get(property);
- if (state.equals(value)) return true;
- SystemClock.sleep(50);
- }
- Slog.e(TAG, "waitForState(" + state + ") for " + property + " FAILED: got " + value);
- return false;
- }
-
- private static String propertyFromFilename(String filename) {
- return USB_TYPEC_PROP_PREFIX + filename;
- }
-
- private static boolean writeFile(File dir, String filename, String contents) {
- SystemProperties.set(propertyFromFilename(filename), contents);
- return waitForState(USB_TYPEC_STATE, contents);
- }
-
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
Slog.println(priority, TAG, msg);
if (pw != null) {
@@ -698,8 +686,10 @@ public class UsbPortManager {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_PORTS: {
+ Bundle b = msg.getData();
+ ArrayList<RawPortInfo> PortInfo = b.getParcelableArrayList(PORT_INFO);
synchronized (mLock) {
- updatePortsLocked(null);
+ updatePortsLocked(null, PortInfo);
}
break;
}
@@ -707,13 +697,6 @@ public class UsbPortManager {
}
};
- private final UEventObserver mUEventObserver = new UEventObserver() {
- @Override
- public void onUEvent(UEvent event) {
- scheduleUpdatePorts();
- }
- };
-
/**
* Describes a USB port.
*/
@@ -764,10 +747,10 @@ public class UsbPortManager {
}
/**
- * Describes a simulated USB port.
- * Roughly mirrors the information we would ordinarily get from the kernel.
+ * Used for storing the raw data from the kernel
+ * Values of the member variables mocked directly incase of emulation.
*/
- private static final class SimulatedPortInfo {
+ private static final class RawPortInfo implements Parcelable {
public final String mPortId;
public final int mSupportedModes;
public int mCurrentMode;
@@ -777,9 +760,63 @@ public class UsbPortManager {
public int mCurrentDataRole;
public boolean mCanChangeDataRole;
- public SimulatedPortInfo(String portId, int supportedModes) {
+ RawPortInfo(String portId, int supportedModes) {
mPortId = portId;
mSupportedModes = supportedModes;
}
+
+ RawPortInfo(String portId, int supportedModes,
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole) {
+ mPortId = portId;
+ mSupportedModes = supportedModes;
+ mCurrentMode = currentMode;
+ mCanChangeMode = canChangeMode;
+ mCurrentPowerRole = currentPowerRole;
+ mCanChangePowerRole = canChangePowerRole;
+ mCurrentDataRole = currentDataRole;
+ mCanChangeDataRole = canChangeDataRole;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mPortId);
+ dest.writeInt(mSupportedModes);
+ dest.writeInt(mCurrentMode);
+ dest.writeByte((byte) (mCanChangeMode ? 1 : 0));
+ dest.writeInt(mCurrentPowerRole);
+ dest.writeByte((byte) (mCanChangePowerRole ? 1 : 0));
+ dest.writeInt(mCurrentDataRole);
+ dest.writeByte((byte) (mCanChangeDataRole ? 1 : 0));
+ }
+
+ public static final Parcelable.Creator<RawPortInfo> CREATOR =
+ new Parcelable.Creator<RawPortInfo>() {
+ @Override
+ public RawPortInfo createFromParcel(Parcel in) {
+ String id = in.readString();
+ int supportedModes = in.readInt();
+ int currentMode = in.readInt();
+ boolean canChangeMode = in.readByte() != 0;
+ int currentPowerRole = in.readInt();
+ boolean canChangePowerRole = in.readByte() != 0;
+ int currentDataRole = in.readInt();
+ boolean canChangeDataRole = in.readByte() != 0;
+ return new RawPortInfo(id, supportedModes, currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole);
+ }
+
+ @Override
+ public RawPortInfo[] newArray(int size) {
+ return new RawPortInfo[size];
+ }
+ };
}
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index d0ccd55eb3c5..6e100298da35 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -98,6 +98,7 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
private static final String SESSION_CREATE_CONN = "CS.crCo";
+ private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
private static final String SESSION_ABORT = "CS.ab";
private static final String SESSION_ANSWER = "CS.an";
private static final String SESSION_ANSWER_VIDEO = "CS.anV";
@@ -142,6 +143,7 @@ public abstract class ConnectionService extends Service {
private static final int MSG_PULL_EXTERNAL_CALL = 22;
private static final int MSG_SEND_CALL_EVENT = 23;
private static final int MSG_ON_EXTRAS_CHANGED = 24;
+ private static final int MSG_CREATE_CONNECTION_FAILED = 25;
private static Connection sNullConnection;
@@ -211,6 +213,25 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void createConnectionFailed(
+ String callId,
+ ConnectionRequest request,
+ boolean isIncoming,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = request;
+ args.arg3 = Log.createSubsession();
+ args.argi1 = isIncoming ? 1 : 0;
+ mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void abort(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_ABORT);
try {
@@ -552,6 +573,35 @@ public abstract class ConnectionService extends Service {
}
break;
}
+ case MSG_CREATE_CONNECTION_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+ SESSION_CREATE_CONN_FAILED);
+ try {
+ final String id = (String) args.arg1;
+ final ConnectionRequest request = (ConnectionRequest) args.arg2;
+ final boolean isIncoming = args.argi1 == 1;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ createConnectionFailed(id, request, isIncoming);
+ }
+ }.prepare());
+ } else {
+ Log.i(this, "createConnectionFailed %s", id);
+ createConnectionFailed(id, request, isIncoming);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_ABORT: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1175,6 +1225,17 @@ public abstract class ConnectionService extends Service {
}
}
+ private void createConnectionFailed(final String callId, final ConnectionRequest request,
+ boolean isIncoming) {
+
+ Log.i(this, "createConnectionFailed %s", callId);
+ if (isIncoming) {
+ onCreateIncomingConnectionFailed(request);
+ } else {
+ onCreateOutgoingConnectionFailed(request);
+ }
+ }
+
private void abort(String callId) {
Log.d(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort();
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ba7b6a174a32..96070b88a1a6 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1517,6 +1517,10 @@ public class TelecomManager {
* otherwise.
*/
public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+ if (phoneAccountHandle == null) {
+ return false;
+ }
+
ITelecomService service = getTelecomService();
if (service != null) {
try {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 8a27675e08ab..20feba78f5c9 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -46,6 +46,9 @@ oneway interface IConnectionService {
boolean isUnknown,
in Session.Info sessionInfo);
+ void createConnectionFailed(String callId, in ConnectionRequest request, boolean isIncoming,
+ in Session.Info sessionInfo);
+
void abort(String callId, in Session.Info sessionInfo);
void answerVideo(String callId, int videoState, in Session.Info sessionInfo);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a853d5c3a7f7..3b15f1c2ebfe 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -259,6 +259,12 @@ public class CarrierConfigManager {
KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
/**
+ * Override the device's configuration for the ImsService to use for this SIM card.
+ */
+ public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING =
+ "config_ims_package_override_string";
+
+ /**
* Override the platform's notion of a network operator being considered roaming.
* Value is string array of SIDs to be considered roaming for 3GPP2 RATs.
*/
@@ -1167,6 +1173,9 @@ public class CarrierConfigManager {
* and {@code NEW_CODE} is the new {@code ImsReasonInfo#CODE_*} which this combination of
* original code and message shall be remapped to.
*
+ * Note: If {@code *} is specified for the original code, any ImsReasonInfo with the matching
+ * {@code MESSAGE} will be remapped to {@code NEW_CODE}.
+ *
* Example: "501|call completion elsewhere|1014"
* When the {@link ImsReasonInfo#getCode()} is {@link ImsReasonInfo#CODE_USER_TERMINATED} and
* the {@link ImsReasonInfo#getExtraMessage()} is {@code "call completion elsewhere"},
@@ -1396,6 +1405,7 @@ public class CarrierConfigManager {
});
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
+ sDefaults.putString(KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_DIAL_STRING_REPLACE_STRING_ARRAY, null);
@@ -1558,12 +1568,12 @@ public class CarrierConfigManager {
* moment.
* </p>
* <p>Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
* <p>
* This method returns before the reload has completed, and
* {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
* arbitrary thread.
* </p>
+ * @see #hasCarrierPrivileges
*/
public void notifyConfigChangedForSubId(int subId) {
try {
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 10cb7c95e85b..e53e2460cdcb 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -246,23 +246,18 @@ public class DisconnectCause {
*/
public static final int IMEI_NOT_ACCEPTED = 58;
+ /**
+ * A call over WIFI was disconnected because the WIFI signal was lost or became too degraded to
+ * continue the call.
+ */
+ public static final int WIFI_LOST = 59;
+
//*********************************************************************************************
// When adding a disconnect type:
- // 1) Please assign the new type the next id value below.
- // 2) Increment the next id value below to a new value.
- // 3) Update MAXIMUM_VALID_VALUE to the new disconnect type.
- // 4) Update toString() with the newly added disconnect type.
- // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
- //
- // NextId: 59
+ // 1) Update toString() with the newly added disconnect type.
+ // 2) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
//*********************************************************************************************
- /** Smallest valid value for call disconnect codes. */
- public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
-
- /** Largest valid value for call disconnect codes. */
- public static final int MAXIMUM_VALID_VALUE = IMEI_NOT_ACCEPTED;
-
/** Private constructor to avoid class instantiation. */
private DisconnectCause() {
// Do nothing.
@@ -387,6 +382,8 @@ public class DisconnectCause {
return "DIALED_CALL_FORWARDING_WHILE_ROAMING";
case IMEI_NOT_ACCEPTED:
return "IMEI_NOT_ACCEPTED";
+ case WIFI_LOST:
+ return "WIFI_LOST";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b28627bf3f74..1b3aa8aff845 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18,6 +18,7 @@ package android.telephony;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -46,8 +47,11 @@ import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.ClientRequestStats;
import android.telephony.TelephonyHistogram;
+import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IPhoneSubInfo;
@@ -61,6 +65,8 @@ import com.android.internal.telephony.TelephonyProperties;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -373,13 +379,46 @@ public class TelephonyManager {
"android.telephony.action.EMERGENCY_ASSISTANCE";
/**
+ * A boolean meta-data value indicating whether the voicemail settings should be hidden in the
+ * call settings page launched by
+ * {@link android.telecom.TelecomManager#ACTION_SHOW_CALL_SETTINGS}.
+ * Dialer implementations (see {@link android.telecom.TelecomManager#getDefaultDialerPackage()})
+ * which would also like to manage voicemail settings should set this meta-data to {@code true}
+ * in the manifest registration of their application.
+ *
+ * @see android.telecom.TelecomManager#ACTION_SHOW_CALL_SETTINGS
+ * @see #ACTION_CONFIGURE_VOICEMAIL
+ * @see #EXTRA_HIDE_PUBLIC_SETTINGS
+ */
+ public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU =
+ "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
+
+ /**
* Open the voicemail settings activity to make changes to voicemail configuration.
+ *
+ * <p>
+ * The {@link #EXTRA_HIDE_PUBLIC_SETTINGS} hides settings the dialer will modify through public
+ * API if set.
+ *
+ * @see #EXTRA_HIDE_PUBLIC_SETTINGS
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CONFIGURE_VOICEMAIL =
"android.telephony.action.CONFIGURE_VOICEMAIL";
/**
+ * The boolean value indicating whether the voicemail settings activity launched by {@link
+ * #ACTION_CONFIGURE_VOICEMAIL} should hide settings accessible through public API. This is
+ * used by dialer implementations which provides their own voicemail settings UI, but still
+ * needs to expose device specific voicemail settings to the user.
+ *
+ * @see #ACTION_CONFIGURE_VOICEMAIL
+ * @see #METADATA_HIDE_VOICEMAIL_SETTINGS_MENU
+ */
+ public static final String EXTRA_HIDE_PUBLIC_SETTINGS =
+ "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
+
+ /**
* @hide
*/
public static final boolean EMERGENCY_ASSISTANCE_ENABLED = true;
@@ -388,13 +427,13 @@ public class TelephonyManager {
* The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
* for a String containing the new call state.
*
- * @see #EXTRA_STATE_IDLE
- * @see #EXTRA_STATE_RINGING
- * @see #EXTRA_STATE_OFFHOOK
- *
* <p class="note">
* Retrieve with
* {@link android.content.Intent#getStringExtra(String)}.
+ *
+ * @see #EXTRA_STATE_IDLE
+ * @see #EXTRA_STATE_RINGING
+ * @see #EXTRA_STATE_OFFHOOK
*/
public static final String EXTRA_STATE = PhoneConstants.STATE_KEY;
@@ -780,37 +819,6 @@ public class TelephonyManager {
public static final String EVENT_DOWNGRADE_DATA_DISABLED =
"android.telephony.event.EVENT_DOWNGRADE_DATA_DISABLED";
- /**
- * Response codes for sim activation. Activation completed successfully.
- * @hide
- */
- @SystemApi
- public static final int SIM_ACTIVATION_RESULT_COMPLETE = 0;
- /**
- * Response codes for sim activation. Activation not supported (device has no SIM).
- * @hide
- */
- @SystemApi
- public static final int SIM_ACTIVATION_RESULT_NOT_SUPPORTED = 1;
- /**
- * Response codes for sim activation. Activation is in progress.
- * @hide
- */
- @SystemApi
- public static final int SIM_ACTIVATION_RESULT_IN_PROGRESS = 2;
- /**
- * Response codes for sim activation. Activation failed to complete.
- * @hide
- */
- @SystemApi
- public static final int SIM_ACTIVATION_RESULT_FAILED = 3;
- /**
- * Response codes for sim activation. Activation canceled by user.
- * @hide
- */
- @SystemApi
- public static final int SIM_ACTIVATION_RESULT_CANCELED = 4;
-
/* Visual voicemail protocols */
/**
@@ -1104,12 +1112,12 @@ public class TelephonyManager {
/**
* Returns the neighboring cell information of the device.
*
- * @return List of NeighboringCellInfo or null if info unavailable.
- *
* <p>Requires Permission:
- * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES}
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
*
- * @deprecated Use (@link getAllCellInfo} which returns a superset of the information
+ * @return List of NeighboringCellInfo or null if info unavailable.
+ *
+ * @deprecated Use {@link #getAllCellInfo} which returns a superset of the information
* from NeighboringCellInfo.
*/
@Deprecated
@@ -1655,6 +1663,11 @@ public class TelephonyManager {
/**
* Returns a constant indicating the radio technology (network type)
* currently in use on the device for data transmission.
+ *
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
* @return the network type
*
* @see #NETWORK_TYPE_UNKNOWN
@@ -1673,10 +1686,6 @@ public class TelephonyManager {
* @see #NETWORK_TYPE_LTE
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public int getDataNetworkType() {
return getDataNetworkType(getSubId());
@@ -2657,6 +2666,28 @@ public class TelephonyManager {
return false;
}
+
+ /**
+ * Returns the package responsible of processing visual voicemail for the phone account.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+ * READ_PHONE_STATE}
+ */
+ @Nullable
+ public String getVisualVoicemailPackageName(PhoneAccountHandle phoneAccountHandle) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony
+ .getVisualVoicemailPackageName(mContext.getOpPackageName(),
+ phoneAccountHandle);
+ }
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return null;
+ }
+
/**
* Enables the visual voicemail SMS filter for a phone account. When the filter is
* enabled, Incoming SMS messages matching the OMTP VVM SMS interface will be redirected to the
@@ -2851,6 +2882,30 @@ public class TelephonyManager {
}
/**
+ * Send the special dialer code. The IPC caller must be the current default dialer.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @param inputCode The special dialer code to send which follows the format of *#*#<code>#*#*
+ * @return true if sent sucessfully, false otherwise
+ *
+ */
+ public boolean sendDialerCode(String inputCode) {
+ try {
+ final ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ Log.e(TAG, "Telephony service unavailable");
+ return false;
+ }
+ return telephony.sendDialerCode(mContext.getOpPackageName(), inputCode);
+ } catch (RemoteException | NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return false;
+ }
+ }
+
+ /**
* Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
* @return the IMPI, or null if not present or not loaded
* @hide
@@ -4104,6 +4159,37 @@ public class TelephonyManager {
}
}
+ /** @hide */
+ @IntDef({ImsFeature.EMERGENCY_MMTEL, ImsFeature.MMTEL, ImsFeature.RCS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Feature {}
+
+ /**
+ * Returns the {@link IImsServiceController} that corresponds to the given slot Id and IMS
+ * feature or {@link null} if the service is not available. If an ImsServiceController is
+ * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
+ * feature updates.
+ * @param slotId The SIM slot that we are requesting the {@link IImsServiceController} for.
+ * @param feature The IMS Feature we are requesting, corresponding to {@link ImsFeature}.
+ * @param callback Listener that will send updates to ImsManager when there are updates to
+ * ImsServiceController.
+ * @return {@link IImsServiceController} interface for the feature specified or {@link null} if
+ * it is unavailable.
+ * @hide
+ */
+ public IImsServiceController getImsServiceControllerAndListen(int slotId, @Feature int feature,
+ IImsServiceFeatureListener callback) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getImsServiceControllerAndListen(slotId, feature, callback);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage());
+ }
+ return null;
+ }
+
/**
* Set IMS registration state
*
diff --git a/telephony/java/android/telephony/ims/ImsServiceBase.java b/telephony/java/android/telephony/ims/ImsServiceBase.java
new file mode 100644
index 000000000000..0b50ecaeb1ca
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceBase.java
@@ -0,0 +1,35 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Base ImsService Implementation, which is used by the ImsResolver to bind.
+ * @hide
+ */
+@SystemApi
+public class ImsServiceBase extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
new file mode 100644
index 000000000000..0509d604e688
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -0,0 +1,33 @@
+/*
+ * 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.telephony.ims.feature;
+
+/**
+ * Base class for all IMS features that are supported by the framework.
+ * @hide
+ */
+public class ImsFeature {
+
+ // Invalid feature value
+ public static final int INVALID = -1;
+ // ImsFeatures that are defined in the Manifests
+ public static final int EMERGENCY_MMTEL = 0;
+ public static final int MMTEL = 1;
+ public static final int RCS = 2;
+ // Total number of features defined
+ public static final int MAX = 3;
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 56b882221cd7..c71808c59830 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -308,6 +308,11 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_DATA_DISABLED = 1406;
/**
+ * Indicates a call was disconnected due to loss of wifi signal.
+ */
+ public static final int CODE_WIFI_LOST = 1407;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
new file mode 100644
index 000000000000..fa86a43c79d3
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.ims.internal;
+
+/**
+ * {@hide}
+ */
+interface IImsServiceController {
+ void createImsFeature(int slotId, int feature);
+ void removeImsFeature(int slotId, int feature);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
new file mode 100644
index 000000000000..0a36b6bec6a2
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.ims.internal;
+
+/**
+ * {@hide}
+ */
+oneway interface IImsServiceFeatureListener {
+ void imsFeatureCreated(int slotId, int feature);
+ void imsFeatureRemoved(int slotId, int feature);
+} \ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9a9a0923bc68..f2b8804e5e54 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -33,6 +33,8 @@ import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.OperatorInfo;
@@ -478,6 +480,9 @@ interface ITelephony {
boolean isVisualVoicemailEnabled(String callingPackage,
in PhoneAccountHandle accountHandle);
+ String getVisualVoicemailPackageName(String callingPackage,
+ in PhoneAccountHandle phoneAccountHandle);
+
// Not oneway, caller needs to make sure the vaule is set before receiving a SMS
void enableVisualVoicemailSmsFilter(String callingPackage, int subId,
in VisualVoicemailSmsFilterSettings settings);
@@ -501,6 +506,9 @@ interface ITelephony {
oneway void sendVisualVoicemailSmsForSubscriber(in String callingPackage, in int subId,
in String number, in int port, in String text, in PendingIntent sentIntent);
+ // Send the special dialer code. The IPC caller must be the current default dialer.
+ boolean sendDialerCode(String callingPackageName, String inputCode);
+
/**
* Returns the network type for data transmission
* Legacy call, permission-free
@@ -742,6 +750,14 @@ interface ITelephony {
int getTetherApnRequired();
/**
+ * Get ImsServiceController binder from ImsResolver that corresponds to the subId and feature
+ * requested as well as registering the ImsServiceController for callbacks using the
+ * IImsServiceFeatureListener interface.
+ */
+ IImsServiceController getImsServiceControllerAndListen(int slotId, int feature,
+ IImsServiceFeatureListener callback);
+
+ /**
* Set the network selection mode to automatic.
*
* @param subId the id of the subscription to update.
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 891b8a1adb73..5ee7e23eabca 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -417,7 +417,7 @@ cat include/telephony/ril.h | \
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
- int RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
+ int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b6e701eb5225..9ffd92d0a754 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -692,6 +692,13 @@ public class MockContext extends Context {
return null;
}
+ /** @hide */
+ @Override
+ public Context createContextForSplit(String splitName)
+ throws PackageManager.NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
/** {@hide} */
@Override
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 0c34f204a8cb..0dcd0f14dd38 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -16,9 +16,7 @@
package android.test.mock;
-import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Intent;
@@ -26,7 +24,7 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -149,6 +147,12 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean isPermissionReviewModeEnabled() {
+ return false;
+ }
+
@Override
public PermissionGroupInfo getPermissionGroupInfo(String name,
int flags) throws NameNotFoundException {
@@ -220,6 +224,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public boolean canRequestPackageInstalls() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
throw new UnsupportedOperationException();
}
@@ -331,38 +340,38 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public List<EphemeralApplicationInfo> getEphemeralApplications() {
+ public List<InstantAppInfo> getInstantApps() {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public Drawable getEphemeralApplicationIcon(String packageName) {
+ public Drawable getInstantAppIcon(String packageName) {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public byte[] getEphemeralCookie() {
- return new byte[0];
+ public byte[] getInstantAppCookie() {
+ throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public boolean isEphemeralApplication() {
- return false;
+ public boolean isInstantApp() {
+ throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public int getEphemeralCookieMaxSizeBytes() {
- return 0;
+ public int getInstantAppCookieMaxSize() {
+ throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public boolean setEphemeralCookie(@NonNull byte[] cookie) {
- return false;
+ public boolean setInstantAppCookie(@NonNull byte[] cookie) {
+ throw new UnsupportedOperationException();
}
@Override
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index dc3b3379d204..25bfa53b0cf2 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -227,7 +227,7 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
public void testConfigBuilderUsesParents() throws Exception {
// Check that a builder with a parent uses the parent's values when non is set.
NetworkSecurityConfig config = new NetworkSecurityConfig.Builder()
- .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, false))
+ .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1))
.build();
assert(!config.getTrustAnchors().isEmpty());
}
@@ -268,9 +268,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
// Install the test CA.
store.installCertificate(TEST_CA_CERT);
NetworkSecurityConfig preNConfig =
- NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M, false).build();
+ NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M, 1).build();
NetworkSecurityConfig nConfig =
- NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, false).build();
+ NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1).build();
Set<TrustAnchor> preNAnchors = preNConfig.getTrustAnchors();
Set<TrustAnchor> nAnchors = nConfig.getTrustAnchors();
Set<X509Certificate> preNCerts = new HashSet<X509Certificate>();
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index da27ea916a18..56aad23eecc9 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -424,6 +424,17 @@ public class NotificationTestList extends TestActivity
mNM.notify("secret", 7012, n);
}
},
+ new Test("1 minute timeout") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("timeout in a minute")
+ .setTimeout(System.currentTimeMillis() + (1000 * 60))
+ .build();
+ mNM.notify("timeout_min", 7013, n);
+ }
+ },
new Test("Off") {
public void run() {
PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
index 6629770ec6b4..251bf24e8a39 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
@@ -30,8 +30,9 @@ import android.widget.TextView;
import android.transition.AutoTransition;
import android.transition.ChangeBounds;
import android.transition.Transition;
-import android.transition.TransitionSet;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
+import android.transition.TransitionSet;
import java.util.ArrayList;
import java.util.HashMap;
@@ -84,7 +85,7 @@ public class ListViewAddRemove extends Activity {
fadeIn.setDuration(50);
noFadeIn.addTransition(new Fade(Fade.OUT)).addTransition(new ChangeBounds()).addTransition(fadeIn);
- myTransition.addListener(new Transition.TransitionListenerAdapter() {
+ myTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionStart(Transition transition) {
System.out.println("---------ListView Tops: Before--------");
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 0681b61fc02f..c20be5141df5 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -100,6 +100,31 @@
</intent-filter>
</activity>
<activity
+ android:name=".FadingEdgeListActivity"
+ android:label="General/Fading Edge ListView" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".SaveLayerInterleaveActivity"
+ android:label="General/SaveLayer Animation" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ClippedListActivity"
+ android:label="General/Clipped ListView"
+ android:theme="@style/NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".TrivialRecyclerViewActivity"
android:label="General/Trivial RecyclerView" >
<intent-filter>
diff --git a/tests/UiBench/res/layout/app_bar_navigation_drawer.xml b/tests/UiBench/res/layout/app_bar_navigation_drawer.xml
index ede2a566987b..5657587f7772 100644
--- a/tests/UiBench/res/layout/app_bar_navigation_drawer.xml
+++ b/tests/UiBench/res/layout/app_bar_navigation_drawer.xml
@@ -16,6 +16,7 @@
-->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
diff --git a/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java b/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java
new file mode 100644
index 000000000000..7454124b5ed0
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.design.widget.NavigationView;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class ClippedListActivity extends AppCompatActivity
+ implements NavigationView.OnNavigationItemSelectedListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_navigation_drawer);
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+ ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
+ this, drawer, toolbar, R.string.navigation_drawer_open,
+ R.string.navigation_drawer_close);
+ drawer.setDrawerListener(toggle);
+ toggle.syncState();
+
+ NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
+ navigationView.setNavigationItemSelectedListener(this);
+
+ FragmentManager fm = getSupportFragmentManager();
+ if (fm.findFragmentById(android.R.id.content) == null) {
+ ListFragment listFragment = new ListFragment();
+ ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+ TextUtils.buildSimpleStringList(40));
+ listFragment.setListAdapter(adapter);
+ fm.beginTransaction().add(R.id.app_bar_layout, listFragment).commit();
+ }
+ }
+
+ @Override
+ public boolean onNavigationItemSelected(MenuItem item) {
+ DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+ drawer.closeDrawer(GravityCompat.START);
+ return true;
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java b/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java
new file mode 100644
index 000000000000..3241e669fb1d
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java
@@ -0,0 +1,37 @@
+/*
+ * 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.test.uibench;
+
+import android.support.v4.app.ListFragment;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+import com.android.test.uibench.listview.FadingEdgeListFragment;
+
+public class FadingEdgeListActivity extends CompatListActivity {
+
+ @Override
+ protected ListAdapter createListAdapter() {
+ return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+ TextUtils.buildSimpleStringList(40));
+ }
+
+ @Override
+ protected ListFragment createListFragment() {
+ return (ListFragment)new FadingEdgeListFragment();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java b/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java
new file mode 100644
index 000000000000..eec91cb38066
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java
@@ -0,0 +1,89 @@
+/*
+ * 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.test.uibench;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+/**
+ * Test Canvas.saveLayer performance by interleaving drawText/drawRect with saveLayer.
+ * This test will be used to measure if drawing interleaved layers at the beginning of a frame will
+ * decrease FBO switching overhead (this is a future optimization in SkiaGL rendering pipeline).
+ */
+public class SaveLayerInterleaveActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new Drawable() {
+ private final Paint mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawColor(Color.RED);
+
+ Rect bounds = getBounds();
+ int regions = 20;
+ int smallRectHeight = (bounds.height()/regions);
+ int padding = smallRectHeight / 4;
+ int top = bounds.top;
+ mBluePaint.setColor(Color.BLUE);
+ mBluePaint.setTextSize(padding);
+ mGreenPaint.setColor(Color.GREEN);
+ mGreenPaint.setTextSize(padding);
+
+ //interleave drawText and drawRect with saveLayer ops
+ for (int i = 0; i < regions; i++, top += smallRectHeight) {
+ canvas.saveLayer(bounds.left, top, bounds.right, top + padding,
+ mBluePaint);
+ canvas.drawColor(Color.YELLOW);
+ canvas.drawText("offscreen line "+ i, bounds.left, top + padding,
+ mBluePaint);
+ canvas.restore();
+
+ Rect partX = new Rect(bounds.left, top + padding,
+ bounds.right,top + smallRectHeight - padding);
+ canvas.drawRect(partX, mBluePaint);
+ canvas.drawText("onscreen line "+ i, bounds.left,
+ top + smallRectHeight - padding, mGreenPaint);
+ }
+
+ invalidateSelf();
+ }
+ });
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextUtils.java b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
index d88ca1e1a889..32a59868e6c0 100644
--- a/tests/UiBench/src/com/android/test/uibench/TextUtils.java
+++ b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
@@ -35,10 +35,14 @@ public class TextUtils {
}
public static String[] buildSimpleStringList() {
+ return buildSimpleStringList(SIMPLE_STRING_LENGTH);
+ }
+
+ public static String[] buildSimpleStringList(int stringLength) {
String[] strings = new String[STRING_COUNT];
Random random = new Random(0);
for (int i = 0; i < strings.length; i++) {
- strings[i] = randomWord(random, SIMPLE_STRING_LENGTH);
+ strings[i] = randomWord(random, stringLength);
}
return strings;
}
diff --git a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
index 214c07463fd7..bb7f4a302f8c 100644
--- a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
@@ -29,11 +29,15 @@ public abstract class CompatListActivity extends AppCompatActivity {
FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentById(android.R.id.content) == null) {
- ListFragment listFragment = new ListFragment();
+ ListFragment listFragment = createListFragment();
listFragment.setListAdapter(createListAdapter());
fm.beginTransaction().add(android.R.id.content, listFragment).commit();
}
}
protected abstract ListAdapter createListAdapter();
+
+ protected ListFragment createListFragment() {
+ return new ListFragment();
+ }
}
diff --git a/core/java/com/android/internal/logging/legacy/HistogramParser.java b/tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java
index bb7e75cce7f2..a018b40e8528 100644
--- a/core/java/com/android/internal/logging/legacy/HistogramParser.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java
@@ -13,23 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.logging.legacy;
+package com.android.test.uibench.listview;
-/**
- * Parse the Android histogram event logs.
- * @hide
- */
-public class HistogramParser extends CounterParser {
- private static final String TAG = "HistogramParser";
- private static final int EVENTLOG_TAG = 524291;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.widget.ListView;
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
+public class FadingEdgeListFragment extends ListFragment {
@Override
- protected void logCount(TronLogger logger, String name, int value) {
- logger.incrementIntHistogram("tron_varz_" + name, value);
+ public void onActivityCreated(Bundle savedInstanceState) {
+ ListView listView = getListView();
+ listView.setVerticalFadingEdgeEnabled(true);
+ listView.setFadingEdgeLength(500);
+ super.onActivityCreated(savedInstanceState);
}
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
new file mode 100644
index 000000000000..b984bbfddac3
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.net;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+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 android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityManagerTest {
+ static NetworkCapabilities verifyNetworkCapabilities(
+ int legacyType, int transportType, int... capabilities) {
+ final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
+ assertNotNull(nc);
+ assertTrue(nc.hasTransport(transportType));
+ for (int capability : capabilities) {
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ return nc;
+ }
+
+ static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
+ verifyNetworkCapabilities(
+ legacyType,
+ transportType,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+ }
+
+ static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ legacyType,
+ TRANSPORT_CELLULAR,
+ capability,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobile() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileCbs() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileDun() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileFota() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileHipri() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileIms() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileMms() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_MMS,
+ TRANSPORT_CELLULAR,
+ NET_CAPABILITY_MMS,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileSupl() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_SUPL,
+ TRANSPORT_CELLULAR,
+ NET_CAPABILITY_SUPL,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeWifi() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeWifiP2p() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_WIFI_P2P,
+ TRANSPORT_WIFI,
+ NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeBluetooth() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeEthernet() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
+ }
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index ff6175427ce7..91d6c6840f47 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -29,9 +29,11 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.os.ConditionVariable;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
+import android.text.format.DateUtils;
import android.test.suitebuilder.annotation.SmallTest;
import static android.system.OsConstants.*;
@@ -604,6 +606,8 @@ public class ApfTest extends AndroidTestCase {
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
private FileDescriptor mWriteSocket;
+ private final long mFixedTimeMs = SystemClock.elapsedRealtime();
+
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
IpConnectivityLog log) throws Exception {
super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
@@ -617,6 +621,11 @@ public class ApfTest extends AndroidTestCase {
}
@Override
+ protected long currentTimeSeconds() {
+ return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
+ }
+
+ @Override
void maybeStartFilter() {
mHardwareAddress = MOCK_MAC_ADDR;
installNewProgramLocked();
@@ -969,27 +978,30 @@ public class ApfTest extends AndroidTestCase {
// Verify that the last program pushed to the IpManager.Callback properly filters the
// given packet for the given lifetime.
- private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
- int lifetime) {
- byte[] program = ipManagerCallback.getApfProgram();
+ private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
+ final int FRACTION_OF_LIFETIME = 6;
+ final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
- // Verify new program should drop RA for 1/6th its lifetime
+ // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
assertDrop(program, packet.array());
- assertDrop(program, packet.array(), lifetime/6);
- assertPass(program, packet.array(), lifetime/6 + 1);
+ assertDrop(program, packet.array(), ageLimit);
+ assertPass(program, packet.array(), ageLimit + 1);
assertPass(program, packet.array(), lifetime);
-
// Verify RA checksum is ignored
+ final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
assertDrop(program, packet.array());
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
assertDrop(program, packet.array());
+ packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
// Verify other changes to RA make it not match filter
+ final byte originalFirstByte = packet.get(0);
packet.put(0, (byte)-1);
assertPass(program, packet.array());
packet.put(0, (byte)0);
assertDrop(program, packet.array());
+ packet.put(0, originalFirstByte);
}
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -999,9 +1011,8 @@ public class ApfTest extends AndroidTestCase {
// Verify new program generated if ApfFilter witnesses RA
ipManagerCallback.resetApfProgramWait();
apfFilter.pretendPacketReceived(packet.array());
- ipManagerCallback.getApfProgram();
-
- verifyRaLifetime(ipManagerCallback, packet, lifetime);
+ byte[] program = ipManagerCallback.getApfProgram();
+ verifyRaLifetime(program, packet, lifetime);
}
private void verifyRaEvent(RaEvent expected) {
@@ -1046,18 +1057,26 @@ public class ApfTest extends AndroidTestCase {
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
+ final int ROUTER_LIFETIME = 1000;
+ final int PREFIX_VALID_LIFETIME = 200;
+ final int PREFIX_PREFERRED_LIFETIME = 100;
+ final int RDNSS_LIFETIME = 300;
+ final int ROUTE_LIFETIME = 400;
+ // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
+ final int DNSSL_LIFETIME = 2000;
+
// Verify RA is passed the first time
ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
- basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
+ basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
basePacket.position(IPV6_DEST_ADDR_OFFSET);
basePacket.put(IPV6_ALL_NODES_ADDRESS);
assertPass(program, basePacket.array());
- testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
+ testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
// Ensure zero-length options cause the packet to be silently skipped.
// Do this before we test other packets. http://b/29586253
@@ -1079,11 +1098,14 @@ public class ApfTest extends AndroidTestCase {
prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100);
+ ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+ PREFIX_PREFERRED_LIFETIME);
prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
- testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
- verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+ PREFIX_VALID_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+ verifyRaEvent(new RaEvent(
+ ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1092,9 +1114,9 @@ public class ApfTest extends AndroidTestCase {
rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
rdnssOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
- testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1103,9 +1125,9 @@ public class ApfTest extends AndroidTestCase {
routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
routeInfoOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
- testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
- verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1114,18 +1136,17 @@ public class ApfTest extends AndroidTestCase {
dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
dnsslOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000);
- // Note that lifetime of 2000 will be ignored in favor of shorter
- // route lifetime of 1000.
- testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
// Verify that current program filters all five RAs:
- verifyRaLifetime(ipManagerCallback, basePacket, 1000);
- verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100);
- verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300);
- verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400);
- verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000);
+ program = ipManagerCallback.getApfProgram();
+ verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
+ verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+ verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
+ verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
apfFilter.shutdown();
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 46b64031ee8a..eeaf26f92f47 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -53,7 +53,7 @@ import android.net.NetworkMisc;
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.metrics.IpConnectivityLog;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
@@ -68,7 +68,6 @@ import android.os.Process;
import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
-import android.test.FlakyTest;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -154,49 +153,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/**
- * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
- * will return immediately if the handler is already idle.
+ * Block until the given handler becomes idle, or until timeoutMs has passed.
*/
- private class IdleableHandlerThread extends HandlerThread {
- private IdleHandler mIdleHandler;
-
- public IdleableHandlerThread(String name) {
- super(name);
- }
-
- public void waitForIdle(int timeoutMs) {
- final ConditionVariable cv = new ConditionVariable();
- final MessageQueue queue = getLooper().getQueue();
-
- synchronized (queue) {
- if (queue.isIdle()) {
- return;
- }
-
- assertNull("BUG: only one idle handler allowed", mIdleHandler);
- mIdleHandler = new IdleHandler() {
- public boolean queueIdle() {
- synchronized (queue) {
- cv.open();
- mIdleHandler = null;
- return false; // Remove the handler.
- }
- }
- };
- queue.addIdleHandler(mIdleHandler);
- }
-
- if (!cv.block(timeoutMs)) {
- fail("HandlerThread " + getName() +
- " did not become idle after " + timeoutMs + " ms");
- queue.removeIdleHandler(mIdleHandler);
- }
+ private static void waitForIdleHandler(HandlerThread handlerThread, int timeoutMs) {
+ final ConditionVariable cv = new ConditionVariable();
+ final Handler handler = new Handler(handlerThread.getLooper());
+ handler.post(() -> cv.open());
+ if (!cv.block(timeoutMs)) {
+ fail("HandlerThread " + handlerThread.getName() +
+ " did not become idle after " + timeoutMs + " ms");
}
}
- // Tests that IdleableHandlerThread works as expected.
@SmallTest
- public void testIdleableHandlerThread() {
+ public void testWaitForIdle() {
final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
// Tests that waitForIdle returns immediately if the service is already idle.
@@ -220,9 +190,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- @SmallTest
- @FlakyTest(tolerance = 3)
- public void testNotWaitingForIdleCausesRaceConditions() {
+ // This test has an inherent race condition in it, and cannot be enabled for continuous testing
+ // or presubmit tests. It is kept for manual runs and documentation purposes.
+ public void verifyThatNotWaitingForIdleCausesRaceConditions() {
// Bring up a network that we can use to send messages to ConnectivityService.
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -249,7 +219,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private final WrappedNetworkMonitor mWrappedNetworkMonitor;
private final NetworkInfo mNetworkInfo;
private final NetworkCapabilities mNetworkCapabilities;
- private final IdleableHandlerThread mHandlerThread;
+ private final HandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
@@ -281,7 +251,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
default:
throw new UnsupportedOperationException("unimplemented network type");
}
- mHandlerThread = new IdleableHandlerThread("Mock-" + typeName);
+ mHandlerThread = new HandlerThread("Mock-" + typeName);
mHandlerThread.start();
mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
"Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
@@ -321,7 +291,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
public void waitForIdle(int timeoutMs) {
- mHandlerThread.waitForIdle(timeoutMs);
+ waitForIdleHandler(mHandlerThread, timeoutMs);
}
public void waitForIdle() {
@@ -623,10 +593,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
+ private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
public volatile boolean configRestrictsAvoidBadWifi;
+ public volatile int configMeteredMultipathPreference;
- public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
+ public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
}
@@ -634,10 +605,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
public boolean configRestrictsAvoidBadWifi() {
return configRestrictsAvoidBadWifi;
}
+
+ @Override
+ public int configMeteredMultipathPreference() {
+ return configMeteredMultipathPreference;
+ }
}
private class WrappedConnectivityService extends ConnectivityService {
- public WrappedAvoidBadWifiTracker wrappedAvoidBadWifiTracker;
+ public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -648,11 +624,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
- protected HandlerThread createHandlerThread() {
- return new IdleableHandlerThread("WrappedConnectivityService");
- }
-
- @Override
protected int getDefaultTcpRwnd() {
// Prevent wrapped ConnectivityService from trying to write to SystemProperties.
return 0;
@@ -689,14 +660,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
- public AvoidBadWifiTracker createAvoidBadWifiTracker(
+ public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
Context c, Handler h, Runnable r) {
- final WrappedAvoidBadWifiTracker tracker = new WrappedAvoidBadWifiTracker(c, h, r);
+ final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
return tracker;
}
- public WrappedAvoidBadWifiTracker getAvoidBadWifiTracker() {
- return (WrappedAvoidBadWifiTracker) mAvoidBadWifiTracker;
+ public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
+ return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
}
@Override
@@ -710,7 +681,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
public void waitForIdle(int timeoutMs) {
- ((IdleableHandlerThread) mHandlerThread).waitForIdle(timeoutMs);
+ waitForIdleHandler(mHandlerThread, timeoutMs);
}
public void waitForIdle() {
@@ -718,22 +689,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- private interface Criteria {
- public boolean get();
- }
-
- /**
- * Wait up to 500ms for {@code criteria.get()} to become true, polling.
- * Fails if 500ms goes by before {@code criteria.get()} to become true.
- */
- static private void waitFor(Criteria criteria) {
- int delays = 0;
- while (!criteria.get()) {
- sleepFor(50);
- if (++delays == 10) fail();
- }
- }
-
/**
* Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
* Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
@@ -869,8 +824,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
// Test cellular linger timeout.
- waitFor(new Criteria() {
- public boolean get() { return mCm.getAllNetworks().length == 1; } });
+ waitFor(mCellNetworkAgent.getDisconnectedCV());
+ mService.waitForIdle();
+ assertEquals(1, mCm.getAllNetworks().length);
verifyActiveNetwork(TRANSPORT_WIFI);
assertEquals(1, mCm.getAllNetworks().length);
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -1135,7 +1091,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Chosen to be much less than the linger timeout. This ensures that we can distinguish
// between a LOST callback that arrives immediately and a LOST callback that arrives after
// the linger timeout.
- private final static int TIMEOUT_MS = 50;
+ private final static int TIMEOUT_MS = 100;
private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
@@ -1487,8 +1443,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Let linger run its course.
callback.assertNoCallback();
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS /* timeoutMs */);
+ final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Clean up.
mWiFiNetworkAgent.disconnect();
@@ -1645,8 +1601,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
mCellNetworkAgent.connectWithoutInternet();
waitFor(cv);
- waitFor(new Criteria() {
- public boolean get() { return mCm.getAllNetworks().length == 0; } });
+ mService.waitForIdle();
+ assertEquals(0, mCm.getAllNetworks().length);
verifyNoNetwork();
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1977,7 +1933,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
// When lingering is complete, cell is still there but is now in the background.
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS);
+ mService.waitForIdle();
+ int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
callback.assertNoCallback();
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -2172,7 +2130,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@SmallTest
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
tracker.configRestrictsAvoidBadWifi = false;
@@ -2182,7 +2140,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
tracker.reevaluate();
mService.waitForIdle();
String msg = String.format("config=false, setting=%s", values[i]);
- assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+ assertTrue(mService.avoidBadWifi());
assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
}
@@ -2191,26 +2149,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
Settings.Global.putInt(cr, settingName, 0);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+ assertFalse(mService.avoidBadWifi());
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putInt(cr, settingName, 1);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+ assertTrue(mService.avoidBadWifi());
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putString(cr, settingName, null);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+ assertFalse(mService.avoidBadWifi());
assertTrue(tracker.shouldNotifyWifiUnvalidated());
}
@SmallTest
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
// Pretend we're on a carrier that restricts switching away from bad wifi.
tracker.configRestrictsAvoidBadWifi = true;
@@ -2330,6 +2288,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @SmallTest
+ public void testMeteredMultipathPreferenceSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
+ final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+ for (int config : Arrays.asList(0, 3, 2)) {
+ for (String setting: Arrays.asList(null, "0", "2", "1")) {
+ tracker.configMeteredMultipathPreference = config;
+ Settings.Global.putString(cr, settingName, setting);
+ tracker.reevaluate();
+ mService.waitForIdle();
+
+ final int expected = (setting != null) ? Integer.parseInt(setting) : config;
+ String msg = String.format("config=%d, setting=%s", config, setting);
+ assertEquals(msg, expected, mCm.getMultipathPreference(null));
+ }
+ }
+ }
+
/**
* Validate that a satisfied network request does not trigger onUnavailable() once the
* time-out period expires.
@@ -2339,14 +2317,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 150;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
- sleepFor(15);
networkCallback.assertNoCallback();
}
@@ -2359,17 +2337,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 500);
+ final int requestTimeoutMs = 100;
+ mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ final int assertTimeoutMs = 150;
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// pass timeout and validate that UNAVAILABLE is not called
- sleepFor(600);
+ sleepFor(100);
networkCallback.assertNoCallback();
}
@@ -2383,7 +2363,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 10;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
// pass timeout and validate that UNAVAILABLE is called
networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
@@ -2403,7 +2384,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 10;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
// remove request
mCm.unregisterNetworkCallback(networkCallback);
@@ -2420,17 +2402,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
networkCallback.assertNoCallback();
}
- public void assertEventuallyTrue(BooleanSupplier fn, long maxWaitingTimeMs) throws Exception {
- long start = SystemClock.elapsedRealtime();
- while (SystemClock.elapsedRealtime() <= start + maxWaitingTimeMs) {
- if (fn.getAsBoolean()) {
- return;
- }
- Thread.sleep(10);
- }
- assertTrue(fn.getAsBoolean());
- }
-
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -2591,10 +2562,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
mWiFiNetworkAgent.disconnect();
+ waitFor(mWiFiNetworkAgent.getDisconnectedCV());
callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
// ... and that stopping it after that has no adverse effects.
- assertNull(mCm.getNetworkCapabilities(myNet));
+ mService.waitForIdle();
+ final Network myNetAlias = myNet;
+ assertNull(mCm.getNetworkCapabilities(myNetAlias));
ka.stop();
// Reconnect.
@@ -2606,6 +2580,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
callback.expectStarted();
ka.stop();
mWiFiNetworkAgent.disconnect();
+ waitFor(mWiFiNetworkAgent.getDisconnectedCV());
mService.waitForIdle();
callback.expectStopped();
@@ -2838,11 +2813,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/* test utilities */
+ // TODO: eliminate all usages of sleepFor and replace by proper timeouts/waitForIdle.
static private void sleepFor(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
-
}
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 1e67769277da..3ed56dff3f83 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -23,7 +23,13 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -40,6 +46,7 @@ import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.HashMap;
@@ -64,7 +71,7 @@ public class UpstreamNetworkMonitorTest {
reset(mContext);
reset(mCS);
- mCM = new TestConnectivityManager(mContext, mCS);
+ mCM = spy(new TestConnectivityManager(mContext, mCS));
mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
}
@@ -91,12 +98,12 @@ public class UpstreamNetworkMonitorTest {
}
@Test
- public void testListensForDunNetworks() throws Exception {
+ public void testListensForAllNetworks() throws Exception {
assertTrue(mCM.listening.isEmpty());
mUNM.start();
assertFalse(mCM.listening.isEmpty());
- assertTrue(mCM.isListeningForDun());
+ assertTrue(mCM.isListeningForAll());
mUNM.stop();
assertTrue(mCM.hasNoCallbacks());
@@ -126,6 +133,42 @@ public class UpstreamNetworkMonitorTest {
}
@Test
+ public void testDuplicateMobileRequestsIgnored() throws Exception {
+ assertFalse(mUNM.mobileNetworkRequested());
+ assertEquals(0, mCM.requested.size());
+
+ mUNM.start();
+ verify(mCM, Mockito.times(1)).registerNetworkCallback(
+ any(NetworkRequest.class), any(NetworkCallback.class));
+ verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
+ assertFalse(mUNM.mobileNetworkRequested());
+ assertEquals(0, mCM.requested.size());
+
+ mUNM.updateMobileRequiresDun(true);
+ mUNM.registerMobileNetworkRequest();
+ verify(mCM, Mockito.times(1)).requestNetwork(
+ any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
+
+ assertTrue(mUNM.mobileNetworkRequested());
+ assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
+ assertTrue(mCM.isDunRequested());
+
+ // Try a few things that must not result in any state change.
+ mUNM.registerMobileNetworkRequest();
+ mUNM.updateMobileRequiresDun(true);
+ mUNM.registerMobileNetworkRequest();
+
+ assertTrue(mUNM.mobileNetworkRequested());
+ assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
+ assertTrue(mCM.isDunRequested());
+
+ mUNM.stop();
+ verify(mCM, times(3)).unregisterNetworkCallback(any(NetworkCallback.class));
+
+ verifyNoMoreInteractions(mCM);
+ }
+
+ @Test
public void testRequestsDunNetwork() throws Exception {
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
@@ -149,7 +192,7 @@ public class UpstreamNetworkMonitorTest {
}
@Test
- public void testUpdateMobileRequiredDun() throws Exception {
+ public void testUpdateMobileRequiresDun() throws Exception {
mUNM.start();
// Test going from no-DUN to DUN correctly re-registers callbacks.
@@ -180,7 +223,7 @@ public class UpstreamNetworkMonitorTest {
mCM.legacyTypeMap.values().iterator().next());
}
- private static class TestConnectivityManager extends ConnectivityManager {
+ public static class TestConnectivityManager extends ConnectivityManager {
public Set<NetworkCallback> trackingDefault = new HashSet<>();
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -197,9 +240,12 @@ public class UpstreamNetworkMonitorTest {
legacyTypeMap.isEmpty();
}
- boolean isListeningForDun() {
+ boolean isListeningForAll() {
+ final NetworkCapabilities empty = new NetworkCapabilities();
+ empty.clearAll();
+
for (NetworkRequest req : listening.values()) {
- if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
+ if (req.networkCapabilities.equalRequestableCapabilities(empty)) {
return true;
}
}
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index d0026a28ba16..0aca45ea8d60 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -267,8 +267,8 @@ void applyVersionForCompatibility(ConfigDescription* config) {
uint16_t minSdk = 0;
if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
== ResTable_config::UI_MODE_TYPE_VR_HEADSET
- || config->colorimetry & ResTable_config::MASK_WIDE_COLOR_GAMUT
- || config->colorimetry & ResTable_config::MASK_HDR) {
+ || config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT
+ || config->colorMode & ResTable_config::MASK_HDR) {
minSdk = SDK_O;
} else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
minSdk = SDK_MNC;
@@ -451,18 +451,18 @@ bool parseScreenRound(const char* name, ResTable_config* out) {
bool parseWideColorGamut(const char* name, ResTable_config* out) {
if (strcmp(name, kWildcardName) == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
| ResTable_config::WIDE_COLOR_GAMUT_ANY;
return true;
} else if (strcmp(name, "widecg") == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
| ResTable_config::WIDE_COLOR_GAMUT_YES;
return true;
} else if (strcmp(name, "nowidecg") == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
| ResTable_config::WIDE_COLOR_GAMUT_NO;
return true;
}
@@ -471,18 +471,18 @@ bool parseWideColorGamut(const char* name, ResTable_config* out) {
bool parseHdr(const char* name, ResTable_config* out) {
if (strcmp(name, kWildcardName) == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_HDR)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_HDR)
| ResTable_config::HDR_ANY;
return true;
} else if (strcmp(name, "highdr") == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_HDR)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_HDR)
| ResTable_config::HDR_YES;
return true;
} else if (strcmp(name, "lowdr") == 0) {
- if (out) out->colorimetry =
- (out->colorimetry&~ResTable_config::MASK_HDR)
+ if (out) out->colorMode =
+ (out->colorMode&~ResTable_config::MASK_HDR)
| ResTable_config::HDR_NO;
return true;
}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 653c1b4d6f97..a93ee2e2b71d 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -55,6 +55,7 @@ public:
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
mAutoAddOverlay(false), mGenDependencies(false), mNoVersionVectors(false),
+ mNoVersionTransitions(false),
mCrunchedOutputDir(NULL), mProguardFile(NULL), mMainDexProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -219,6 +220,8 @@ public:
void setBuildAppAsSharedLibrary(bool val) { mBuildAppAsSharedLibrary = val; }
void setNoVersionVectors(bool val) { mNoVersionVectors = val; }
bool getNoVersionVectors() const { return mNoVersionVectors; }
+ void setNoVersionTransitions(bool val) { mNoVersionTransitions = val; }
+ bool getNoVersionTransitions() const { return mNoVersionTransitions; }
/*
* Set and get the file specification.
@@ -299,6 +302,7 @@ private:
bool mAutoAddOverlay;
bool mGenDependencies;
bool mNoVersionVectors;
+ bool mNoVersionTransitions;
const char* mCrunchedOutputDir;
const char* mProguardFile;
const char* mMainDexProguardFile;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 984d98e30f29..417b7ae087e1 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -223,6 +223,8 @@ void usage(void)
" localization\n"
" --no-version-vectors\n"
" Do not automatically generate versioned copies of vector XML resources.\n"
+ " --no-version-transitions\n"
+ " Do not automatically generate versioned copies of transition XML resources.\n"
" --private-symbols\n"
" Java package name to use when generating R.java for private resources.\n",
gDefaultIgnoreAssets);
@@ -704,6 +706,8 @@ int main(int argc, char* const argv[])
bundle.setPseudolocalize(PSEUDO_ACCENTED | PSEUDO_BIDI);
} else if (strcmp(cp, "-no-version-vectors") == 0) {
bundle.setNoVersionVectors(true);
+ } else if (strcmp(cp, "-no-version-transitions") == 0) {
+ bundle.setNoVersionTransitions(true);
} else if (strcmp(cp, "-private-symbols") == 0) {
argc--;
argv++;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b9bf7991edb3..ff306ce5be6b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4732,6 +4732,32 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
return NO_ERROR;
}
+const String16 kTransitionElements[] = {
+ String16("fade"),
+ String16("changeBounds"),
+ String16("slide"),
+ String16("explode"),
+ String16("changeImageTransform"),
+ String16("changeTransform"),
+ String16("changeClipBounds"),
+ String16("autoTransition"),
+ String16("recolor"),
+ String16("changeScroll"),
+ String16("transitionSet"),
+ String16("transition"),
+ String16("transitionManager"),
+};
+
+static bool IsTransitionElement(const String16& name) {
+ for (int i = 0, size = sizeof(kTransitionElements) / sizeof(kTransitionElements[0]);
+ i < size; ++i) {
+ if (name == kTransitionElements[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
status_t ResourceTable::modifyForCompat(const Bundle* bundle,
const String16& resourceName,
const sp<AaptFile>& target,
@@ -4768,6 +4794,11 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
continue;
}
+ if (bundle->getNoVersionTransitions() && (IsTransitionElement(node->getElementName()))) {
+ // We were told not to version transition tags, so skip the children here.
+ continue;
+ }
+
const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
for (size_t i = 0; i < attrs.size(); i++) {
const XMLNode::attribute_entry& attr = attrs[i];
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index 23f61e9e4b70..4f22fa581a88 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -103,13 +103,13 @@ TEST(AaptConfigTest, WideColorGamutQualifier) {
ConfigDescription config;
EXPECT_TRUE(TestParse("widecg", &config));
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
- config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+ config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(String8("widecg-v26"), config.toString());
EXPECT_TRUE(TestParse("nowidecg", &config));
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
- config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+ config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(String8("nowidecg-v26"), config.toString());
}
@@ -118,13 +118,13 @@ TEST(AaptConfigTest, HdrQualifier) {
ConfigDescription config;
EXPECT_TRUE(TestParse("highdr", &config));
EXPECT_EQ(android::ResTable_config::HDR_YES,
- config.colorimetry & android::ResTable_config::MASK_HDR);
+ config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(String8("highdr-v26"), config.toString());
EXPECT_TRUE(TestParse("lowdr", &config));
EXPECT_EQ(android::ResTable_config::HDR_NO,
- config.colorimetry & android::ResTable_config::MASK_HDR);
+ config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(String8("lowdr-v26"), config.toString());
} \ No newline at end of file
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 20439cc498e6..dabaca6c9cf7 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -19,6 +19,7 @@ toolSources = [
"diff/Diff.cpp",
"dump/Dump.cpp",
"link/Link.cpp",
+ "strip/Strip.cpp",
]
cc_defaults {
@@ -119,6 +120,7 @@ cc_library_host_static {
"java/JavaClassGenerator.cpp",
"java/ManifestClassGenerator.cpp",
"java/ProguardRules.cpp",
+ "LoadedApk.cpp",
"Locale.cpp",
"Resource.cpp",
"ResourceParser.cpp",
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 5bea3ad1bbad..46098cbc3aa4 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -209,20 +209,20 @@ static bool parseScreenRound(const char* name, ResTable_config* out) {
static bool parseWideColorGamut(const char* name, ResTable_config* out) {
if (strcmp(name, kWildcardName) == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
ResTable_config::WIDE_COLOR_GAMUT_ANY;
return true;
} else if (strcmp(name, "widecg") == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
ResTable_config::WIDE_COLOR_GAMUT_YES;
return true;
} else if (strcmp(name, "nowidecg") == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
ResTable_config::WIDE_COLOR_GAMUT_NO;
return true;
}
@@ -232,20 +232,20 @@ static bool parseWideColorGamut(const char* name, ResTable_config* out) {
static bool parseHdr(const char* name, ResTable_config* out) {
if (strcmp(name, kWildcardName) == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_HDR) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_HDR) |
ResTable_config::HDR_ANY;
return true;
} else if (strcmp(name, "highdr") == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_HDR) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_HDR) |
ResTable_config::HDR_YES;
return true;
} else if (strcmp(name, "lowdr") == 0) {
if (out)
- out->colorimetry =
- (out->colorimetry & ~ResTable_config::MASK_HDR) |
+ out->colorMode =
+ (out->colorMode & ~ResTable_config::MASK_HDR) |
ResTable_config::HDR_NO;
return true;
}
@@ -840,8 +840,8 @@ void ConfigDescription::ApplyVersionForCompatibility(
uint16_t min_sdk = 0;
if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
== ResTable_config::UI_MODE_TYPE_VR_HEADSET ||
- config->colorimetry & ResTable_config::MASK_WIDE_COLOR_GAMUT ||
- config->colorimetry & ResTable_config::MASK_HDR) {
+ config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT ||
+ config->colorMode & ResTable_config::MASK_HDR) {
min_sdk = SDK_O;
} else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
min_sdk = SDK_MARSHMALLOW;
@@ -912,11 +912,11 @@ bool ConfigDescription::HasHigherPrecedenceThan(
if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
return !(o.screenLayout2 & MASK_SCREENROUND);
}
- if ((colorimetry | o.colorimetry) & MASK_HDR) {
- return !(o.colorimetry & MASK_HDR);
+ if ((colorMode | o.colorMode) & MASK_HDR) {
+ return !(o.colorMode & MASK_HDR);
}
- if ((colorimetry | o.colorimetry) & MASK_WIDE_COLOR_GAMUT) {
- return !(o.colorimetry & MASK_WIDE_COLOR_GAMUT);
+ if ((colorMode | o.colorMode) & MASK_WIDE_COLOR_GAMUT) {
+ return !(o.colorMode & MASK_WIDE_COLOR_GAMUT);
}
if (orientation || o.orientation) return (!o.orientation);
if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
@@ -964,9 +964,9 @@ bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
!pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
!pred(screenLayout2 & MASK_SCREENROUND,
o.screenLayout2 & MASK_SCREENROUND) ||
- !pred(colorimetry & MASK_HDR, o.colorimetry & MASK_HDR) ||
- !pred(colorimetry & MASK_WIDE_COLOR_GAMUT,
- o.colorimetry & MASK_WIDE_COLOR_GAMUT) ||
+ !pred(colorMode & MASK_HDR, o.colorMode & MASK_HDR) ||
+ !pred(colorMode & MASK_WIDE_COLOR_GAMUT,
+ o.colorMode & MASK_WIDE_COLOR_GAMUT) ||
!pred(orientation, o.orientation) ||
!pred(touchscreen, o.touchscreen) ||
!pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
diff --git a/tools/aapt2/ConfigDescription_test.cpp b/tools/aapt2/ConfigDescription_test.cpp
index b88838ae26f5..14a565624e01 100644
--- a/tools/aapt2/ConfigDescription_test.cpp
+++ b/tools/aapt2/ConfigDescription_test.cpp
@@ -106,13 +106,13 @@ TEST(ConfigDescriptionTest, TestWideColorGamutQualifier) {
ConfigDescription config;
EXPECT_TRUE(TestParse("widecg", &config));
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
- config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+ config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(std::string("widecg-v26"), config.toString().string());
EXPECT_TRUE(TestParse("nowidecg", &config));
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
- config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+ config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(std::string("nowidecg-v26"), config.toString().string());
}
@@ -121,13 +121,13 @@ TEST(ConfigDescriptionTest, TestHdrQualifier) {
ConfigDescription config;
EXPECT_TRUE(TestParse("highdr", &config));
EXPECT_EQ(android::ResTable_config::HDR_YES,
- config.colorimetry & android::ResTable_config::MASK_HDR);
+ config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(std::string("highdr-v26"), config.toString().string());
EXPECT_TRUE(TestParse("lowdr", &config));
EXPECT_EQ(android::ResTable_config::HDR_NO,
- config.colorimetry & android::ResTable_config::MASK_HDR);
+ config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
EXPECT_EQ(std::string("lowdr-v26"), config.toString().string());
}
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
new file mode 100644
index 000000000000..3d7bd9479ad8
--- /dev/null
+++ b/tools/aapt2/LoadedApk.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include "LoadedApk.h"
+
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
+#include "flatten/Archive.h"
+#include "flatten/TableFlattener.h"
+
+namespace aapt {
+
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
+ const android::StringPiece& path) {
+ Source source(path);
+ std::string error;
+ std::unique_ptr<io::ZipFileCollection> apk =
+ io::ZipFileCollection::Create(path, &error);
+ if (!apk) {
+ context->GetDiagnostics()->Error(DiagMessage(source) << error);
+ return {};
+ }
+
+ io::IFile* file = apk->FindFile("resources.arsc");
+ if (!file) {
+ context->GetDiagnostics()->Error(DiagMessage(source)
+ << "no resources.arsc found");
+ return {};
+ }
+
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (!data) {
+ context->GetDiagnostics()->Error(DiagMessage(source)
+ << "could not open resources.arsc");
+ return {};
+ }
+
+ std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+ BinaryResourceParser parser(context, table.get(), source, data->data(),
+ data->size());
+ if (!parser.Parse()) {
+ return {};
+ }
+
+ return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
+}
+
+bool LoadedApk::WriteToArchive(IAaptContext* context, IArchiveWriter* writer) {
+ std::set<std::string> referenced_resources;
+ // List the files being referenced in the resource table.
+ for (auto& pkg : table_->packages) {
+ for (auto& type : pkg->types) {
+ for (auto& entry : type->entries) {
+ for (auto& config_value : entry->values) {
+ FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
+ if (file_ref) {
+ referenced_resources.insert(*file_ref->path);
+ }
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<io::IFileCollectionIterator> iterator = apk_->Iterator();
+ while (iterator->HasNext()) {
+ io::IFile* file = iterator->Next();
+
+ std::string path = file->GetSource().path;
+ // The name of the path has the format "<zip-file-name>@<path-to-file>".
+ path = path.substr(path.find("@") + 1);
+
+ // Skip resources that are not referenced if requested.
+ if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
+ if (context->IsVerbose()) {
+ context->GetDiagnostics()->Note(DiagMessage()
+ << "Removing resource '" << path << "' from APK.");
+ }
+ continue;
+ }
+
+ // The resource table needs to be reserialized since it might have changed.
+ if (path == "resources.arsc") {
+ BigBuffer buffer = BigBuffer(1024);
+ TableFlattener flattener(&buffer);
+ if (!flattener.Consume(context, table_.get())) {
+ return false;
+ }
+
+ if (!writer->StartEntry(path, ArchiveEntry::kAlign) || !writer->WriteEntry(buffer) ||
+ !writer->FinishEntry()) {
+ context->GetDiagnostics()->Error(DiagMessage()
+ << "Error when writing file '" << path << "' in APK.");
+ return false;
+ }
+ continue;
+ }
+
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
+ if (!writer->StartEntry(path, compression_flags) ||
+ !writer->WriteEntry(data->data(), data->size()) || !writer->FinishEntry()) {
+ context->GetDiagnostics()->Error(DiagMessage()
+ << "Error when writing file '" << path << "' in APK.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
new file mode 100644
index 000000000000..f8878d13ae35
--- /dev/null
+++ b/tools/aapt2/LoadedApk.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LOADEDAPK_H
+#define AAPT_LOADEDAPK_H
+
+#include "androidfw/StringPiece.h"
+
+#include "ResourceTable.h"
+#include "flatten/Archive.h"
+#include "io/ZipArchive.h"
+#include "unflatten/BinaryResourceParser.h"
+
+namespace aapt {
+
+/** Info about an APK loaded in memory. */
+class LoadedApk {
+ public:
+ LoadedApk(
+ const Source& source,
+ std::unique_ptr<io::IFileCollection> apk,
+ std::unique_ptr<ResourceTable> table)
+ : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
+
+ io::IFileCollection* GetFileCollection() { return apk_.get(); }
+
+ ResourceTable* GetResourceTable() { return table_.get(); }
+
+ const Source& GetSource() { return source_; }
+
+ /**
+ * Writes the APK on disk at the given path, while also removing the resource
+ * files that are not referenced in the resource table.
+ */
+ bool WriteToArchive(IAaptContext* context, IArchiveWriter* writer);
+
+ static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
+ const android::StringPiece& path);
+
+ private:
+ Source source_;
+ std::unique_ptr<io::IFileCollection> apk_;
+ std::unique_ptr<ResourceTable> table_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadedApk);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_LOADEDAPK_H */
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 74d40194e955..227ffa34af4c 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@ namespace aapt {
static const char* sMajorVersion = "2";
// Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "4";
+static const char* sMinorVersion = "6";
int PrintVersion() {
std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
@@ -37,6 +37,7 @@ extern int Compile(const std::vector<android::StringPiece>& args);
extern int Link(const std::vector<android::StringPiece>& args);
extern int Dump(const std::vector<android::StringPiece>& args);
extern int Diff(const std::vector<android::StringPiece>& args);
+extern int Strip(const std::vector<android::StringPiece>& args);
} // namespace aapt
@@ -59,6 +60,8 @@ int main(int argc, char** argv) {
return aapt::Dump(args);
} else if (command == "diff") {
return aapt::Diff(args);
+ } else if (command == "strip") {
+ return aapt::Strip(args);
} else if (command == "version") {
return aapt::PrintVersion();
}
@@ -67,7 +70,7 @@ int main(int argc, char** argv) {
std::cerr << "no command specified\n";
}
- std::cerr << "\nusage: aapt2 [compile|link|dump|diff|version] ..."
+ std::cerr << "\nusage: aapt2 [compile|link|dump|diff|strip|version] ..."
<< std::endl;
return 1;
}
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index fdabce17433c..35971e7bd99b 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -39,6 +39,8 @@ StringPiece ToString(ResourceType type) {
return "bool";
case ResourceType::kColor:
return "color";
+ case ResourceType::kConfigVarying:
+ return "configVarying";
case ResourceType::kDimen:
return "dimen";
case ResourceType::kDrawable:
@@ -85,6 +87,7 @@ static const std::map<StringPiece, ResourceType> sResourceTypeMap{
{"^attr-private", ResourceType::kAttrPrivate},
{"bool", ResourceType::kBool},
{"color", ResourceType::kColor},
+ {"configVarying", ResourceType::kConfigVarying},
{"dimen", ResourceType::kDimen},
{"drawable", ResourceType::kDrawable},
{"font", ResourceType::kFont},
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 1950ea35a652..4d915d9f23c0 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -44,6 +44,11 @@ enum class ResourceType {
kAttrPrivate,
kBool,
kColor,
+
+ // Not really a type, but it shows up in some CTS tests and
+ // we need to continue respecting it.
+ kConfigVarying,
+
kDimen,
kDrawable,
kFont,
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 79379fe4b5ee..1c750c6748b9 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -338,50 +338,52 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*,
ParsedResource*)>;
- static const auto elToItemMap =
- ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
- {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
- {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
- {"dimen",
- {ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT |
- android::ResTable_map::TYPE_FRACTION |
- android::ResTable_map::TYPE_DIMENSION}},
- {"drawable",
- {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
- {"fraction",
- {ResourceType::kFraction,
- android::ResTable_map::TYPE_FLOAT |
- android::ResTable_map::TYPE_FRACTION |
- android::ResTable_map::TYPE_DIMENSION}},
- {"integer",
- {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
- {"string",
- {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
- });
-
- static const auto elToBagMap =
- ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
- {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
- {"array", std::mem_fn(&ResourceParser::ParseArray)},
- {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
- {"declare-styleable",
- std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
- {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
- {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
- {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
- {"public", std::mem_fn(&ResourceParser::ParsePublic)},
- {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
- {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
- {"style", std::mem_fn(&ResourceParser::ParseStyle)},
- {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
- });
+ static const auto elToItemMap = ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
+ {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
+ {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
+ {"configVarying", {ResourceType::kConfigVarying, android::ResTable_map::TYPE_ANY}},
+ {"dimen",
+ {ResourceType::kDimen,
+ android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+ android::ResTable_map::TYPE_DIMENSION}},
+ {"drawable", {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
+ {"fraction",
+ {ResourceType::kFraction,
+ android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+ android::ResTable_map::TYPE_DIMENSION}},
+ {"integer", {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
+ {"string", {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
+ });
+
+ static const auto elToBagMap = ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
+ {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
+ {"array", std::mem_fn(&ResourceParser::ParseArray)},
+ {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
+ {"configVarying",
+ std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kConfigVarying,
+ std::placeholders::_2, std::placeholders::_3)},
+ {"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
+ {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
+ {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+ {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
+ {"public", std::mem_fn(&ResourceParser::ParsePublic)},
+ {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
+ {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
+ {"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
+ std::placeholders::_2, std::placeholders::_3)},
+ {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+ });
std::string resource_type = parser->element_name();
// The value format accepted for this resource.
uint32_t resource_format = 0u;
+ bool can_be_item = true;
+ bool can_be_bag = true;
if (resource_type == "item") {
+ can_be_bag = false;
+
// Items have their type encoded in the type attribute.
if (Maybe<StringPiece> maybe_type =
xml::FindNonEmptyAttribute(parser, "type")) {
@@ -406,6 +408,17 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
return false;
}
}
+ } else if (resource_type == "bag") {
+ can_be_item = false;
+
+ // Bags have their type encoded in the type attribute.
+ if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+ resource_type = maybe_type.value().to_string();
+ } else {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ << "<bag> must have a 'type' attribute");
+ return false;
+ }
}
// Get the name of the resource. This will be checked later, because not all
@@ -426,36 +439,61 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
return true;
}
- const auto item_iter = elToItemMap.find(resource_type);
- if (item_iter != elToItemMap.end()) {
- // This is an item, record its type and format and start parsing.
+ if (can_be_item) {
+ const auto item_iter = elToItemMap.find(resource_type);
+ if (item_iter != elToItemMap.end()) {
+ // This is an item, record its type and format and start parsing.
- if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
- return false;
- }
+ if (!maybe_name) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
+ return false;
+ }
- out_resource->name.type = item_iter->second.type;
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.type = item_iter->second.type;
+ out_resource->name.entry = maybe_name.value().to_string();
- // Only use the implicit format for this type if it wasn't overridden.
- if (!resource_format) {
- resource_format = item_iter->second.format;
- }
+ // Only use the implicit format for this type if it wasn't overridden.
+ if (!resource_format) {
+ resource_format = item_iter->second.format;
+ }
- if (!ParseItem(parser, out_resource, resource_format)) {
- return false;
+ if (!ParseItem(parser, out_resource, resource_format)) {
+ return false;
+ }
+ return true;
}
- return true;
}
// This might be a bag or something.
- const auto bag_iter = elToBagMap.find(resource_type);
- if (bag_iter != elToBagMap.end()) {
- // Ensure we have a name (unless this is a <public-group>).
- if (resource_type != "public-group") {
+ if (can_be_bag) {
+ const auto bag_iter = elToBagMap.find(resource_type);
+ if (bag_iter != elToBagMap.end()) {
+ // Ensure we have a name (unless this is a <public-group>).
+ if (resource_type != "public-group") {
+ if (!maybe_name) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
+ return false;
+ }
+
+ out_resource->name.entry = maybe_name.value().to_string();
+ }
+
+ // Call the associated parse method. The type will be filled in by the
+ // parse func.
+ if (!bag_iter->second(this, parser, out_resource)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ if (can_be_item) {
+ // Try parsing the elementName (or type) as a resource. These shall only be
+ // resources like 'layout' or 'xml' and they can only be references.
+ const ResourceType* parsed_type = ParseResourceType(resource_type);
+ if (parsed_type) {
if (!maybe_name) {
diag_->Error(DiagMessage(out_resource->source)
<< "<" << parser->element_name()
@@ -463,39 +501,16 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
return false;
}
+ out_resource->name.type = *parsed_type;
out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+ if (!out_resource->value) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "invalid value for type '" << *parsed_type << "'. Expected a reference");
+ return false;
+ }
+ return true;
}
-
- // Call the associated parse method. The type will be filled in by the
- // parse func.
- if (!bag_iter->second(this, parser, out_resource)) {
- return false;
- }
- return true;
- }
-
- // Try parsing the elementName (or type) as a resource. These shall only be
- // resources like 'layout' or 'xml' and they can only be references.
- const ResourceType* parsed_type = ParseResourceType(resource_type);
- if (parsed_type) {
- if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
- return false;
- }
-
- out_resource->name.type = *parsed_type;
- out_resource->name.entry = maybe_name.value().to_string();
- out_resource->value =
- ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
- if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source)
- << "invalid value for type '" << *parsed_type
- << "'. Expected a reference");
- return false;
- }
- return true;
}
diag_->Warn(DiagMessage(out_resource->source)
@@ -1048,9 +1063,9 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
return true;
}
-bool ResourceParser::ParseStyle(xml::XmlPullParser* parser,
+bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
ParsedResource* out_resource) {
- out_resource->name.type = ResourceType::kStyle;
+ out_resource->name.type = type;
std::unique_ptr<Style> style = util::make_unique<Style>();
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index c12dacf1c707..cc0fa26f44d5 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -102,7 +102,8 @@ class ResourceParser {
bool weak);
Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
const android::StringPiece& tag);
- bool ParseStyle(xml::XmlPullParser* parser, ParsedResource* out_resource);
+ bool ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
+ ParsedResource* out_resource);
bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
bool ParseDeclareStyleable(xml::XmlPullParser* parser,
ParsedResource* out_resource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 5762fb035a81..cf901dae11bb 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -719,4 +719,23 @@ TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
}
+TEST_F(ResourceParserTest, ParseConfigVaryingItem) {
+ std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
+ ASSERT_TRUE(TestParse(input));
+ ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
+}
+
+TEST_F(ResourceParserTest, ParseBagElement) {
+ std::string input =
+ R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
+ ASSERT_TRUE(TestParse(input));
+
+ Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
+ ASSERT_NE(nullptr, val);
+
+ ASSERT_EQ(1u, val->entries.size());
+ EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
+ EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 6acb4d3eb850..ad4e3ce02b32 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -49,6 +49,10 @@ TEST(ResourceTypeTest, ParseResourceTypes) {
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kColor);
+ type = ParseResourceType("configVarying");
+ ASSERT_NE(type, nullptr);
+ EXPECT_EQ(*type, ResourceType::kConfigVarying);
+
type = ParseResourceType("dimen");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kDimen);
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
index de0fe404b867..acebedafe43d 100644
--- a/tools/aapt2/diff/Diff.cpp
+++ b/tools/aapt2/diff/Diff.cpp
@@ -17,12 +17,10 @@
#include "android-base/macros.h"
#include "Flags.h"
-#include "ResourceTable.h"
+#include "LoadedApk.h"
#include "ValueVisitor.h"
-#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
-#include "unflatten/BinaryResourceParser.h"
using android::StringPiece;
@@ -51,61 +49,6 @@ class DiffContext : public IAaptContext {
SymbolTable symbol_table_;
};
-class LoadedApk {
- public:
- LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table)
- : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
-
- io::IFileCollection* GetFileCollection() { return apk_.get(); }
-
- ResourceTable* GetResourceTable() { return table_.get(); }
-
- const Source& GetSource() { return source_; }
-
- private:
- Source source_;
- std::unique_ptr<io::IFileCollection> apk_;
- std::unique_ptr<ResourceTable> table_;
-
- DISALLOW_COPY_AND_ASSIGN(LoadedApk);
-};
-
-static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
- const StringPiece& path) {
- Source source(path);
- std::string error;
- std::unique_ptr<io::ZipFileCollection> apk =
- io::ZipFileCollection::Create(path, &error);
- if (!apk) {
- context->GetDiagnostics()->Error(DiagMessage(source) << error);
- return {};
- }
-
- io::IFile* file = apk->FindFile("resources.arsc");
- if (!file) {
- context->GetDiagnostics()->Error(DiagMessage(source)
- << "no resources.arsc found");
- return {};
- }
-
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(source)
- << "could not open resources.arsc");
- return {};
- }
-
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(context, table.get(), source, data->data(),
- data->size());
- if (!parser.Parse()) {
- return {};
- }
-
- return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
-}
-
static void EmitDiffLine(const Source& source, const StringPiece& message) {
std::cerr << source << ": " << message << "\n";
}
@@ -413,9 +356,9 @@ int Diff(const std::vector<StringPiece>& args) {
}
std::unique_ptr<LoadedApk> apk_a =
- LoadApkFromPath(&context, flags.GetArgs()[0]);
+ LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
std::unique_ptr<LoadedApk> apk_b =
- LoadApkFromPath(&context, flags.GetArgs()[1]);
+ LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[1]);
if (!apk_a || !apk_b) {
return 1;
}
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/AppOne/Android.mk
index bc40a6269382..a6f32d4b9fdc 100644
--- a/tools/aapt2/integration-tests/AppOne/Android.mk
+++ b/tools/aapt2/integration-tests/AppOne/Android.mk
@@ -24,5 +24,5 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_STATIC_ANDROID_LIBRARIES := \
AaptTestStaticLibOne \
AaptTestStaticLibTwo
-LOCAL_AAPT_FLAGS := --no-version-vectors
+LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions
include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml b/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml
new file mode 100644
index 000000000000..e10e6c2f53da
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+ android:transitionOrdering="sequential">
+ <fade android:fadingMode="fade_out" />
+ <changeBounds />
+ <fade android:fadingMode="fade_in" />
+</transitionSet>
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 3d5b5b11707e..1ef9743f65cf 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -63,6 +63,11 @@ class IFile {
IFile* CreateFileSegment(size_t offset, size_t len);
+ /** Returns whether the file was compressed before it was stored in memory. */
+ virtual bool WasCompressed() {
+ return false;
+ }
+
private:
// Any segments created from this IFile need to be owned by this IFile, so
// keep them
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 62b436fe4dc7..6494d2def748 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -59,6 +59,10 @@ std::unique_ptr<IData> ZipFile::OpenAsData() {
const Source& ZipFile::GetSource() const { return source_; }
+bool ZipFile::WasCompressed() {
+ return zip_entry_.method != kCompressStored;
+}
+
ZipFileCollectionIterator::ZipFileCollectionIterator(
ZipFileCollection* collection)
: current_(collection->files_.begin()), end_(collection->files_.end()) {}
@@ -66,7 +70,7 @@ ZipFileCollectionIterator::ZipFileCollectionIterator(
bool ZipFileCollectionIterator::HasNext() { return current_ != end_; }
IFile* ZipFileCollectionIterator::Next() {
- IFile* result = current_->second.get();
+ IFile* result = current_->get();
++current_;
return result;
}
@@ -110,8 +114,10 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
std::string(reinterpret_cast<const char*>(zip_entry_name.name),
zip_entry_name.name_length);
std::string nested_path = path.to_string() + "@" + zip_entry_path;
- collection->files_[zip_entry_path] = util::make_unique<ZipFile>(
- collection->handle_, zip_data, Source(nested_path));
+ std::unique_ptr<IFile> file =
+ util::make_unique<ZipFile>(collection->handle_, zip_data, Source(nested_path));
+ collection->files_by_name_[zip_entry_path] = file.get();
+ collection->files_.push_back(std::move(file));
}
if (result != -1) {
@@ -122,9 +128,9 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
}
IFile* ZipFileCollection::FindFile(const StringPiece& path) {
- auto iter = files_.find(path.to_string());
- if (iter != files_.end()) {
- return iter->second.get();
+ auto iter = files_by_name_.find(path.to_string());
+ if (iter != files_by_name_.end()) {
+ return iter->second;
}
return nullptr;
}
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 634adad8af32..56c74e326e6c 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -40,6 +40,7 @@ class ZipFile : public IFile {
std::unique_ptr<IData> OpenAsData() override;
const Source& GetSource() const override;
+ bool WasCompressed() override;
private:
ZipArchiveHandle zip_handle_;
@@ -57,7 +58,7 @@ class ZipFileCollectionIterator : public IFileCollectionIterator {
io::IFile* Next() override;
private:
- std::map<std::string, std::unique_ptr<IFile>>::const_iterator current_, end_;
+ std::vector<std::unique_ptr<IFile>>::const_iterator current_, end_;
};
/**
@@ -78,7 +79,8 @@ class ZipFileCollection : public IFileCollection {
ZipFileCollection();
ZipArchiveHandle handle_;
- std::map<std::string, std::unique_ptr<IFile>> files_;
+ std::vector<std::unique_ptr<IFile>> files_;
+ std::map<std::string, IFile*> files_by_name_;
};
} // namespace io
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index c3ce0760f554..f7e0f8f55fd4 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -80,6 +80,7 @@ struct LinkOptions {
// Optimizations/features.
bool no_auto_version = false;
bool no_version_vectors = false;
+ bool no_version_transitions = false;
bool no_resource_deduping = false;
bool no_xml_namespaces = false;
bool do_not_compress_anything = false;
@@ -250,6 +251,7 @@ static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path,
struct ResourceFileFlattenerOptions {
bool no_auto_version = false;
bool no_version_vectors = false;
+ bool no_version_transitions = false;
bool no_xml_namespaces = false;
bool keep_raw_values = false;
bool do_not_compress_anything = false;
@@ -306,6 +308,23 @@ uint32_t ResourceFileFlattener::GetCompressionFlags(const StringPiece& str) {
return ArchiveEntry::kCompress;
}
+static bool IsTransitionElement(const std::string& name) {
+ return
+ name == "fade" ||
+ name == "changeBounds" ||
+ name == "slide" ||
+ name == "explode" ||
+ name == "changeImageTransform" ||
+ name == "changeTransform" ||
+ name == "changeClipBounds" ||
+ name == "autoTransition" ||
+ name == "recolor" ||
+ name == "changeScroll" ||
+ name == "transitionSet" ||
+ name == "transition" ||
+ name == "transitionManager";
+}
+
bool ResourceFileFlattener::LinkAndVersionXmlFile(
ResourceTable* table, FileOperation* file_op,
std::queue<FileOperation>* out_file_op_queue) {
@@ -345,6 +364,17 @@ bool ResourceFileFlattener::LinkAndVersionXmlFile(
}
}
}
+ if (options_.no_version_transitions) {
+ // Skip this if it is a transition resource.
+ xml::Element* el = xml::FindRootElement(doc);
+ if (el && el->namespace_uri.empty()) {
+ if (IsTransitionElement(el->name)) {
+ // We are NOT going to version this file.
+ file_op->skip_version = true;
+ return true;
+ }
+ }
+ }
const ConfigDescription& config = file_op->config;
@@ -1384,6 +1414,7 @@ class LinkCommand {
options_.extensions_to_not_compress;
file_flattener_options.no_auto_version = options_.no_auto_version;
file_flattener_options.no_version_vectors = options_.no_version_vectors;
+ file_flattener_options.no_version_transitions = options_.no_version_transitions;
file_flattener_options.no_xml_namespaces = options_.no_xml_namespaces;
file_flattener_options.update_proguard_spec =
static_cast<bool>(options_.generate_proguard_rules_path);
@@ -1863,6 +1894,11 @@ int Link(const std::vector<StringPiece>& args) {
"Use this only\n"
"when building with vector drawable support library",
&options.no_version_vectors)
+ .OptionalSwitch("--no-version-transitions",
+ "Disables automatic versioning of transition resources. "
+ "Use this only\n"
+ "when building with transition support library",
+ &options.no_version_transitions)
.OptionalSwitch("--no-resource-deduping",
"Disables automatic deduping of resources with\n"
"identical values across compatible configurations.",
@@ -2104,6 +2140,7 @@ int Link(const std::vector<StringPiece>& args) {
if (options.static_lib) {
options.no_auto_version = true;
options.no_version_vectors = true;
+ options.no_version_transitions = true;
}
LinkCommand cmd(&context, options);
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index e5eaf2fe62a8..b4cf4f8d7f54 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -111,6 +111,36 @@ static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
return true;
}
+// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
+static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
+ bool has_name = false;
+ if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
+ if (attr->value.empty()) {
+ diag->Error(DiagMessage(el->line_number)
+ << "android:name in <uses-feature> must not be empty");
+ return false;
+ }
+ has_name = true;
+ }
+
+ bool has_gl_es_version = false;
+ if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
+ if (has_name) {
+ diag->Error(DiagMessage(el->line_number)
+ << "cannot define both android:name and android:glEsVersion in <uses-feature>");
+ return false;
+ }
+ has_gl_es_version = true;
+ }
+
+ if (!has_name && !has_gl_es_version) {
+ diag->Error(DiagMessage(el->line_number)
+ << "<uses-feature> must have either android:name or android:glEsVersion attribute");
+ return false;
+ }
+ return true;
+}
+
bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
IDiagnostics* diag) {
// First verify some options.
@@ -134,15 +164,25 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
}
}
- // Common intent-filter actions.
+ // Common <intent-filter> actions.
xml::XmlNodeAction intent_filter_action;
intent_filter_action["action"];
intent_filter_action["category"];
intent_filter_action["data"];
- // Common meta-data actions.
+ // Common <meta-data> actions.
xml::XmlNodeAction meta_data_action;
+ // Common <uses-feature> actions.
+ xml::XmlNodeAction uses_feature_action;
+ uses_feature_action.Action(VerifyUsesFeature);
+
+ // Common component actions.
+ xml::XmlNodeAction component_action;
+ component_action.Action(RequiredNameIsJavaClassName);
+ component_action["intent-filter"] = intent_filter_action;
+ component_action["meta-data"] = meta_data_action;
+
// Manifest actions.
xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
manifest_action.Action(VerifyManifest);
@@ -190,6 +230,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
});
// Instrumentation actions.
+ manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
if (!options_.rename_instrumentation_target_package) {
return true;
@@ -201,6 +242,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
}
return true;
});
+ manifest_action["instrumentation"]["meta-data"] = meta_data_action;
manifest_action["original-package"];
manifest_action["protected-broadcast"];
@@ -208,51 +250,28 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
manifest_action["permission"];
manifest_action["permission-tree"];
manifest_action["permission-group"];
-
manifest_action["uses-configuration"];
- manifest_action["uses-feature"];
manifest_action["supports-screens"];
-
+ manifest_action["uses-feature"] = uses_feature_action;
+ manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
manifest_action["compatible-screens"];
manifest_action["compatible-screens"]["screen"];
-
manifest_action["supports-gl-texture"];
-
manifest_action["meta-data"] = meta_data_action;
// Application actions.
xml::XmlNodeAction& application_action = manifest_action["application"];
application_action.Action(OptionalNameIsJavaClassName);
- // Uses library actions.
application_action["uses-library"];
-
- // Meta-data.
application_action["meta-data"] = meta_data_action;
-
- // Activity actions.
- application_action["activity"].Action(RequiredNameIsJavaClassName);
- application_action["activity"]["intent-filter"] = intent_filter_action;
- application_action["activity"]["meta-data"] = meta_data_action;
-
- // Activity alias actions.
- application_action["activity-alias"]["intent-filter"] = intent_filter_action;
- application_action["activity-alias"]["meta-data"] = meta_data_action;
-
- // Service actions.
- application_action["service"].Action(RequiredNameIsJavaClassName);
- application_action["service"]["intent-filter"] = intent_filter_action;
- application_action["service"]["meta-data"] = meta_data_action;
-
- // Receiver actions.
- application_action["receiver"].Action(RequiredNameIsJavaClassName);
- application_action["receiver"]["intent-filter"] = intent_filter_action;
- application_action["receiver"]["meta-data"] = meta_data_action;
+ application_action["activity"] = component_action;
+ application_action["activity-alias"] = component_action;
+ application_action["service"] = component_action;
+ application_action["receiver"] = component_action;
// Provider actions.
- application_action["provider"].Action(RequiredNameIsJavaClassName);
- application_action["provider"]["intent-filter"] = intent_filter_action;
- application_action["provider"]["meta-data"] = meta_data_action;
+ application_action["provider"] = component_action;
application_action["provider"]["grant-uri-permissions"];
application_action["provider"]["path-permissions"];
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 12a304a39f4b..ce84993feebe 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -90,7 +90,7 @@ TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
}
TEST_F(ManifestFixerTest, AllowMetaData) {
- auto doc = Verify(R"EOF(
+ auto doc = Verify(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<meta-data />
@@ -98,12 +98,13 @@ TEST_F(ManifestFixerTest, AllowMetaData) {
<meta-data />
<activity android:name=".Hi"><meta-data /></activity>
<activity-alias android:name=".Ho"><meta-data /></activity-alias>
- <receiver android:name=".OffToWork"><meta-data /></receiver>
- <provider android:name=".We"><meta-data /></provider>
- <service android:name=".Go"><meta-data /></service>
+ <receiver android:name=".OffTo"><meta-data /></receiver>
+ <provider android:name=".Work"><meta-data /></provider>
+ <service android:name=".We"><meta-data /></service>
</application>
+ <instrumentation android:name=".Go"><meta-data /></instrumentation>
</manifest>)EOF");
- ASSERT_NE(nullptr, doc);
+ ASSERT_NE(nullptr, doc);
}
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
@@ -290,7 +291,7 @@ TEST_F(ManifestFixerTest,
std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
- <instrumentation android:targetPackage="android" />
+ <instrumentation android:name=".TestRunner" android:targetPackage="android" />
</manifest>)EOF",
options);
ASSERT_NE(nullptr, doc);
@@ -354,4 +355,51 @@ TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
}
+TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
+ std::string input = R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <uses-feature android:name="feature" />
+ <uses-feature android:glEsVersion="1" />
+ <feature-group />
+ <feature-group>
+ <uses-feature android:name="feature_in_group" />
+ <uses-feature android:glEsVersion="2" />
+ </feature-group>
+ </manifest>)EOF";
+ EXPECT_NE(nullptr, Verify(input));
+
+ input = R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <uses-feature android:name="feature" android:glEsVersion="1" />
+ </manifest>)EOF";
+ EXPECT_EQ(nullptr, Verify(input));
+
+ input = R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <uses-feature />
+ </manifest>)EOF";
+ EXPECT_EQ(nullptr, Verify(input));
+
+ input = R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <feature-group>
+ <uses-feature android:name="feature" android:glEsVersion="1" />
+ </feature-group>
+ </manifest>)EOF";
+ EXPECT_EQ(nullptr, Verify(input));
+
+ input = R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <feature-group>
+ <uses-feature />
+ </feature-group>
+ </manifest>)EOF";
+ EXPECT_EQ(nullptr, Verify(input));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 800103307e2b..44d22c42468d 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,17 @@
# Android Asset Packaging Tool 2.0 (AAPT2) release notes
+## Version 2.6
+### `aapt2`
+- Support legacy `configVarying` resource type.
+- Support `<bag>` tag and treat as `<style>` regardless of type.
+- Add `<feature-group>` manifest tag verification.
+- Add `<meta-data>` tag support to `<instrumentation>`.
+
+## Version 2.5
+### `aapt2 link ...`
+- Transition XML versioning: Adds a new flag `--no-version-transitions` to disable automatic
+ versioning of Transition XML resources.
+
## Version 2.4
### `aapt2 link ...`
- Supports `<meta-data>` tags in `<manifest>`.
diff --git a/tools/aapt2/strip/Strip.cpp b/tools/aapt2/strip/Strip.cpp
new file mode 100644
index 000000000000..c34cfbf3580e
--- /dev/null
+++ b/tools/aapt2/strip/Strip.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <vector>
+
+#include "androidfw/StringPiece.h"
+
+#include "Diagnostics.h"
+#include "Flags.h"
+#include "LoadedApk.h"
+#include "split/TableSplitter.h"
+
+using android::StringPiece;
+
+namespace aapt {
+
+struct StripOptions {
+ /** Path to the output APK. */
+ std::string output_path;
+
+ /** List of screen density configurations the APK will be optimized for. */
+ std::vector<ConfigDescription> target_configs;
+};
+
+class StripContext : public IAaptContext {
+ public:
+ IDiagnostics* GetDiagnostics() override { return &diagnostics_; }
+
+ NameMangler* GetNameMangler() override {
+ abort();
+ return nullptr;
+ }
+
+ const std::string& GetCompilationPackage() override {
+ static std::string empty;
+ return empty;
+ }
+
+ uint8_t GetPackageId() override { return 0; }
+
+ SymbolTable* GetExternalSymbols() override {
+ abort();
+ return nullptr;
+ }
+
+ bool IsVerbose() override { return verbose_; }
+
+ void SetVerbose(bool val) { verbose_ = val; }
+
+ int GetMinSdkVersion() override { return 0; }
+
+ private:
+ StdErrDiagnostics diagnostics_;
+ bool verbose_ = false;
+};
+
+class StripCommand {
+ public:
+ StripCommand(StripContext* context, const StripOptions& options)
+ : options_(options),
+ context_(context) {}
+
+ int Run(std::unique_ptr<LoadedApk> apk) {
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(DiagMessage() << "Stripping APK...");
+ }
+
+ // TODO(lecesne): Add support for more than one density.
+ if (options_.target_configs.size() > 1) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "Multiple densities not supported at the moment");
+ return 1;
+ }
+
+ // Stripping the APK using the TableSplitter with no splits and the target
+ // density as the preferred density. The resource table is modified in
+ // place in the LoadedApk.
+ TableSplitterOptions splitter_options;
+ splitter_options.preferred_density = options_.target_configs[0].density;
+ std::vector<SplitConstraints> splits;
+ TableSplitter splitter(splits, splitter_options);
+ splitter.SplitTable(apk->GetResourceTable());
+
+ std::unique_ptr<IArchiveWriter> writer =
+ CreateZipFileArchiveWriter(context_->GetDiagnostics(), options_.output_path);
+ if (!apk->WriteToArchive(context_, writer.get())) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ private:
+ StripOptions options_;
+ StripContext* context_;
+};
+
+int Strip(const std::vector<StringPiece>& args) {
+ StripContext context;
+ StripOptions options;
+ std::string target_densities;
+ bool verbose = false;
+ Flags flags =
+ Flags()
+ .RequiredFlag("-o", "Path to the output APK.", &options.output_path)
+ .RequiredFlag(
+ "--target-densities",
+ "Comma separated list of the screen densities that the APK will "
+ "be optimized for. All the resources that would be unused on "
+ "devices of the given densities will be removed from the APK.",
+ &target_densities)
+ .OptionalSwitch("-v", "Enables verbose logging", &verbose);
+
+ if (!flags.Parse("aapt2 strip", args, &std::cerr)) {
+ return 1;
+ }
+
+ if (flags.GetArgs().size() != 1u) {
+ std::cerr << "must have one APK as argument.\n\n";
+ flags.Usage("aapt2 strip", &std::cerr);
+ return 1;
+ }
+
+ std::unique_ptr<LoadedApk> apk =
+ LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
+ if (!apk) {
+ return 1;
+ }
+
+ if (verbose) {
+ context.SetVerbose(verbose);
+ }
+
+ // Parse the target screen densities.
+ for (const StringPiece& config_str : util::Tokenize(target_densities, ',')) {
+ ConfigDescription config;
+ if (!ConfigDescription::Parse(config_str, &config) || config.density == 0) {
+ context.GetDiagnostics()->Error(
+ DiagMessage() << "invalid density '" << config_str
+ << "' for --target-densities option");
+ return 1;
+ }
+
+ // Clear the version that can be automatically added.
+ config.sdkVersion = 0;
+
+ if (config.diff(ConfigDescription::DefaultConfig()) !=
+ ConfigDescription::CONFIG_DENSITY) {
+ context.GetDiagnostics()->Error(
+ DiagMessage() << "invalid density '" << config_str
+ << "' for --target-densities option. Must be only a "
+ << "density value.");
+ return 1;
+ }
+
+ options.target_configs.push_back(config);
+ }
+
+ StripCommand cmd(&context, options);
+ return cmd.Run(std::move(apk));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index aeabcff011ed..7098fe9f7cb6 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -370,8 +370,7 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
return false;
}
- if (!table_->AddResourceAllowMangled(name, config, {},
- std::move(resource_value),
+ if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
context_->GetDiagnostics())) {
return false;
}
diff --git a/tools/incident_report/Android.mk b/tools/incident_report/Android.mk
index 9e56e3d7eeaf..e57a95949e5a 100644
--- a/tools/incident_report/Android.mk
+++ b/tools/incident_report/Android.mk
@@ -34,6 +34,9 @@ LOCAL_SHARED_LIBRARIES := \
libplatformprotos \
libprotobuf-cpp-full
+# b/34740546, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -modernize*
+
LOCAL_C_FLAGS := \
-Wno-unused-parameter
include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/incident_section_gen/Android.mk b/tools/incident_section_gen/Android.mk
index acf3f8327b5c..05490266576a 100644
--- a/tools/incident_section_gen/Android.mk
+++ b/tools/incident_section_gen/Android.mk
@@ -21,6 +21,8 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := incident-section-gen
+# b/34740546, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -modernize*
LOCAL_CFLAGS += -g -O0
LOCAL_C_INCLUDES := \
external/protobuf/src
diff --git a/tools/layoutlib/.idea/libraries/mockito.xml b/tools/layoutlib/.idea/libraries/mockito.xml
new file mode 100644
index 000000000000..032963e40b94
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/mockito.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+ <library name="mockito">
+ <CLASSES>
+ <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/mockito-host_intermediates/javalib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+</component> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/objenesis.xml b/tools/layoutlib/.idea/libraries/objenesis.xml
new file mode 100644
index 000000000000..1484de59be6a
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/objenesis.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+ <library name="objenesis">
+ <CLASSES>
+ <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/objenesis-host_intermediates/javalib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+</component> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index fbaed520fff9..85ec3eb73b92 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -86,5 +86,7 @@
</library>
</orderEntry>
<orderEntry type="library" scope="TEST" name="junit" level="project" />
+ <orderEntry type="library" scope="TEST" name="mockito" level="project" />
+ <orderEntry type="library" scope="TEST" name="objenesis" level="project" />
</component>
</module> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 9d9d71f66de9..8c6740c41052 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -636,6 +636,20 @@ public final class Bitmap_Delegate {
Bitmap.getDefaultDensity());
}
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.nativeCreateHardwareBitmap() is not supported", null /*data*/);
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.nativeCreateGraphicBufferHandle() is not supported", null /*data*/);
+ return null;
+ }
+
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index c599e9d6d6bc..47216eec03bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -209,20 +209,20 @@ public final class Canvas_Delegate extends BaseCanvas_Delegate {
}
@LayoutlibDelegate
- public static void nRestore(long nativeCanvas, boolean throwOnUnderflow) {
+ public static boolean nRestore(long nativeCanvas) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
- return;
+ return false;
}
canvasDelegate.restore();
+ return true;
}
@LayoutlibDelegate
- public static void nRestoreToCount(long nativeCanvas, int saveCount,
- boolean throwOnUnderflow) {
+ public static void nRestoreToCount(long nativeCanvas, int saveCount) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
@@ -427,7 +427,7 @@ public final class Canvas_Delegate extends BaseCanvas_Delegate {
}
@LayoutlibDelegate
- public static void nGetCTM(long canvas, long matrix) {
+ public static void nGetMatrix(long canvas, long matrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
if (canvasDelegate == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index d0c959972b13..a43e54579da2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -249,14 +249,17 @@ public class FontFamily_Delegate {
// ---- delegate methods ----
@LayoutlibDelegate
/*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex) {
- final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mNativePtr);
+ if (thisFontFamily.mBuilderPtr == 0) {
+ throw new IllegalStateException("Unable to call addFont after freezing.");
+ }
+ final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mBuilderPtr);
return delegate != null && delegate.addFont(path, ttcIndex);
}
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static long nCreateFamily(String lang, int variant) {
+ /*package*/ static long nInitBuilder(String lang, int variant) {
// TODO: support lang. This is required for japanese locale.
FontFamily_Delegate delegate = new FontFamily_Delegate();
// variant can be 0, 1 or 2.
@@ -271,6 +274,11 @@ public class FontFamily_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static long nCreateFamily(long builderPtr) {
+ return builderPtr;
+ }
+
+ @LayoutlibDelegate
/*package*/ static void nUnrefFamily(long nativePtr) {
// Removing the java reference for the object doesn't mean that it's freed for garbage
// collection. Typeface_Delegate may still hold a reference for it.
@@ -278,22 +286,22 @@ public class FontFamily_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex) {
+ /*package*/ static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) {
assert false : "The only client of this method has been overriden.";
return false;
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
int ttcIndex, List<FontConfig.Axis> listOfAxis,
int weight, boolean isItalic) {
assert false : "The only client of this method has been overriden.";
return false;
}
- static boolean addFont(long nativeFamily, final String path, final int weight,
+ static boolean addFont(long builderPtr, final String path, final int weight,
final boolean isItalic) {
- final FontFamily_Delegate delegate = getDelegate(nativeFamily);
+ final FontFamily_Delegate delegate = getDelegate(builderPtr);
if (delegate != null) {
if (sFontLocation == null) {
delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, isItalic));
@@ -305,8 +313,9 @@ public class FontFamily_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
- FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
+ /*package*/ static boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr, String path,
+ int cookie, boolean isAsset) {
+ FontFamily_Delegate ffd = sManager.getDelegate(builderPtr);
if (ffd == null) {
return false;
}
@@ -380,6 +389,10 @@ public class FontFamily_Delegate {
return false;
}
+ @LayoutlibDelegate
+ /*package*/ static void nAbort(long builderPtr) {
+ sManager.removeJavaReferenceFor(builderPtr);
+ }
// ---- private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 9b8fa996a017..aa1f00dee42e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -1062,8 +1062,6 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void nSetWordSpacing(long nativePaint, float wordSpacing) {
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
- "Paint.setWordSpacing() not supported.", null, null);
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 6e337d50a31f..11328dce94e1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -16,12 +16,14 @@
package android.graphics;
-import android.text.FontConfig;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.annotation.NonNull;
import android.graphics.FontFamily_Delegate.FontVariant;
+import android.text.FontConfig;
import java.awt.Font;
import java.io.File;
@@ -160,6 +162,18 @@ public final class Typeface_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static synchronized long nativeCreateFromTypefaceWithVariation(long native_instance,
+ List<FontConfig.Axis> axes) {
+ long newInstance = nativeCreateFromTypeface(native_instance, 0);
+
+ if (newInstance != 0) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "nativeCreateFromTypefaceWithVariation is not supported", null, null);
+ }
+ return newInstance;
+ }
+
+ @LayoutlibDelegate
/*package*/ static long nativeCreateWeightAlias(long native_instance, int weight) {
Typeface_Delegate delegate = sManager.getDelegate(native_instance);
if (delegate == null) {
@@ -213,9 +227,10 @@ public final class Typeface_Delegate {
Map<String, ByteBuffer> bufferForPath) {
FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
for (FontConfig.Font font : family.getFonts()) {
- FontFamily_Delegate.addFont(fontFamily.mNativePtr, font.getFontName(),
+ FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, font.getFontName(),
font.getWeight(), font.isItalic());
}
+ fontFamily.freeze();
return fontFamily;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 430607aa178b..eee74734fde5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -156,7 +156,7 @@ public class VectorDrawable_Delegate {
bounds.offsetTo(0, 0);
nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
- Canvas_Delegate.nRestore(canvasWrapperPtr, true);
+ Canvas_Delegate.nRestore(canvasWrapperPtr);
return bounds.width() * bounds.height();
}
@@ -1122,7 +1122,7 @@ public class VectorDrawable_Delegate {
drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
}
}
- Canvas_Delegate.nRestore(canvasPtr, true);
+ Canvas_Delegate.nRestore(canvasPtr);
}
public void draw(long canvasPtr, long filterPtr, int w, int h) {
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index 65c0a07bbac4..970c7d577c51 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -75,7 +75,8 @@ public class StaticLayout_Delegate {
/*package*/ static void nSetupParagraph(long nativeBuilder, char[] text, int length,
float firstWidth, int firstWidthLineCount, float restWidth,
int[] variableTabStops, int defaultTabStop, int breakStrategy,
- int hyphenationFrequency) {
+ int hyphenationFrequency, boolean isJustified) {
+ // TODO: implement justified alignment
Builder builder = sBuilderManager.getDelegate(nativeBuilder);
if (builder == null) {
return;
diff --git a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
index 138b2d5fca3d..9fd1e1557537 100644
--- a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
@@ -16,6 +16,7 @@
package android.util;
+import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.internal.util.XmlUtils;
@@ -27,6 +28,11 @@ import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
+import android.annotation.NonNull;
+
+import java.util.Map;
+import java.util.function.Function;
+
/**
* A correct implementation of the {@link AttributeSet} interface on top of a XmlPullParser
*/
@@ -34,12 +40,30 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
private final BridgeContext mContext;
private final boolean mPlatformFile;
-
- public BridgeXmlPullAttributes(XmlPullParser parser, BridgeContext context,
- boolean platformFile) {
+ private final Function<String, Map<String, Integer>> mFrameworkEnumValueSupplier;
+ private final Function<String, Map<String, Integer>> mProjectEnumValueSupplier;
+
+ // VisibleForTesting
+ BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
+ boolean platformFile,
+ @NonNull Function<String, Map<String, Integer>> frameworkEnumValueSupplier,
+ @NonNull Function<String, Map<String, Integer>> projectEnumValueSupplier) {
super(parser);
mContext = context;
mPlatformFile = platformFile;
+ mFrameworkEnumValueSupplier = frameworkEnumValueSupplier;
+ mProjectEnumValueSupplier = projectEnumValueSupplier;
+ }
+
+ public BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
+ boolean platformFile) {
+ this(parser, context, platformFile, Bridge::getEnumValues, attrName -> {
+ // get the styleable matching the resolved name
+ RenderResources res = context.getRenderResources();
+ ResourceValue attr = res.getProjectResource(ResourceType.ATTR, attrName);
+ return attr instanceof AttrResourceValue ?
+ ((AttrResourceValue) attr).getAttributeValues() : null;
+ });
}
/*
@@ -59,12 +83,8 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
String ns = mParser.getAttributeNamespace(index);
if (BridgeConstants.NS_RESOURCES.equals(ns)) {
- Integer v = Bridge.getResourceId(ResourceType.ATTR, name);
- if (v != null) {
- return v.intValue();
- }
+ return Bridge.getResourceId(ResourceType.ATTR, name);
- return 0;
}
// this is not an attribute in the android namespace, we query the customviewloader, if
@@ -72,7 +92,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
if (mContext.getLayoutlibCallback().getNamespace().equals(ns)) {
Integer v = mContext.getLayoutlibCallback().getResourceId(ResourceType.ATTR, name);
if (v != null) {
- return v.intValue();
+ return v;
}
}
@@ -121,20 +141,38 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
}
@Override
- public int getAttributeIntValue(String namespace, String attribute,
- int defaultValue) {
+ public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
String value = getAttributeValue(namespace, attribute);
- if (value != null) {
- ResourceValue r = getResourceValue(value);
+ if (value == null) {
+ return defaultValue;
+ }
- if (r != null) {
- value = r.getValue();
- }
+ ResourceValue r = getResourceValue(value);
- return XmlUtils.convertValueToInt(value, defaultValue);
+ if (r != null) {
+ value = r.getValue();
}
- return defaultValue;
+ if (value.charAt(0) == '#') {
+ return ResourceHelper.getColor(value);
+ }
+
+ try {
+ return XmlUtils.convertValueToInt(value, defaultValue);
+ } catch (NumberFormatException e) {
+ // This is probably an enum
+ Map<String, Integer> enumValues = BridgeConstants.NS_RESOURCES.equals(namespace) ?
+ mFrameworkEnumValueSupplier.apply(attribute) :
+ mProjectEnumValueSupplier.apply(attribute);
+
+ Integer enumValue = enumValues != null ? enumValues.get(value) : null;
+ if (enumValue != null) {
+ return enumValue;
+ }
+
+ // We weren't able to find the enum int value
+ throw e;
+ }
}
@Override
@@ -203,21 +241,9 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
@Override
public int getAttributeIntValue(int index, int defaultValue) {
- String value = getAttributeValue(index);
- if (value != null) {
- ResourceValue r = getResourceValue(value);
-
- if (r != null) {
- value = r.getValue();
- }
-
- if (value.charAt(0) == '#') {
- return ResourceHelper.getColor(value);
- }
- return XmlUtils.convertValueToInt(value, defaultValue);
- }
-
- return defaultValue;
+ return getAttributeIntValue(mParser.getAttributeNamespace(index),
+ getAttributeName(index)
+ , defaultValue);
}
@Override
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 5ed5460f8c4f..253ea6f27201 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -340,12 +340,6 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public void setScreenCaptureDisabled(int userId, boolean disabled) {
// TODO Auto-generated method stub
}
@@ -489,16 +483,6 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public Rect getPictureInPictureDefaultBounds(int displayId) {
- return null;
- }
-
- @Override
- public Rect getPictureInPictureMovementBounds(int displayId) {
- return null;
- }
-
- @Override
public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
throws RemoteException {
}
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
index a801cb0606e0..152878bb0fd5 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -57,7 +57,7 @@ public class RenderNode_Delegate {
private String mName;
@LayoutlibDelegate
- /*package*/ static long nCreate(RenderNode thisRenderNode, String name) {
+ /*package*/ static long nCreate(String name) {
RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
renderNodeDelegate.mName = name;
return sManager.addNewDelegate(renderNodeDelegate);
diff --git a/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java
index 06874bd57d2b..8e1f21831a35 100644
--- a/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java
+++ b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java
@@ -16,208 +16,43 @@
package android.view.textservice;
-import com.android.internal.textservice.ISpellCheckerSessionListener;
-import com.android.internal.textservice.ITextServicesManager;
-import com.android.internal.textservice.ITextServicesSessionListener;
-
-import android.content.Context;
import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
import java.util.Locale;
/**
- * System API to the overall text services, which arbitrates interaction between applications
- * and text services. You can retrieve an instance of this interface with
- * {@link Context#getSystemService(String) Context.getSystemService()}.
- *
- * The user can change the current text services in Settings. And also applications can specify
- * the target text services.
- *
- * <h3>Architecture Overview</h3>
- *
- * <p>There are three primary parties involved in the text services
- * framework (TSF) architecture:</p>
- *
- * <ul>
- * <li> The <strong>text services manager</strong> as expressed by this class
- * is the central point of the system that manages interaction between all
- * other parts. It is expressed as the client-side API here which exists
- * in each application context and communicates with a global system service
- * that manages the interaction across all processes.
- * <li> A <strong>text service</strong> implements a particular
- * interaction model allowing the client application to retrieve information of text.
- * The system binds to the current text service that is in use, causing it to be created and run.
- * <li> Multiple <strong>client applications</strong> arbitrate with the text service
- * manager for connections to text services.
- * </ul>
- *
- * <h3>Text services sessions</h3>
- * <ul>
- * <li>The <strong>spell checker session</strong> is one of the text services.
- * {@link android.view.textservice.SpellCheckerSession}</li>
- * </ul>
- *
+ * A stub class of TextServicesManager for Layout-Lib.
*/
public final class TextServicesManager {
- private static final String TAG = TextServicesManager.class.getSimpleName();
- private static final boolean DBG = false;
-
- private static TextServicesManager sInstance;
-
- private final ITextServicesManager mService;
-
- private TextServicesManager() {
- mService = new FakeTextServicesManager();
- }
+ private static final TextServicesManager sInstance = new TextServicesManager();
+ private static final SpellCheckerInfo[] EMPTY_SPELL_CHECKER_INFO = new SpellCheckerInfo[0];
/**
* Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
* @hide
*/
public static TextServicesManager getInstance() {
- synchronized (TextServicesManager.class) {
- if (sInstance == null) {
- sInstance = new TextServicesManager();
- }
- return sInstance;
- }
- }
-
- /**
- * Returns the language component of a given locale string.
- */
- private static String parseLanguageFromLocaleString(String locale) {
- final int idx = locale.indexOf('_');
- if (idx < 0) {
- return locale;
- } else {
- return locale.substring(0, idx);
- }
+ return sInstance;
}
- /**
- * Get a spell checker session for the specified spell checker
- * @param locale the locale for the spell checker. If {@code locale} is null and
- * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be
- * returned. If {@code locale} is not null and referToSpellCheckerLanguageSettings is true,
- * the locale specified in Settings will be returned only when it is same as {@code locale}.
- * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@code locale} is
- * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
- * selected.
- * @param listener a spell checker session lister for getting results from a spell checker.
- * @param referToSpellCheckerLanguageSettings if true, the session for one of enabled
- * languages in settings will be returned.
- * @return the spell checker session of the spell checker
- */
public SpellCheckerSession newSpellCheckerSession(Bundle bundle, Locale locale,
SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) {
- if (listener == null) {
- throw new NullPointerException();
- }
- if (!referToSpellCheckerLanguageSettings && locale == null) {
- throw new IllegalArgumentException("Locale should not be null if you don't refer"
- + " settings.");
- }
-
- if (referToSpellCheckerLanguageSettings && !isSpellCheckerEnabled()) {
- return null;
- }
-
- final SpellCheckerInfo sci;
- try {
- sci = mService.getCurrentSpellChecker(null);
- } catch (RemoteException e) {
- return null;
- }
- if (sci == null) {
- return null;
- }
- SpellCheckerSubtype subtypeInUse = null;
- if (referToSpellCheckerLanguageSettings) {
- subtypeInUse = getCurrentSpellCheckerSubtype(true);
- if (subtypeInUse == null) {
- return null;
- }
- if (locale != null) {
- final String subtypeLocale = subtypeInUse.getLocale();
- final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale);
- if (subtypeLanguage.length() < 2 || !locale.getLanguage().equals(subtypeLanguage)) {
- return null;
- }
- }
- } else {
- final String localeStr = locale.toString();
- for (int i = 0; i < sci.getSubtypeCount(); ++i) {
- final SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
- final String tempSubtypeLocale = subtype.getLocale();
- final String tempSubtypeLanguage = parseLanguageFromLocaleString(tempSubtypeLocale);
- if (tempSubtypeLocale.equals(localeStr)) {
- subtypeInUse = subtype;
- break;
- } else if (tempSubtypeLanguage.length() >= 2 &&
- locale.getLanguage().equals(tempSubtypeLanguage)) {
- subtypeInUse = subtype;
- }
- }
- }
- if (subtypeInUse == null) {
- return null;
- }
- final SpellCheckerSession session = new SpellCheckerSession(
- sci, mService, listener, subtypeInUse);
- try {
- mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(),
- session.getTextServicesSessionListener(),
- session.getSpellCheckerSessionListener(), bundle);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return session;
+ return null;
}
/**
* @hide
*/
public SpellCheckerInfo[] getEnabledSpellCheckers() {
- try {
- final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers();
- if (DBG) {
- Log.d(TAG, "getEnabledSpellCheckers: " + (retval != null ? retval.length : "null"));
- }
- return retval;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return EMPTY_SPELL_CHECKER_INFO;
}
/**
* @hide
*/
public SpellCheckerInfo getCurrentSpellChecker() {
- try {
- // Passing null as a locale for ICS
- return mService.getCurrentSpellChecker(null);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- public void setCurrentSpellChecker(SpellCheckerInfo sci) {
- try {
- if (sci == null) {
- throw new NullPointerException("SpellCheckerInfo is null.");
- }
- mService.setCurrentSpellChecker(null, sci.getId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return null;
}
/**
@@ -225,118 +60,13 @@ public final class TextServicesManager {
*/
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
boolean allowImplicitlySelectedSubtype) {
- try {
- // Passing null as a locale until we support multiple enabled spell checker subtypes.
- return mService.getCurrentSpellCheckerSubtype(null, allowImplicitlySelectedSubtype);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- public void setSpellCheckerSubtype(SpellCheckerSubtype subtype) {
- try {
- final int hashCode;
- if (subtype == null) {
- hashCode = 0;
- } else {
- hashCode = subtype.hashCode();
- }
- mService.setCurrentSpellCheckerSubtype(null, hashCode);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- public void setSpellCheckerEnabled(boolean enabled) {
- try {
- mService.setSpellCheckerEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return null;
}
/**
* @hide
*/
public boolean isSpellCheckerEnabled() {
- try {
- return mService.isSpellCheckerEnabled();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private static class FakeTextServicesManager implements ITextServicesManager {
-
- @Override
- public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
- throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
- throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void getSpellCheckerService(String arg0, String arg1,
- ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
- throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean isSpellCheckerEnabled() throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public IBinder asBinder() {
- // TODO Auto-generated method stub
- return null;
- }
-
+ return false;
}
-} \ No newline at end of file
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 68680d5d8d9c..c9b04dcf8ed4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -111,7 +111,7 @@ import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_AP
* Custom implementation of Context/Activity to handle non compiled resources.
*/
@SuppressWarnings("deprecation") // For use of Pair.
-public final class BridgeContext extends Context {
+public class BridgeContext extends Context {
private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
private static final Map<String, ResourceValue> FRAMEWORK_PATCHED_VALUES = new HashMap<>(2);
@@ -1325,6 +1325,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public Context createContextForSplit(String splitName) {
+ // pass
+ return null;
+ }
+
+ @Override
public String[] databaseList() {
// pass
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index d3ec9e271ba4..00799a1c6bb6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -24,7 +24,7 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -145,6 +145,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public boolean isPermissionReviewModeEnabled() {
+ return false;
+ }
+
+ @Override
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags)
throws NameNotFoundException {
return null;
@@ -295,32 +300,32 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public List<EphemeralApplicationInfo> getEphemeralApplications() {
+ public List<InstantAppInfo> getInstantApps() {
return null;
}
@Override
- public Drawable getEphemeralApplicationIcon(String packageName) {
+ public Drawable getInstantAppIcon(String packageName) {
throw new UnsupportedOperationException();
}
@Override
- public byte[] getEphemeralCookie() {
+ public byte[] getInstantAppCookie() {
return new byte[0];
}
@Override
- public boolean isEphemeralApplication() {
+ public boolean isInstantApp() {
return false;
}
@Override
- public int getEphemeralCookieMaxSizeBytes() {
+ public int getInstantAppCookieMaxSize() {
return 0;
}
@Override
- public boolean setEphemeralCookie(@NonNull byte[] cookie) {
+ public boolean setInstantAppCookie(@NonNull byte[] cookie) {
return false;
}
@@ -891,4 +896,9 @@ public class BridgePackageManager extends PackageManager {
public int getInstallReason(String packageName, UserHandle user) {
return INSTALL_REASON_UNKNOWN;
}
+
+ @Override
+ public boolean canRequestPackageInstalls() {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index a83f10087649..a51ad2ec22ee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -108,6 +108,10 @@ public final class BridgeWindow implements IWindow {
}
@Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {
+ }
+
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 33d55dea6f79..1b65eee729e6 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -31,7 +31,8 @@ LOCAL_JAVA_LIBRARIES := layoutlib \
tools-common-prebuilt \
sdk-common \
junit-host \
- guavalib
+ guavalib \
+ mockito-host
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 199ea60e0e24..affc31ee48e2 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index 89ff5db8f40b..a53dcbae327b 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
index 1f4405d49ffc..88fa9ddbd349 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
index 26aed6a7ed7c..e33f92d7e1bd 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
index aaf1514ddc24..915868c59f11 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
index c3bd70837ff1..ee72a6fe27e8 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
index 0c1621544870..781d617cc975 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
index 81755cec9b15..5b64d336235f 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
index 868cd51f8bb5..a8567b3ef023 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
index 601f711f32d3..5ae95ea34ad4 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
index 0b8f1a96791c..b2b6a970c29f 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
index 87bd5020bcd4..cf1a769f0550 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
index eb431b0280da..e0abcf412844 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
index 4e448c8f2efc..3d0fbd606188 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
index b75671990ce6..86b00415c3ec 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 466eca8d1721..7bbae09c13d3 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
index 940fe5bc44ba..e9dca69281be 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java b/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java
new file mode 100644
index 000000000000..2fcec8e98585
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.util;
+
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import org.junit.Test;
+import org.xmlpull.v1.XmlPullParser;
+
+import com.google.common.collect.ImmutableMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BridgeXmlPullAttributesTest {
+ @Test
+ public void testGetAttributeIntValueForEnums() {
+ RenderResources renderResources = new RenderResources();
+
+ XmlPullParser parser = mock(XmlPullParser.class);
+ when(parser.getAttributeValue(BridgeConstants.NS_RESOURCES, "layout_width"))
+ .thenReturn("match_parent");
+ when(parser.getAttributeName(0)).thenReturn("layout_width");
+ when(parser.getAttributeNamespace(0)).thenReturn(BridgeConstants.NS_RESOURCES);
+ // Return every value twice since there is one test using name and other using index
+ when(parser.getAttributeValue("http://custom", "my_custom_attr"))
+ .thenReturn("a", "a", "b", "b", "invalid", "invalid");
+ when(parser.getAttributeName(1)).thenReturn("my_custom_attr");
+ when(parser.getAttributeNamespace(1)).thenReturn("http://custom");
+
+ BridgeContext context = mock(BridgeContext.class);
+ when(context.getRenderResources()).thenReturn(renderResources);
+
+ BridgeXmlPullAttributes attributes = new BridgeXmlPullAttributes(
+ parser,
+ context,
+ false,
+ attrName -> {
+ if ("layout_width".equals(attrName)) {
+ return ImmutableMap.of(
+ "match_parent", 123);
+ }
+ return ImmutableMap.of();
+ },
+ attrName -> {
+ if ("my_custom_attr".equals(attrName)) {
+ return ImmutableMap.of(
+ "a", 1,
+ "b", 2
+ );
+ }
+ return ImmutableMap.of();
+ });
+
+ // Test a framework defined enum attribute
+ assertEquals(123, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
+ "layout_width", 500));
+ assertEquals(123, attributes.getAttributeIntValue(0, 500));
+ // Test non existing attribute (it should return the default value)
+ assertEquals(500, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
+ "layout_height", 500));
+ assertEquals(500, attributes.getAttributeIntValue(2, 500));
+
+ // Test project defined enum attribute
+ assertEquals(1, attributes.getAttributeIntValue("http://custom",
+ "my_custom_attr", 500));
+ assertEquals(1, attributes.getAttributeIntValue(1, 500));
+ assertEquals(2, attributes.getAttributeIntValue("http://custom",
+ "my_custom_attr", 500));
+ assertEquals(2, attributes.getAttributeIntValue(1, 500));
+ // Test an invalid enum
+ boolean exception = false;
+ try {
+ attributes.getAttributeIntValue("http://custom", "my_custom_attr", 500);
+ } catch(NumberFormatException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+ exception = false;
+ try {
+ attributes.getAttributeIntValue(1, 500);
+ } catch(NumberFormatException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+
+ // Test non existing project attribute
+ assertEquals(500, attributes.getAttributeIntValue("http://custom",
+ "my_other_attr", 500));
+ }
+
+} \ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
index 18c662915a6d..cdf56334cbc5 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
@@ -54,7 +54,7 @@ public class ImageUtils {
*/
private static final boolean FAIL_ON_MISSING_THUMBNAIL = true;
- private static final int THUMBNAIL_SIZE = 250;
+ private static final int THUMBNAIL_SIZE = 1000;
private static final double MAX_PERCENT_DIFFERENCE = 0.3;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index a2f8372d6eb8..bed5806aadad 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -36,6 +36,7 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
/**
* Class that generates a new JAR from a list of classes, some of which are to be kept as-is
@@ -78,6 +79,8 @@ public class AsmGenerator {
private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
/** A map { FQCN => set { field names } } which should be promoted to public visibility */
private final Map<String, Set<String>> mPromotedFields;
+ /** A list of classes to be promoted to public visibility */
+ private final Set<String> mPromotedClasses;
/**
* Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -179,6 +182,9 @@ public class AsmGenerator {
addToMap(createInfo.getPromotedFields(), mPromotedFields);
mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
+
+ mPromotedClasses =
+ Arrays.stream(createInfo.getPromotedClasses()).collect(Collectors.toSet());
}
/**
@@ -400,7 +406,11 @@ public class AsmGenerator {
if (promoteFields != null && !promoteFields.isEmpty()) {
cv = new PromoteFieldClassAdapter(cv, promoteFields);
}
+ if (!mPromotedClasses.isEmpty()) {
+ cv = new PromoteClassClassAdapter(cv, mPromotedClasses);
+ }
cr.accept(cv, 0);
+
return cw.toByteArray();
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 7ba86fdc5c30..94302d328313 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -113,6 +113,11 @@ public final class CreateInfo implements ICreateInfo {
}
@Override
+ public String[] getPromotedClasses() {
+ return PROMOTED_CLASSES;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return INJECTED_METHODS;
}
@@ -339,7 +344,15 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] PROMOTED_FIELDS = new String[] {
"android.graphics.drawable.VectorDrawable#mVectorState",
- "android.view.Choreographer#mLastFrameTimeNanos"
+ "android.view.Choreographer#mLastFrameTimeNanos",
+ "android.graphics.FontFamily#mBuilderPtr"
+ };
+
+ /**
+ * List of classes to be promoted to public visibility. Prefer using PROMOTED_FIELDS to this
+ * if possible.
+ */
+ private final static String[] PROMOTED_CLASSES = new String[] {
};
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 535a9a8c0b77..48abde4517e6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -78,6 +78,11 @@ public interface ICreateInfo {
String[] getPromotedFields();
/**
+ * Returns a list of classes to be promoted to public visibility.
+ */
+ String[] getPromotedClasses();
+
+ /**
* Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
* called to inject methods into a class.
* Can be empty but must not be null.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteClassClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteClassClassAdapter.java
new file mode 100644
index 000000000000..99e3089115d6
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteClassClassAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+
+/**
+ * Promotes given classes to public visibility.
+ */
+public class PromoteClassClassAdapter extends ClassVisitor {
+
+ private final Set<String> mClassNames;
+ private static final int CLEAR_PRIVATE_MASK = ~(ACC_PRIVATE | ACC_PROTECTED);
+
+ public PromoteClassClassAdapter(ClassVisitor cv, Set<String> classNames) {
+ super(Main.ASM_VERSION, cv);
+ mClassNames =
+ classNames.stream().map(name -> name.replace(".", "/")).collect(Collectors.toSet());
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ if (mClassNames.contains(name)) {
+ if ((access & ACC_PUBLIC) == 0) {
+ access = (access & CLEAR_PRIVATE_MASK) | ACC_PUBLIC;
+ }
+ }
+
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ if (mClassNames.contains(name)) {
+ if ((access & ACC_PUBLIC) == 0) {
+ access = (access & CLEAR_PRIVATE_MASK) | ACC_PUBLIC;
+ }
+ }
+
+ super.visitInnerClass(name, outerName, innerName, access);
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
index 05af0337a397..ba778602546d 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
@@ -31,7 +31,7 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
public class PromoteFieldClassAdapter extends ClassVisitor {
private final Set<String> mFieldNames;
- private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED);
+ private static final int CLEAR_PRIVATE_MASK = ~(ACC_PRIVATE | ACC_PROTECTED);
public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) {
super(Main.ASM_VERSION, cv);
@@ -43,7 +43,7 @@ public class PromoteFieldClassAdapter extends ClassVisitor {
Object value) {
if (mFieldNames.contains(name)) {
if ((access & ACC_PUBLIC) == 0) {
- access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC;
+ access = (access & CLEAR_PRIVATE_MASK) | ACC_PUBLIC;
}
}
return super.visitField(access, name, desc, signature, value);
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 0560d8aca1bd..4d5d5d2c4a6e 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -137,6 +137,11 @@ public class AsmGeneratorTest {
}
@Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.emptyMap();
}
@@ -211,6 +216,11 @@ public class AsmGeneratorTest {
}
@Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.emptyMap();
}
@@ -293,6 +303,11 @@ public class AsmGeneratorTest {
}
@Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.emptyMap();
}
@@ -370,6 +385,11 @@ public class AsmGeneratorTest {
}
@Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.singletonMap("mock_android.util.EmptyArray",
InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java
new file mode 100644
index 000000000000..eeb0b10c1e2b
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.tools.layoutlib.create;
+
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringJoiner;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * {@link ClassVisitor} that logs all the calls to the different visit methods so they can be later
+ * inspected.
+ */
+class LoggingClassVisitor extends ClassVisitor {
+ List<String> mLog = new LinkedList<String>();
+
+ public LoggingClassVisitor() {
+ super(Main.ASM_VERSION);
+ }
+
+ public LoggingClassVisitor(ClassVisitor cv) {
+ super(Main.ASM_VERSION, cv);
+ }
+
+ private static String formatAccess(int access) {
+ StringJoiner modifiers = new StringJoiner(",");
+
+ if ((access & Opcodes.ACC_PUBLIC) != 0) {
+ modifiers.add("public");
+ }
+ if ((access & Opcodes.ACC_PRIVATE) != 0) {
+ modifiers.add("private");
+ }
+ if ((access & Opcodes.ACC_PROTECTED) != 0) {
+ modifiers.add("protected");
+ }
+ if ((access & Opcodes.ACC_STATIC) != 0) {
+ modifiers.add("static");
+ }
+ if ((access & Opcodes.ACC_FINAL) != 0) {
+ modifiers.add("static");
+ }
+
+ return "[" + modifiers.toString() + "]";
+ }
+
+ private void log(String method, String format, Object...args) {
+ mLog.add(
+ String.format("[%s] - %s", method, String.format(format, (Object[]) args))
+ );
+ }
+
+ @Override
+ public void visitOuterClass(String owner, String name, String desc) {
+ log(
+ "visitOuterClass",
+ "owner=%s, name=%s, desc=%s",
+ owner, name, desc
+ );
+
+ super.visitOuterClass(owner, name, desc);
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ log(
+ "visitInnerClass",
+ "name=%s, outerName=%s, innerName=%s, access=%s",
+ name, outerName, innerName, formatAccess(access)
+ );
+
+ super.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ log(
+ "visit",
+ "version=%d, access=%s, name=%s, signature=%s, superName=%s, interfaces=%s",
+ version, formatAccess(access), name, signature, superName, Arrays.toString(interfaces)
+ );
+
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+}
+
+class PackageProtectedClass {}
+
+public class PromoteClassClassAdapterTest {
+ private static class PrivateClass {}
+ private static class ClassWithPrivateInnerClass {
+ private class InnerPrivateClass {}
+ }
+
+ @Test
+ public void testInnerClassPromotion() throws IOException {
+ ClassReader reader = new ClassReader(PrivateClass.class.getName());
+ LoggingClassVisitor log = new LoggingClassVisitor();
+
+ PromoteClassClassAdapter adapter = new PromoteClassClassAdapter(log, new HashSet<String>() {
+ {
+ add("com.android.tools.layoutlib.create.PromoteClassClassAdapterTest$PrivateClass");
+ add("com.android.tools.layoutlib.create" +
+ ".PromoteClassClassAdapterTest$ClassWithPrivateInnerClass$InnerPrivateClass");
+ }
+ });
+ reader.accept(adapter, 0);
+ assertTrue(log.mLog.contains(
+ "[visitInnerClass] - " +
+ "name=com/android/tools/layoutlib/create" +
+ "/PromoteClassClassAdapterTest$PrivateClass, " +
+ "outerName=com/android/tools/layoutlib/create" +
+ "/PromoteClassClassAdapterTest, innerName=PrivateClass, access=[public,static]"));
+
+ // Test inner of inner class
+ log.mLog.clear();
+ reader = new ClassReader(ClassWithPrivateInnerClass.class.getName());
+ reader.accept(adapter, 0);
+
+ assertTrue(log.mLog.contains("[visitInnerClass] - " +
+ "name=com/android/tools/layoutlib/create" +
+ "/PromoteClassClassAdapterTest$ClassWithPrivateInnerClass$InnerPrivateClass, " +
+ "outerName=com/android/tools/layoutlib/create" +
+ "/PromoteClassClassAdapterTest$ClassWithPrivateInnerClass, " +
+ "innerName=InnerPrivateClass, access=[public]"));
+
+ }
+
+ @Test
+ public void testProtectedClassPromotion() throws IOException {
+ ClassReader reader = new ClassReader(PackageProtectedClass.class.getName());
+ LoggingClassVisitor log = new LoggingClassVisitor();
+
+ PromoteClassClassAdapter adapter = new PromoteClassClassAdapter(log, new HashSet<String>() {
+ {
+ add("com.android.tools.layoutlib.create.PackageProtectedClass");
+ }
+ });
+
+ reader.accept(adapter, 0);
+ assertTrue(log.mLog.contains("[visit] - version=52, access=[public], " +
+ "name=com/android/tools/layoutlib/create/PackageProtectedClass, signature=null, " +
+ "superName=java/lang/Object, interfaces=[]"));
+
+ }
+} \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 8cf7a24efb0a..dbf8cc1674b2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -373,6 +373,12 @@ public class WifiConfiguration implements Parcelable {
public String providerFriendlyName;
/**
+ * Flag indicating if this network is provided by a home Passpoint provider or a roaming
+ * Passpoint provider.
+ */
+ public boolean isHomeProviderNetwork;
+
+ /**
* Roaming Consortium Id list for passpoint credential; identifies a set of networks where
* passpoint credential will be considered valid
*/
@@ -1891,6 +1897,7 @@ public class WifiConfiguration implements Parcelable {
FQDN = source.FQDN;
roamingConsortiumIds = source.roamingConsortiumIds.clone();
providerFriendlyName = source.providerFriendlyName;
+ isHomeProviderNetwork = source.isHomeProviderNetwork;
preSharedKey = source.preSharedKey;
mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
@@ -1971,6 +1978,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(apChannel);
dest.writeString(FQDN);
dest.writeString(providerFriendlyName);
+ dest.writeInt(isHomeProviderNetwork ? 1 : 0);
dest.writeInt(roamingConsortiumIds.length);
for (long roamingConsortiumId : roamingConsortiumIds) {
dest.writeLong(roamingConsortiumId);
@@ -2036,6 +2044,7 @@ public class WifiConfiguration implements Parcelable {
config.apChannel = in.readInt();
config.FQDN = in.readString();
config.providerFriendlyName = in.readString();
+ config.isHomeProviderNetwork = in.readInt() != 0;
int numRoamingConsortiumIds = in.readInt();
config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
for (int i = 0; i < numRoamingConsortiumIds; i++) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index e410a9cf917e..0bfb95581e60 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -142,7 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable {
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
- private X509Certificate mClientCertificate;
+ private X509Certificate[] mClientCertificateChain;
private int mEapMethod = Eap.NONE;
private int mPhase2Method = Phase2.NONE;
@@ -161,9 +161,19 @@ public class WifiEnterpriseConfig implements Parcelable {
for (String key : source.mFields.keySet()) {
mFields.put(key, source.mFields.get(key));
}
- mCaCerts = source.mCaCerts;
+ if (source.mCaCerts != null) {
+ mCaCerts = Arrays.copyOf(source.mCaCerts, source.mCaCerts.length);
+ } else {
+ mCaCerts = null;
+ }
mClientPrivateKey = source.mClientPrivateKey;
- mClientCertificate = source.mClientCertificate;
+ if (source.mClientCertificateChain != null) {
+ mClientCertificateChain = Arrays.copyOf(
+ source.mClientCertificateChain,
+ source.mClientCertificateChain.length);
+ } else {
+ mClientCertificateChain = null;
+ }
mEapMethod = source.mEapMethod;
mPhase2Method = source.mPhase2Method;
}
@@ -185,7 +195,7 @@ public class WifiEnterpriseConfig implements Parcelable {
dest.writeInt(mPhase2Method);
ParcelUtil.writeCertificates(dest, mCaCerts);
ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
- ParcelUtil.writeCertificate(dest, mClientCertificate);
+ ParcelUtil.writeCertificates(dest, mClientCertificateChain);
}
public static final Creator<WifiEnterpriseConfig> CREATOR =
@@ -204,7 +214,7 @@ public class WifiEnterpriseConfig implements Parcelable {
enterpriseConfig.mPhase2Method = in.readInt();
enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
- enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in);
+ enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
return enterpriseConfig;
}
@@ -742,10 +752,54 @@ public class WifiEnterpriseConfig implements Parcelable {
* @throws IllegalArgumentException for an invalid key or certificate.
*/
public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
+ X509Certificate[] clientCertificates = null;
if (clientCertificate != null) {
- if (clientCertificate.getBasicConstraints() != -1) {
- throw new IllegalArgumentException("Cannot be a CA certificate");
+ clientCertificates = new X509Certificate[] {clientCertificate};
+ }
+ setClientKeyEntryWithCertificateChain(privateKey, clientCertificates);
+ }
+
+ /**
+ * Specify a private key and client certificate chain for client authorization.
+ *
+ * <p>A default name is automatically assigned to the key entry and used
+ * with this configuration. The framework takes care of installing the
+ * key entry when the config is saved and removing the key entry when
+ * the config is removed.
+
+ * @param privateKey
+ * @param clientCertificateChain
+ * @throws IllegalArgumentException for an invalid key or certificate.
+ */
+ public void setClientKeyEntryWithCertificateChain(PrivateKey privateKey,
+ X509Certificate[] clientCertificateChain) {
+ X509Certificate[] newCerts = null;
+ if (clientCertificateChain != null && clientCertificateChain.length > 0) {
+ // We validate that this is a well formed chain that starts
+ // with an end-certificate and is followed by CA certificates.
+ // We don't validate that each following certificate verifies
+ // the previous. https://en.wikipedia.org/wiki/Chain_of_trust
+ //
+ // Basic constraints is an X.509 extension type that defines
+ // whether a given certificate is allowed to sign additional
+ // certificates and what path length restrictions may exist.
+ // We use this to judge whether the certificate is an end
+ // certificate or a CA certificate.
+ // https://cryptography.io/en/latest/x509/reference/
+ if (clientCertificateChain[0].getBasicConstraints() != -1) {
+ throw new IllegalArgumentException(
+ "First certificate in the chain must be a client end certificate");
+ }
+
+ for (int i = 1; i < clientCertificateChain.length; i++) {
+ if (clientCertificateChain[i].getBasicConstraints() == -1) {
+ throw new IllegalArgumentException(
+ "All certificates following the first must be CA certificates");
+ }
}
+ newCerts = Arrays.copyOf(clientCertificateChain,
+ clientCertificateChain.length);
+
if (privateKey == null) {
throw new IllegalArgumentException("Client cert without a private key");
}
@@ -755,7 +809,7 @@ public class WifiEnterpriseConfig implements Parcelable {
}
mClientPrivateKey = privateKey;
- mClientCertificate = clientCertificate;
+ mClientCertificateChain = newCerts;
}
/**
@@ -764,7 +818,24 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return X.509 client certificate
*/
public X509Certificate getClientCertificate() {
- return mClientCertificate;
+ if (mClientCertificateChain != null && mClientCertificateChain.length > 0) {
+ return mClientCertificateChain[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the complete client certificate chain
+ *
+ * @return X.509 client certificates
+ */
+ @Nullable public X509Certificate[] getClientCertificateChain() {
+ if (mClientCertificateChain != null && mClientCertificateChain.length > 0) {
+ return mClientCertificateChain;
+ } else {
+ return null;
+ }
}
/**
@@ -772,7 +843,7 @@ public class WifiEnterpriseConfig implements Parcelable {
*/
public void resetClientKeyEntry() {
mClientPrivateKey = null;
- mClientCertificate = null;
+ mClientCertificateChain = null;
}
/**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 3b6e76f76677..3fb8ef3e2de3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -120,11 +120,7 @@ public class WifiManager {
public static final String PASSPOINT_ICON_RECEIVED_ACTION =
"android.net.wifi.PASSPOINT_ICON_RECEIVED";
/** @hide */
- public static final String EXTRA_PASSPOINT_ICON_BSSID = "bssid";
- /** @hide */
public static final String EXTRA_PASSPOINT_ICON_FILE = "file";
- /** @hide */
- public static final String EXTRA_PASSPOINT_ICON_DATA = "icon";
/**
* Broadcast intent action indicating that the a Passpoint release
@@ -159,6 +155,127 @@ public class WifiManager {
public static final String EXTRA_PASSPOINT_WNM_DELAY = "delay";
/**
+ * Broadcast intent action indicating that a Passpoint provider icon has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_ICON =
+ "android.net.wifi.action.PASSPOINT_ICON";
+ /**
+ * BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_ICON_BSSID =
+ "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ /**
+ * Filename of the icon.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_ICON_FILENAME =
+ "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ /**
+ * Binary blob of the icon.
+ *
+ * Type: byte[]
+ */
+ public static final String EXTRA_PASSPOINT_ICON_DATA =
+ "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+
+ /**
+ * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
+ "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ /**
+ * BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID =
+ "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ /**
+ * Raw data of OSU Providers List ANQP element. Refer to Section 4.8 of Hotspot 2.0 Release 2
+ * Technical Specification for the exact data format.
+ *
+ * Type: byte[]
+ */
+ public static final String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA =
+ "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+
+ /**
+ * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
+ "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ /**
+ * The BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ /**
+ * Flag indicating failure at BSS (Basic Service Set) or ESS (Extended Service Set) level.
+ *
+ * Type: boolean
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ /**
+ * Delay in seconds that a device shall wait before attempting re-association to the same BSS
+ * or ESS (as indicated by {@link #EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS}.
+ *
+ * Type: int
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ /**
+ * URL that provides a webpage explaining the deauth reason.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+
+ /**
+ * Broadcast intent action indicating a Passpoint subscription remediation frame has been
+ * received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
+ "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
+ /**
+ * The BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ /**
+ * The protocol supported by the subscription remediation server. The possible values are:
+ * 0 - OMA DM
+ * 1 - SOAP XML SPP
+ *
+ * Type: int
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ /**
+ * URL of the subscription remediation server.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
+
+ /**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
* enabling, disabling, or unknown. One extra provides this state as an int.
* Another extra provides the previous state, if available.
@@ -856,7 +973,6 @@ public class WifiManager {
*
* @param config The Passpoint configuration to be added
* @return true on success
- * @hide
*/
public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
@@ -871,7 +987,6 @@ public class WifiManager {
*
* @param fqdn The FQDN of the passpoint configuration to be removed
* @return true on success
- * @hide
*/
public boolean removePasspointConfiguration(String fqdn) {
try {
@@ -887,7 +1002,6 @@ public class WifiManager {
* An empty list will be returned when no configurations are installed.
*
* @return A list of {@link PasspointConfiguration}
- * @hide
*/
public List<PasspointConfiguration> getPasspointConfigurations() {
try {
@@ -898,10 +1012,10 @@ public class WifiManager {
}
/**
- * Query for a Hotspot 2.0 release 2 OSU icon
+ * Query for a Hotspot 2.0 release 2 OSU icon file.
+ *
* @param bssid The BSSID of the AP
- * @param fileName Icon file name
- * @hide
+ * @param fileName File name of the icon to query
*/
public void queryPasspointIcon(long bssid, String fileName) {
try {
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 36e4717c16e4..04dea1b60abe 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -19,16 +19,16 @@ package android.net.wifi;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.Context;
-import android.os.Handler;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.ScoredNetwork;
+import android.os.Handler;
+import android.os.Process;
import android.util.Log;
-import com.android.internal.util.Preconditions;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -76,7 +76,7 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) {
mContext = context.getApplicationContext();
mListener = listener;
- mNetworkCache = new HashMap<String, ScoredNetwork>();
+ mNetworkCache = new HashMap<>();
}
@Override public final void updateScores(List<ScoredNetwork> networks) {
@@ -244,7 +244,9 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
- writer.println("WifiNetworkScoreCache");
+ String header = String.format("WifiNetworkScoreCache (%s/%d)",
+ mContext.getPackageName(), Process.myUid());
+ writer.println(header);
writer.println(" All score curves:");
for (ScoredNetwork score : mNetworkCache.values()) {
writer.println(" " + score);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 043925edc5f0..a9e38cef97e8 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -706,7 +706,11 @@ public class WifiAwareManager {
attachCallback.onAttachFailed();
break;
case CALLBACK_IDENTITY_CHANGED:
- identityChangedListener.onIdentityChanged((byte[]) msg.obj);
+ if (identityChangedListener == null) {
+ Log.e(TAG, "CALLBACK_IDENTITY_CHANGED: null listener.");
+ } else {
+ identityChangedListener.onIdentityChanged((byte[]) msg.obj);
+ }
break;
case CALLBACK_RANGING_SUCCESS: {
RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
index 96db5d02679e..027b049a68c9 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
@@ -16,7 +16,7 @@
package android.net.wifi.hotspot2;
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -41,11 +41,9 @@ import java.util.Map;
/**
* Utility class for building PasspointConfiguration from an installation file.
- *
- * @hide
*/
-public final class ConfigBuilder {
- private static final String TAG = "ConfigBuilder";
+public final class ConfigParser {
+ private static final String TAG = "ConfigParser";
// Header names.
private static final String CONTENT_TYPE = "Content-Type";
@@ -101,6 +99,10 @@ public final class ConfigBuilder {
public String encodingType = null;
}
+ /**
+ * @hide
+ */
+ public ConfigParser() {}
/**
* Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration}
@@ -133,7 +135,7 @@ public final class ConfigBuilder {
* certificate chain (optional).
* @return {@link PasspointConfiguration}
*/
- public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) {
+ public static PasspointConfiguration parsePasspointConfig(String mimeType, byte[] data) {
// Verify MIME type.
if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) {
Log.e(TAG, "Unexpected MIME type: " + mimeType);
@@ -169,13 +171,13 @@ public final class ConfigBuilder {
throw new IOException("Missing Passpoint Profile");
}
- PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData));
+ PasspointConfiguration config = PpsMoParser.parseMoText(new String(profileData));
if (config == null) {
throw new IOException("Failed to parse Passpoint profile");
}
// Credential is needed for storing the certificates and private client key.
- if (config.credential == null) {
+ if (config.getCredential() == null) {
throw new IOException("Passpoint profile missing credential");
}
@@ -183,7 +185,7 @@ public final class ConfigBuilder {
byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
if (caCertData != null) {
try {
- config.credential.caCertificate = parseCACert(caCertData);
+ config.getCredential().setCaCertificate(parseCACert(caCertData));
} catch (CertificateException e) {
throw new IOException("Failed to parse CA Certificate");
}
@@ -194,9 +196,9 @@ public final class ConfigBuilder {
if (pkcs12Data != null) {
try {
Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data);
- config.credential.clientPrivateKey = clientKey.first;
- config.credential.clientCertificateChain =
- clientKey.second.toArray(new X509Certificate[clientKey.second.size()]);
+ config.getCredential().setClientPrivateKey(clientKey.first);
+ config.getCredential().setClientCertificateChain(
+ clientKey.second.toArray(new X509Certificate[clientKey.second.size()]));
} catch(GeneralSecurityException | IOException e) {
throw new IOException("Failed to parse PCKS12 string");
}
@@ -470,4 +472,4 @@ public final class ConfigBuilder {
}
return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain);
}
-} \ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 643753abf5dc..7b73b4bcc946 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,24 +17,218 @@
package android.net.wifi.hotspot2;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
import android.os.Parcel;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
/**
* Class representing Passpoint configuration. This contains configurations specified in
* PerProviderSubscription (PPS) Management Object (MO) tree.
*
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
* Release 2 Technical Specification.
- *
- * Currently, only HomeSP and Credential subtrees are supported.
- *
- * @hide
*/
public final class PasspointConfiguration implements Parcelable {
- public HomeSP homeSp = null;
- public Credential credential = null;
+ private static final String TAG = "PasspointConfiguration";
+
+ /**
+ * Number of bytes for certificate SHA-256 fingerprint byte array.
+ */
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * Maximum bytes for URL string.
+ */
+ private static final int MAX_URL_BYTES = 1023;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * Configurations under HomeSp subtree.
+ */
+ private HomeSp mHomeSp = null;
+ public void setHomeSp(HomeSp homeSp) { mHomeSp = homeSp; }
+ public HomeSp getHomeSp() { return mHomeSp; }
+
+ /**
+ * Configurations under Credential subtree.
+ */
+ private Credential mCredential = null;
+ public void setCredential(Credential credential) {
+ mCredential = credential;
+ }
+ public Credential getCredential() {
+ return mCredential;
+ }
+
+ /**
+ * Configurations under Policy subtree.
+ */
+ private Policy mPolicy = null;
+ public void setPolicy(Policy policy) {
+ mPolicy = policy;
+ }
+ public Policy getPolicy() {
+ return mPolicy;
+ }
+
+ /**
+ * Meta data for performing subscription update.
+ */
+ private UpdateParameter mSubscriptionUpdate = null;
+ public void setSubscriptionUpdate(UpdateParameter subscriptionUpdate) {
+ mSubscriptionUpdate = subscriptionUpdate;
+ }
+ public UpdateParameter getSubscriptionUpdate() {
+ return mSubscriptionUpdate;
+ }
+
+ /**
+ * List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256
+ * fingerprint of the certificate. The certificates are used for verifying AAA server's
+ * identity during EAP authentication.
+ */
+ private Map<String, byte[]> mTrustRootCertList = null;
+ public void setTrustRootCertList(Map<String, byte[]> trustRootCertList) {
+ mTrustRootCertList = trustRootCertList;
+ }
+ public Map<String, byte[]> getTrustRootCertList() {
+ return mTrustRootCertList;
+ }
+
+ /**
+ * Set by the subscription server, updated every time the configuration is updated by
+ * the subscription server.
+ *
+ * Use Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mUpdateIdentifier = Integer.MIN_VALUE;
+ public void setUpdateIdentifier(int updateIdentifier) {
+ mUpdateIdentifier = updateIdentifier;
+ }
+ public int getUpdateIdentififer() {
+ return mUpdateIdentifier;
+ }
+
+ /**
+ * The priority of the credential.
+ *
+ * Use Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mCredentialPriority = Integer.MIN_VALUE;
+ public void setCredentialPriority(int credentialPriority) {
+ mCredentialPriority = credentialPriority;
+ }
+ public int getCredentialPriority() {
+ return mCredentialPriority;
+ }
+
+ /**
+ * The time this subscription is created. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mSubscriptionCreationTimeInMs = Long.MIN_VALUE;
+ public void setSubscriptionCreationTimeInMs(long subscriptionCreationTimeInMs) {
+ mSubscriptionCreationTimeInMs = subscriptionCreationTimeInMs;
+ }
+ public long getSubscriptionCreationTimeInMs() {
+ return mSubscriptionCreationTimeInMs;
+ }
+
+ /**
+ * The time this subscription will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mSubscriptionExpirationTimeInMs = Long.MIN_VALUE;
+ public void setSubscriptionExpirationTimeInMs(long subscriptionExpirationTimeInMs) {
+ mSubscriptionExpirationTimeInMs = subscriptionExpirationTimeInMs;
+ }
+ public long getSubscriptionExpirationTimeInMs() {
+ return mSubscriptionExpirationTimeInMs;
+ }
+
+ /**
+ * The type of the subscription. This is defined by the provider and the value is provider
+ * specific.
+ */
+ private String mSubscriptionType = null;
+ public void setSubscriptionType(String subscriptionType) {
+ mSubscriptionType = subscriptionType;
+ }
+ public String getSubscriptionType() {
+ return mSubscriptionType;
+ }
+
+ /**
+ * The time period for usage statistics accumulation. A value of zero means that usage
+ * statistics are not accumulated on a periodic basis (e.g., a one-time limit for
+ * “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes.
+ */
+ private long mUsageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE;
+ public void setUsageLimitUsageTimePeriodInMinutes(long usageLimitUsageTimePeriodInMinutes) {
+ mUsageLimitUsageTimePeriodInMinutes = usageLimitUsageTimePeriodInMinutes;
+ }
+ public long getUsageLimitUsageTimePeriodInMinutes() {
+ return mUsageLimitUsageTimePeriodInMinutes;
+ }
+
+ /**
+ * The time at which usage statistic accumulation begins. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUsageLimitStartTimeInMs = Long.MIN_VALUE;
+ public void setUsageLimitStartTimeInMs(long usageLimitStartTimeInMs) {
+ mUsageLimitStartTimeInMs = usageLimitStartTimeInMs;
+ }
+ public long getUsageLimitStartTimeInMs() {
+ return mUsageLimitStartTimeInMs;
+ }
+
+ /**
+ * The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}.
+ * A value of zero indicate unlimited data usage.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUsageLimitDataLimit = Long.MIN_VALUE;
+ public void setUsageLimitDataLimit(long usageLimitDataLimit) {
+ mUsageLimitDataLimit = usageLimitDataLimit;
+ }
+ public long getUsageLimitDataLimit() {
+ return mUsageLimitDataLimit;
+ }
+
+ /**
+ * The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}.
+ * A value of zero indicate unlimited time usage.
+ */
+ private long mUsageLimitTimeLimitInMinutes = Long.MIN_VALUE;
+ public void setUsageLimitTimeLimitInMinutes(long usageLimitTimeLimitInMinutes) {
+ mUsageLimitTimeLimitInMinutes = usageLimitTimeLimitInMinutes;
+ }
+ public long getUsageLimitTimeLimitInMinutes() {
+ return mUsageLimitTimeLimitInMinutes;
+ }
/**
* Constructor for creating PasspointConfiguration with default values.
@@ -47,14 +241,34 @@ public final class PasspointConfiguration implements Parcelable {
* @param source The source to copy from
*/
public PasspointConfiguration(PasspointConfiguration source) {
- if (source != null) {
- if (source.homeSp != null) {
- homeSp = new HomeSP(source.homeSp);
- }
- if (source.credential != null) {
- credential = new Credential(source.credential);
- }
+ if (source == null) {
+ return;
+ }
+
+ if (source.mHomeSp != null) {
+ mHomeSp = new HomeSp(source.mHomeSp);
+ }
+ if (source.mCredential != null) {
+ mCredential = new Credential(source.mCredential);
+ }
+ if (source.mPolicy != null) {
+ mPolicy = new Policy(source.mPolicy);
+ }
+ if (source.mTrustRootCertList != null) {
+ mTrustRootCertList = Collections.unmodifiableMap(source.mTrustRootCertList);
+ }
+ if (source.mSubscriptionUpdate != null) {
+ mSubscriptionUpdate = new UpdateParameter(source.mSubscriptionUpdate);
}
+ mUpdateIdentifier = source.mUpdateIdentifier;
+ mCredentialPriority = source.mCredentialPriority;
+ mSubscriptionCreationTimeInMs = source.mSubscriptionCreationTimeInMs;
+ mSubscriptionExpirationTimeInMs = source.mSubscriptionExpirationTimeInMs;
+ mSubscriptionType = source.mSubscriptionType;
+ mUsageLimitDataLimit = source.mUsageLimitDataLimit;
+ mUsageLimitStartTimeInMs = source.mUsageLimitStartTimeInMs;
+ mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes;
+ mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
}
@Override
@@ -64,8 +278,20 @@ public final class PasspointConfiguration implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(homeSp, flags);
- dest.writeParcelable(credential, flags);
+ dest.writeParcelable(mHomeSp, flags);
+ dest.writeParcelable(mCredential, flags);
+ dest.writeParcelable(mPolicy, flags);
+ dest.writeParcelable(mSubscriptionUpdate, flags);
+ writeTrustRootCerts(dest, mTrustRootCertList);
+ dest.writeInt(mUpdateIdentifier);
+ dest.writeInt(mCredentialPriority);
+ dest.writeLong(mSubscriptionCreationTimeInMs);
+ dest.writeLong(mSubscriptionExpirationTimeInMs);
+ dest.writeString(mSubscriptionType);
+ dest.writeLong(mUsageLimitUsageTimePeriodInMinutes);
+ dest.writeLong(mUsageLimitStartTimeInMs);
+ dest.writeLong(mUsageLimitDataLimit);
+ dest.writeLong(mUsageLimitTimeLimitInMinutes);
}
@Override
@@ -77,9 +303,30 @@ public final class PasspointConfiguration implements Parcelable {
return false;
}
PasspointConfiguration that = (PasspointConfiguration) thatObject;
- return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) &&
- (credential == null ? that.credential == null :
- credential.equals(that.credential));
+ return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp))
+ && (mCredential == null ? that.mCredential == null
+ : mCredential.equals(that.mCredential))
+ && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy))
+ && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null
+ : mSubscriptionUpdate.equals(that.mSubscriptionUpdate))
+ && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList)
+ && mUpdateIdentifier == that.mUpdateIdentifier
+ && mCredentialPriority == that.mCredentialPriority
+ && mSubscriptionCreationTimeInMs == that.mSubscriptionCreationTimeInMs
+ && mSubscriptionExpirationTimeInMs == that.mSubscriptionExpirationTimeInMs
+ && TextUtils.equals(mSubscriptionType, that.mSubscriptionType)
+ && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes
+ && mUsageLimitStartTimeInMs == that.mUsageLimitStartTimeInMs
+ && mUsageLimitDataLimit == that.mUsageLimitDataLimit
+ && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList,
+ mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMs,
+ mSubscriptionExpirationTimeInMs, mUsageLimitUsageTimePeriodInMinutes,
+ mUsageLimitStartTimeInMs, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes);
}
/**
@@ -88,12 +335,43 @@ public final class PasspointConfiguration implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (homeSp == null || !homeSp.validate()) {
+ if (mHomeSp == null || !mHomeSp.validate()) {
+ return false;
+ }
+ if (mCredential == null || !mCredential.validate()) {
+ return false;
+ }
+ if (mPolicy != null && !mPolicy.validate()) {
return false;
}
- if (credential == null || !credential.validate()) {
+ if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) {
return false;
}
+ if (mTrustRootCertList != null) {
+ for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) {
+ String url = entry.getKey();
+ byte[] certFingerprint = entry.getValue();
+ if (TextUtils.isEmpty(url)) {
+ Log.d(TAG, "Empty URL");
+ return false;
+ }
+ if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
+ Log.d(TAG, "URL bytes exceeded the max: "
+ + url.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (certFingerprint == null) {
+ Log.d(TAG, "Fingerprint not specified");
+ return false;
+ }
+ if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) {
+ Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ + certFingerprint.length);
+ return false;
+ }
+ }
+ }
return true;
}
@@ -102,13 +380,90 @@ public final class PasspointConfiguration implements Parcelable {
@Override
public PasspointConfiguration createFromParcel(Parcel in) {
PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = in.readParcelable(null);
- config.credential = in.readParcelable(null);
+ config.setHomeSp(in.readParcelable(null));
+ config.setCredential(in.readParcelable(null));
+ config.setPolicy(in.readParcelable(null));
+ config.setSubscriptionUpdate(in.readParcelable(null));
+ config.setTrustRootCertList(readTrustRootCerts(in));
+ config.setUpdateIdentifier(in.readInt());
+ config.setCredentialPriority(in.readInt());
+ config.setSubscriptionCreationTimeInMs(in.readLong());
+ config.setSubscriptionExpirationTimeInMs(in.readLong());
+ config.setSubscriptionType(in.readString());
+ config.setUsageLimitUsageTimePeriodInMinutes(in.readLong());
+ config.setUsageLimitStartTimeInMs(in.readLong());
+ config.setUsageLimitDataLimit(in.readLong());
+ config.setUsageLimitTimeLimitInMinutes(in.readLong());
return config;
}
+
@Override
public PasspointConfiguration[] newArray(int size) {
return new PasspointConfiguration[size];
}
+
+ /**
+ * Helper function for reading trust root certificate info list from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return The list of trust root certificate URL with the corresponding certificate
+ * fingerprint
+ */
+ private Map<String, byte[]> readTrustRootCerts(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<String, byte[]> trustRootCerts = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String key = in.readString();
+ byte[] value = in.createByteArray();
+ trustRootCerts.put(key, value);
+ }
+ return trustRootCerts;
+ }
};
+
+ /**
+ * Helper function for writing trust root certificate information list.
+ *
+ * @param dest The Parcel to write to
+ * @param trustRootCerts The list of trust root certificate URL with the corresponding
+ * certificate fingerprint
+ */
+ private static void writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts) {
+ if (trustRootCerts == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(trustRootCerts.size());
+ for (Map.Entry<String, byte[]> entry : trustRootCerts.entrySet()) {
+ dest.writeString(entry.getKey());
+ dest.writeByteArray(entry.getValue());
+ }
+ }
+
+ /**
+ * Helper function for comparing two trust root certificate list. Cannot use Map#equals
+ * method since the value type (byte[]) doesn't override equals method.
+ *
+ * @param list1 The first trust root certificate list
+ * @param list2 The second trust root certificate list
+ * @return true if the two list are equal
+ */
+ private static boolean isTrustRootCertListEquals(Map<String, byte[]> list1,
+ Map<String, byte[]> list2) {
+ if (list1 == null || list2 == null) {
+ return list1 == list2;
+ }
+ if (list1.size() != list2.size()) {
+ return false;
+ }
+ for (Map.Entry<String, byte[]> entry : list1.entrySet()) {
+ if (!Arrays.equals(entry.getValue(), list2.get(entry.getKey()))) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
deleted file mode 100644
index 65a49ea6cecc..000000000000
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
+++ /dev/null
@@ -1,786 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.omadm;
-
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.xml.sax.SAXException;
-
-/**
- * Utility class for converting OMA-DM (Open Mobile Alliance's Device Management)
- * PPS-MO (PerProviderSubscription Management Object) XML tree to a
- * {@link PasspointConfiguration} object.
- *
- * Currently this only supports PerProviderSubscription/HomeSP and
- * PerProviderSubscription/Credential subtree for Hotspot 2.0 Release 1 support.
- *
- * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
- * Release 2 Technical Specification.
- *
- * Below is a sample XML string for a Release 1 PPS MO tree:
- *
- * <MgmtTree xmlns="syncml:dmddf1.2">
- * <VerDTD>1.2</VerDTD>
- * <Node>
- * <NodeName>PerProviderSubscription</NodeName>
- * <RTProperties>
- * <Type>
- * <DDFName>urn:wfa:mo:hotspot2dot0­perprovidersubscription:1.0</DDFName>
- * </Type>
- * </RTProperties>
- * <Node>
- * <NodeName>i001</NodeName>
- * <Node>
- * <NodeName>HomeSP</NodeName>
- * <Node>
- * <NodeName>FriendlyName</NodeName>
- * <Value>Century House</Value>
- * </Node>
- * <Node>
- * <NodeName>FQDN</NodeName>
- * <Value>mi6.co.uk</Value>
- * </Node>
- * <Node>
- * <NodeName>RoamingConsortiumOI</NodeName>
- * <Value>112233,445566</Value>
- * </Node>
- * </Node>
- * <Node>
- * <NodeName>Credential</NodeName>
- * <Node>
- * <NodeName>Realm</NodeName>
- * <Value>shaken.stirred.com</Value>
- * </Node>
- * <Node>
- * <NodeName>UsernamePassword</NodeName>
- * <Node>
- * <NodeName>Username</NodeName>
- * <Value>james</Value>
- * </Node>
- * <Node>
- * <NodeName>Password</NodeName>
- * <Value>Ym9uZDAwNw==</Value>
- * </Node>
- * <Node>
- * <NodeName>EAPMethod</NodeName>
- * <Node>
- * <NodeName>EAPType</NodeName>
- * <Value>21</Value>
- * </Node>
- * <Node>
- * <NodeName>InnerMethod</NodeName>
- * <Value>MS-CHAP-V2</Value>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </MgmtTree>
- *
- * @hide
- */
-public final class PPSMOParser {
- private static final String TAG = "PPSMOParser";
-
- /**
- * XML tags expected in the PPS MO (PerProviderSubscription Management Object) XML tree.
- */
- private static final String TAG_MANAGEMENT_TREE = "MgmtTree";
- private static final String TAG_VER_DTD = "VerDTD";
- private static final String TAG_NODE = "Node";
- private static final String TAG_NODE_NAME = "NodeName";
- private static final String TAG_RT_PROPERTIES = "RTProperties";
- private static final String TAG_TYPE = "Type";
- private static final String TAG_DDF_NAME = "DDFName";
- private static final String TAG_VALUE = "Value";
-
- /**
- * Name for PerProviderSubscription node.
- */
- private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
-
- /**
- * Fields under HomeSP subtree.
- */
- private static final String NODE_HOMESP = "HomeSP";
- private static final String NODE_FQDN = "FQDN";
- private static final String NODE_FRIENDLY_NAME = "FriendlyName";
- private static final String NODE_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
-
- /**
- * Fields under Credential subtree.
- */
- private static final String NODE_CREDENTIAL = "Credential";
- private static final String NODE_USERNAME_PASSWORD = "UsernamePassword";
- private static final String NODE_USERNAME = "Username";
- private static final String NODE_PASSWORD = "Password";
- private static final String NODE_EAP_METHOD = "EAPMethod";
- private static final String NODE_EAP_TYPE = "EAPType";
- private static final String NODE_INNER_METHOD = "InnerMethod";
- private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
- private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
- private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256FingerPrint";
- private static final String NODE_REALM = "Realm";
- private static final String NODE_SIM = "SIM";
- private static final String NODE_SIM_IMSI = "IMSI";
-
- /**
- * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
- */
- private static final String PPS_MO_URN =
- "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
-
- /**
- * Exception for generic parsing errors.
- */
- private static class ParsingException extends Exception {
- public ParsingException(String message) {
- super(message);
- }
- }
-
- /**
- * Class representing a node within the PerProviderSubscription tree.
- * This is used to flatten out and eliminate the extra layering in the XMLNode tree,
- * to make the data parsing easier and cleaner.
- *
- * A PPSNode can be an internal or a leaf node, but not both.
- *
- */
- private static abstract class PPSNode {
- private final String mName;
- public PPSNode(String name) {
- mName = name;
- }
-
- /**
- * @return the name of the node
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Applies for internal node only.
- *
- * @return the list of children nodes.
- */
- public abstract List<PPSNode> getChildren();
-
- /**
- * Applies for leaf node only.
- *
- * @return the string value of the node
- */
- public abstract String getValue();
-
- /**
- * @return a flag indicating if this is a leaf or an internal node
- */
- public abstract boolean isLeaf();
- }
-
- /**
- * Class representing a leaf node in a PPS (PerProviderSubscription) tree.
- */
- private static class LeafNode extends PPSNode {
- private final String mValue;
- public LeafNode(String nodeName, String value) {
- super(nodeName);
- mValue = value;
- }
-
- @Override
- public String getValue() {
- return mValue;
- }
-
- @Override
- public List<PPSNode> getChildren() {
- return null;
- }
-
- @Override
- public boolean isLeaf() {
- return true;
- }
- }
-
- /**
- * Class representing an internal node in a PPS (PerProviderSubscription) tree.
- */
- private static class InternalNode extends PPSNode {
- private final List<PPSNode> mChildren;
- public InternalNode(String nodeName, List<PPSNode> children) {
- super(nodeName);
- mChildren = children;
- }
-
- @Override
- public String getValue() {
- return null;
- }
-
- @Override
- public List<PPSNode> getChildren() {
- return mChildren;
- }
-
- @Override
- public boolean isLeaf() {
- return false;
- }
- }
-
- /**
- * Convert a XML string representation of a PPS MO (PerProviderSubscription
- * Management Object) tree to a {@link PasspointConfiguration} object.
- *
- * @param xmlString XML string representation of a PPS MO tree
- * @return {@link PasspointConfiguration} or null
- */
- public static PasspointConfiguration parseMOText(String xmlString) {
- // Convert the XML string to a XML tree.
- XMLParser xmlParser = new XMLParser();
- XMLNode root = null;
- try {
- root = xmlParser.parse(xmlString);
- } catch(IOException | SAXException e) {
- return null;
- }
- if (root == null) {
- return null;
- }
-
- // Verify root node is a "MgmtTree" node.
- if (root.getTag() != TAG_MANAGEMENT_TREE) {
- Log.e(TAG, "Root is not a MgmtTree");
- return null;
- }
-
- String verDtd = null; // Used for detecting duplicate VerDTD element.
- PasspointConfiguration config = null;
- for (XMLNode child : root.getChildren()) {
- switch(child.getTag()) {
- case TAG_VER_DTD:
- if (verDtd != null) {
- Log.e(TAG, "Duplicate VerDTD element");
- return null;
- }
- verDtd = child.getText();
- break;
- case TAG_NODE:
- if (config != null) {
- Log.e(TAG, "Unexpected multiple Node element under MgmtTree");
- return null;
- }
- try {
- config = parsePpsNode(child);
- } catch (ParsingException e) {
- Log.e(TAG, e.getMessage());
- return null;
- }
- break;
- default:
- Log.e(TAG, "Unknown node: " + child.getTag());
- return null;
- }
- }
- return config;
- }
-
- /**
- * Parse a PerProviderSubscription node. Below is the format of the XML tree (with
- * each XML element represent a node in the tree):
- *
- * <Node>
- * <NodeName>PerProviderSubscription</NodeName>
- * <RTProperties>
- * ...
- * </RTPProperties>
- * <Node>
- * ...
- * </Node>
- * </Node>
- *
- * @param node XMLNode that contains PerProviderSubscription node.
- * @return PasspointConfiguration or null
- * @throws ParsingException
- */
- private static PasspointConfiguration parsePpsNode(XMLNode node)
- throws ParsingException {
- PasspointConfiguration config = null;
- String nodeName = null;
- for (XMLNode child : node.getChildren()) {
- switch (child.getTag()) {
- case TAG_NODE_NAME:
- if (nodeName != null) {
- throw new ParsingException("Duplicant NodeName: " + child.getText());
- }
- nodeName = child.getText();
- if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
- throw new ParsingException("Unexpected NodeName: " + nodeName);
- }
- break;
- case TAG_NODE:
- // Only one PerProviderSubscription instance is expected and allowed.
- if (config != null) {
- throw new ParsingException("Multiple PPS instance");
- }
- // Convert the XML tree to a PPS tree.
- PPSNode ppsInstanceRoot = buildPpsNode(child);
- config = parsePpsInstance(ppsInstanceRoot);
- break;
- case TAG_RT_PROPERTIES:
- // Parse and verify URN stored in the RT (Run Time) Properties.
- String urn = parseUrn(child);
- if (!TextUtils.equals(urn, PPS_MO_URN)) {
- throw new ParsingException("Unknown URN: " + urn);
- }
- break;
- default:
- throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
- }
- }
- return config;
- }
-
- /**
- * Parse the URN stored in the RTProperties. Below is the format of the RTPProperties node:
- *
- * <RTProperties>
- * <Type>
- * <DDFName>urn:...</DDFName>
- * </Type>
- * </RTProperties>
- *
- * @param node XMLNode that contains RTProperties node.
- * @return URN String of URN.
- * @throws ParsingException
- */
- private static String parseUrn(XMLNode node) throws ParsingException {
- if (node.getChildren().size() != 1)
- throw new ParsingException("Expect RTPProperties node to only have one child");
-
- XMLNode typeNode = node.getChildren().get(0);
- if (typeNode.getChildren().size() != 1) {
- throw new ParsingException("Expect Type node to only have one child");
- }
- if (!TextUtils.equals(typeNode.getTag(), TAG_TYPE)) {
- throw new ParsingException("Unexpected tag for Type: " + typeNode.getTag());
- }
-
- XMLNode ddfNameNode = typeNode.getChildren().get(0);
- if (!ddfNameNode.getChildren().isEmpty()) {
- throw new ParsingException("Expect DDFName node to have no child");
- }
- if (!TextUtils.equals(ddfNameNode.getTag(), TAG_DDF_NAME)) {
- throw new ParsingException("Unexpected tag for DDFName: " + ddfNameNode.getTag());
- }
-
- return ddfNameNode.getText();
- }
-
- /**
- * Convert a XML tree represented by XMLNode to a PPS (PerProviderSubscription) instance tree
- * represented by PPSNode. This flattens out the XML tree to allow easier and cleaner parsing
- * of the PPS configuration data. Only three types of XML tag are expected: "NodeName",
- * "Node", and "Value".
- *
- * The original XML tree (each XML element represent a node):
- *
- * <Node>
- * <NodeName>root</NodeName>
- * <Node>
- * <NodeName>child1</NodeName>
- * <Value>value1</Value>
- * </Node>
- * <Node>
- * <NodeName>child2</NodeName>
- * <Node>
- * <NodeName>grandchild1</NodeName>
- * ...
- * </Node>
- * </Node>
- * ...
- * </Node>
- *
- * The converted PPS tree:
- *
- * [root] --- [child1, value1]
- * |
- * ---------[child2] --------[grandchild1] --- ...
- *
- * @param node XMLNode pointed to the root of a XML tree
- * @return PPSNode pointing to the root of a PPS tree
- * @throws ParsingException
- */
- private static PPSNode buildPpsNode(XMLNode node) throws ParsingException {
- String nodeName = null;
- String nodeValue = null;
- List<PPSNode> childNodes = new ArrayList<PPSNode>();
- // Names of parsed child nodes, use for detecting multiple child nodes with the same name.
- Set<String> parsedNodes = new HashSet<String>();
-
- for (XMLNode child : node.getChildren()) {
- String tag = child.getTag();
- if (TextUtils.equals(tag, TAG_NODE_NAME)) {
- if (nodeName != null) {
- throw new ParsingException("Duplicate NodeName node");
- }
- nodeName = child.getText();
- } else if (TextUtils.equals(tag, TAG_NODE)) {
- PPSNode ppsNode = buildPpsNode(child);
- if (parsedNodes.contains(ppsNode.getName())) {
- throw new ParsingException("Duplicate node: " + ppsNode.getName());
- }
- parsedNodes.add(ppsNode.getName());
- childNodes.add(ppsNode);
- } else if (TextUtils.equals(tag, TAG_VALUE)) {
- if (nodeValue != null) {
- throw new ParsingException("Duplicate Value node");
- }
- nodeValue = child.getText();
- } else {
- throw new ParsingException("Unknown tag: " + tag);
- }
- }
-
- if (nodeName == null) {
- throw new ParsingException("Invalid node: missing NodeName");
- }
- if (nodeValue == null && childNodes.size() == 0) {
- throw new ParsingException("Invalid node: " + nodeName +
- " missing both value and children");
- }
- if (nodeValue != null && childNodes.size() > 0) {
- throw new ParsingException("Invalid node: " + nodeName +
- " contained both value and children");
- }
-
- if (nodeValue != null) {
- return new LeafNode(nodeName, nodeValue);
- }
- return new InternalNode(nodeName, childNodes);
- }
-
- /**
- * Return the value of a PPSNode. An exception will be thrown if the given node
- * is not a leaf node.
- *
- * @param node PPSNode to retrieve the value from
- * @return String representing the value of the node
- * @throws ParsingException
- */
- private static String getPpsNodeValue(PPSNode node) throws ParsingException {
- if (!node.isLeaf()) {
- throw new ParsingException("Cannot get value from a non-leaf node: " + node.getName());
- }
- return node.getValue();
- }
-
- /**
- * Parse a PPS (PerProviderSubscription) configurations from a PPS tree.
- *
- * @param root PPSNode representing the root of the PPS tree
- * @return PasspointConfiguration
- * @throws ParsingException
- */
- private static PasspointConfiguration parsePpsInstance(PPSNode root)
- throws ParsingException {
- if (root.isLeaf()) {
- throw new ParsingException("Leaf node not expected for PPS instance");
- }
-
- PasspointConfiguration config = new PasspointConfiguration();
- for (PPSNode child : root.getChildren()) {
- switch(child.getName()) {
- case NODE_HOMESP:
- config.homeSp = parseHomeSP(child);
- break;
- case NODE_CREDENTIAL:
- config.credential = parseCredential(child);
- break;
- default:
- throw new ParsingException("Unknown node: " + child.getName());
- }
- }
- return config;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/HomeSP subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP subtree
- * @return HomeSP
- * @throws ParsingException
- */
- private static HomeSP parseHomeSP(PPSNode node) throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
- }
-
- HomeSP homeSp = new HomeSP();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_FQDN:
- homeSp.fqdn = getPpsNodeValue(child);
- break;
- case NODE_FRIENDLY_NAME:
- homeSp.friendlyName = getPpsNodeValue(child);
- break;
- case NODE_ROAMING_CONSORTIUM_OI:
- homeSp.roamingConsortiumOIs =
- parseRoamingConsortiumOI(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under HomeSP: " + child.getName());
- }
- }
- return homeSp;
- }
-
- /**
- * Parse the roaming consortium OI string, which contains a list of OIs separated by ",".
- *
- * @param oiStr string containing list of OIs (Organization Identifiers) separated by ","
- * @return long[]
- * @throws ParsingException
- */
- private static long[] parseRoamingConsortiumOI(String oiStr)
- throws ParsingException {
- String[] oiStrArray = oiStr.split(",");
- long[] oiArray = new long[oiStrArray.length];
- for (int i = 0; i < oiStrArray.length; i++) {
- try {
- oiArray[i] = Long.parseLong(oiStrArray[i], 16);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid OI: " + oiStrArray[i]);
- }
- }
- return oiArray;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/Credential subtree
- * @return Credential
- * @throws ParsingException
- */
- private static Credential parseCredential(PPSNode node) throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
- }
-
- Credential credential = new Credential();
- for (PPSNode child: node.getChildren()) {
- switch (child.getName()) {
- case NODE_USERNAME_PASSWORD:
- credential.userCredential = parseUserCredential(child);
- break;
- case NODE_DIGITAL_CERTIFICATE:
- credential.certCredential = parseCertificateCredential(child);
- break;
- case NODE_REALM:
- credential.realm = getPpsNodeValue(child);
- break;
- case NODE_SIM:
- credential.simCredential = parseSimCredential(child);
- break;
- default:
- throw new ParsingException("Unknown node under Credential: " +
- child.getName());
- }
- }
- return credential;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/UsernamePassword subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/UsernamePassword subtree
- * @return Credential.UserCredential
- * @throws ParsingException
- */
- private static Credential.UserCredential parseUserCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for UsernamePassword");
- }
-
- Credential.UserCredential userCred = new Credential.UserCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_USERNAME:
- userCred.username = getPpsNodeValue(child);
- break;
- case NODE_PASSWORD:
- userCred.password = getPpsNodeValue(child);
- break;
- case NODE_EAP_METHOD:
- parseEAPMethod(child, userCred);
- break;
- default:
- throw new ParsingException("Unknown node under UsernamPassword: " +
- child.getName());
- }
- }
- return userCred;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/UsernamePassword/EAPMethod
- * subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/UsernamePassword/EAPMethod subtree
- * @param userCred UserCredential to be updated with EAP method values.
- * @throws ParsingException
- */
- private static void parseEAPMethod(PPSNode node, Credential.UserCredential userCred)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for EAPMethod");
- }
-
- for (PPSNode child : node.getChildren()) {
- switch(child.getName()) {
- case NODE_EAP_TYPE:
- userCred.eapType = parseInteger(getPpsNodeValue(child));
- break;
- case NODE_INNER_METHOD:
- userCred.nonEapInnerMethod = getPpsNodeValue(child);
- break;
- default:
- throw new ParsingException("Unknown node under EAPMethod: " + child.getName());
- }
- }
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/DigitalCertificate subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/DigitalCertificate subtree
- * @return Credential.CertificateCredential
- * @throws ParsingException
- */
- private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for DigitalCertificate");
- }
-
- Credential.CertificateCredential certCred = new Credential.CertificateCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_CERTIFICATE_TYPE:
- certCred.certType = getPpsNodeValue(child);
- break;
- case NODE_CERT_SHA256_FINGERPRINT:
- certCred.certSha256FingerPrint = parseHexString(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under DigitalCertificate: " +
- child.getName());
- }
- }
- return certCred;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/SIM subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/Credential/SIM
- * subtree
- * @return Credential.SimCredential
- * @throws ParsingException
- */
- private static Credential.SimCredential parseSimCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for SIM");
- }
-
- Credential.SimCredential simCred = new Credential.SimCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_SIM_IMSI:
- simCred.imsi = getPpsNodeValue(child);
- break;
- case NODE_EAP_TYPE:
- simCred.eapType = parseInteger(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under SIM: " + child.getName());
- }
- }
- return simCred;
- }
-
- /**
- * Convert a hex string to a byte array.
- *
- * @param str String containing hex values
- * @return byte[]
- * @throws ParsingException
- */
- private static byte[] parseHexString(String str) throws ParsingException {
- if ((str.length() & 1) == 1) {
- throw new ParsingException("Odd length hex string: " + str.length());
- }
-
- byte[] result = new byte[str.length() / 2];
- for (int i = 0; i < result.length; i++) {
- int index = i * 2;
- try {
- result[i] = (byte) Integer.parseInt(str.substring(index, index + 2), 16);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid hex string: " + str);
- }
- }
- return result;
- }
-
- /**
- * Parse an integer string.
- *
- * @param value String of integer value
- * @return int
- * @throws ParsingException
- */
- private static int parseInteger(String value) throws ParsingException {
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid integer value: " + value);
- }
- }
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
new file mode 100644
index 000000000000..2ffe42859fc8
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
@@ -0,0 +1,1652 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.omadm;
+
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+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 org.xml.sax.SAXException;
+
+/**
+ * Utility class for converting OMA-DM (Open Mobile Alliance's Device Management)
+ * PPS-MO (PerProviderSubscription Management Object) XML tree to a
+ * {@link PasspointConfiguration} object.
+ *
+ * Currently this only supports PerProviderSubscription/HomeSP and
+ * PerProviderSubscription/Credential subtree for Hotspot 2.0 Release 1 support.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ *
+ * Below is a sample XML string for a Release 1 PPS MO tree:
+ *
+ * <MgmtTree xmlns="syncml:dmddf1.2">
+ * <VerDTD>1.2</VerDTD>
+ * <Node>
+ * <NodeName>PerProviderSubscription</NodeName>
+ * <RTProperties>
+ * <Type>
+ * <DDFName>urn:wfa:mo:hotspot2dot0­perprovidersubscription:1.0</DDFName>
+ * </Type>
+ * </RTProperties>
+ * <Node>
+ * <NodeName>i001</NodeName>
+ * <Node>
+ * <NodeName>HomeSP</NodeName>
+ * <Node>
+ * <NodeName>FriendlyName</NodeName>
+ * <Value>Century House</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>FQDN</NodeName>
+ * <Value>mi6.co.uk</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>RoamingConsortiumOI</NodeName>
+ * <Value>112233,445566</Value>
+ * </Node>
+ * </Node>
+ * <Node>
+ * <NodeName>Credential</NodeName>
+ * <Node>
+ * <NodeName>Realm</NodeName>
+ * <Value>shaken.stirred.com</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>UsernamePassword</NodeName>
+ * <Node>
+ * <NodeName>Username</NodeName>
+ * <Value>james</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>Password</NodeName>
+ * <Value>Ym9uZDAwNw==</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>EAPMethod</NodeName>
+ * <Node>
+ * <NodeName>EAPType</NodeName>
+ * <Value>21</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>InnerMethod</NodeName>
+ * <Value>MS-CHAP-V2</Value>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </MgmtTree>
+ */
+public final class PpsMoParser {
+ private static final String TAG = "PpsMoParser";
+
+ /**
+ * XML tags expected in the PPS MO (PerProviderSubscription Management Object) XML tree.
+ */
+ private static final String TAG_MANAGEMENT_TREE = "MgmtTree";
+ private static final String TAG_VER_DTD = "VerDTD";
+ private static final String TAG_NODE = "Node";
+ private static final String TAG_NODE_NAME = "NodeName";
+ private static final String TAG_RT_PROPERTIES = "RTProperties";
+ private static final String TAG_TYPE = "Type";
+ private static final String TAG_DDF_NAME = "DDFName";
+ private static final String TAG_VALUE = "Value";
+
+ /**
+ * Name for PerProviderSubscription node.
+ */
+ private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
+
+ /**
+ * Fields under PerProviderSubscription.
+ */
+ private static final String NODE_UPDATE_IDENTIFIER = "UpdateIdentifier";
+ private static final String NODE_AAA_SERVER_TRUST_ROOT = "AAAServerTrustRoot";
+ private static final String NODE_SUBSCRIPTION_UPDATE = "SubscriptionUpdate";
+ private static final String NODE_SUBSCRIPTION_PARAMETER = "SubscriptionParameter";
+ private static final String NODE_TYPE_OF_SUBSCRIPTION = "TypeOfSubscription";
+ private static final String NODE_USAGE_LIMITS = "UsageLimits";
+ private static final String NODE_DATA_LIMIT = "DataLimit";
+ private static final String NODE_START_DATE = "StartDate";
+ private static final String NODE_TIME_LIMIT = "TimeLimit";
+ private static final String NODE_USAGE_TIME_PERIOD = "UsageTimePeriod";
+ private static final String NODE_CREDENTIAL_PRIORITY = "CredentialPriority";
+ /**
+ * Fields under HomeSP subtree.
+ */
+ private static final String NODE_HOMESP = "HomeSP";
+ private static final String NODE_FQDN = "FQDN";
+ private static final String NODE_FRIENDLY_NAME = "FriendlyName";
+ private static final String NODE_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
+ private static final String NODE_NETWORK_ID = "NetworkID";
+ private static final String NODE_SSID = "SSID";
+ private static final String NODE_HESSID = "HESSID";
+ private static final String NODE_ICON_URL = "IconURL";
+ private static final String NODE_HOME_OI_LIST = "HomeOIList";
+ private static final String NODE_HOME_OI = "HomeOI";
+ private static final String NODE_HOME_OI_REQUIRED = "HomeOIRequired";
+ private static final String NODE_OTHER_HOME_PARTNERS = "OtherHomePartners";
+
+ /**
+ * Fields under Credential subtree.
+ */
+ private static final String NODE_CREDENTIAL = "Credential";
+ private static final String NODE_CREATION_DATE = "CreationDate";
+ private static final String NODE_EXPIRATION_DATE = "ExpirationDate";
+ private static final String NODE_USERNAME_PASSWORD = "UsernamePassword";
+ private static final String NODE_USERNAME = "Username";
+ private static final String NODE_PASSWORD = "Password";
+ private static final String NODE_MACHINE_MANAGED = "MachineManaged";
+ private static final String NODE_SOFT_TOKEN_APP = "SoftTokenApp";
+ private static final String NODE_ABLE_TO_SHARE = "AbleToShare";
+ private static final String NODE_EAP_METHOD = "EAPMethod";
+ private static final String NODE_EAP_TYPE = "EAPType";
+ private static final String NODE_VENDOR_ID = "VendorId";
+ private static final String NODE_VENDOR_TYPE = "VendorType";
+ private static final String NODE_INNER_EAP_TYPE = "InnerEAPType";
+ private static final String NODE_INNER_VENDOR_ID = "InnerVendorID";
+ private static final String NODE_INNER_VENDOR_TYPE = "InnerVendorType";
+ private static final String NODE_INNER_METHOD = "InnerMethod";
+ private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
+ private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
+ private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint";
+ private static final String NODE_REALM = "Realm";
+ private static final String NODE_SIM = "SIM";
+ private static final String NODE_SIM_IMSI = "IMSI";
+ private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus";
+
+ /**
+ * Fields under Policy subtree.
+ */
+ private static final String NODE_POLICY = "Policy";
+ private static final String NODE_PREFERRED_ROAMING_PARTNER_LIST =
+ "PreferredRoamingPartnerList";
+ private static final String NODE_FQDN_MATCH = "FQDN_Match";
+ private static final String NODE_PRIORITY = "Priority";
+ private static final String NODE_COUNTRY = "Country";
+ private static final String NODE_MIN_BACKHAUL_THRESHOLD = "MinBackhaulThreshold";
+ private static final String NODE_NETWORK_TYPE = "NetworkType";
+ private static final String NODE_DOWNLINK_BANDWIDTH = "DLBandwidth";
+ private static final String NODE_UPLINK_BANDWIDTH = "ULBandwidth";
+ private static final String NODE_POLICY_UPDATE = "PolicyUpdate";
+ private static final String NODE_UPDATE_INTERVAL = "UpdateInterval";
+ private static final String NODE_UPDATE_METHOD = "UpdateMethod";
+ private static final String NODE_RESTRICTION = "Restriction";
+ private static final String NODE_URI = "URI";
+ private static final String NODE_TRUST_ROOT = "TrustRoot";
+ private static final String NODE_CERT_URL = "CertURL";
+ private static final String NODE_SP_EXCLUSION_LIST = "SPExclusionList";
+ private static final String NODE_REQUIRED_PROTO_PORT_TUPLE = "RequiredProtoPortTuple";
+ private static final String NODE_IP_PROTOCOL = "IPProtocol";
+ private static final String NODE_PORT_NUMBER = "PortNumber";
+ private static final String NODE_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue";
+ private static final String NODE_OTHER = "Other";
+
+ /**
+ * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
+ */
+ private static final String PPS_MO_URN =
+ "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
+
+ /**
+ * Exception for generic parsing errors.
+ */
+ private static class ParsingException extends Exception {
+ public ParsingException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Class representing a node within the PerProviderSubscription tree.
+ * This is used to flatten out and eliminate the extra layering in the XMLNode tree,
+ * to make the data parsing easier and cleaner.
+ *
+ * A PPSNode can be an internal or a leaf node, but not both.
+ *
+ */
+ private static abstract class PPSNode {
+ private final String mName;
+ public PPSNode(String name) {
+ mName = name;
+ }
+
+ /**
+ * @return the name of the node
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Applies for internal node only.
+ *
+ * @return the list of children nodes.
+ */
+ public abstract List<PPSNode> getChildren();
+
+ /**
+ * Applies for leaf node only.
+ *
+ * @return the string value of the node
+ */
+ public abstract String getValue();
+
+ /**
+ * @return a flag indicating if this is a leaf or an internal node
+ */
+ public abstract boolean isLeaf();
+ }
+
+ /**
+ * Class representing a leaf node in a PPS (PerProviderSubscription) tree.
+ */
+ private static class LeafNode extends PPSNode {
+ private final String mValue;
+ public LeafNode(String nodeName, String value) {
+ super(nodeName);
+ mValue = value;
+ }
+
+ @Override
+ public String getValue() {
+ return mValue;
+ }
+
+ @Override
+ public List<PPSNode> getChildren() {
+ return null;
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return true;
+ }
+ }
+
+ /**
+ * Class representing an internal node in a PPS (PerProviderSubscription) tree.
+ */
+ private static class InternalNode extends PPSNode {
+ private final List<PPSNode> mChildren;
+ public InternalNode(String nodeName, List<PPSNode> children) {
+ super(nodeName);
+ mChildren = children;
+ }
+
+ @Override
+ public String getValue() {
+ return null;
+ }
+
+ @Override
+ public List<PPSNode> getChildren() {
+ return mChildren;
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public PpsMoParser() {}
+
+ /**
+ * Convert a XML string representation of a PPS MO (PerProviderSubscription
+ * Management Object) tree to a {@link PasspointConfiguration} object.
+ *
+ * @param xmlString XML string representation of a PPS MO tree
+ * @return {@link PasspointConfiguration} or null
+ */
+ public static PasspointConfiguration parseMoText(String xmlString) {
+ // Convert the XML string to a XML tree.
+ XMLParser xmlParser = new XMLParser();
+ XMLNode root = null;
+ try {
+ root = xmlParser.parse(xmlString);
+ } catch(IOException | SAXException e) {
+ return null;
+ }
+ if (root == null) {
+ return null;
+ }
+
+ // Verify root node is a "MgmtTree" node.
+ if (root.getTag() != TAG_MANAGEMENT_TREE) {
+ Log.e(TAG, "Root is not a MgmtTree");
+ return null;
+ }
+
+ String verDtd = null; // Used for detecting duplicate VerDTD element.
+ PasspointConfiguration config = null;
+ for (XMLNode child : root.getChildren()) {
+ switch(child.getTag()) {
+ case TAG_VER_DTD:
+ if (verDtd != null) {
+ Log.e(TAG, "Duplicate VerDTD element");
+ return null;
+ }
+ verDtd = child.getText();
+ break;
+ case TAG_NODE:
+ if (config != null) {
+ Log.e(TAG, "Unexpected multiple Node element under MgmtTree");
+ return null;
+ }
+ try {
+ config = parsePpsNode(child);
+ } catch (ParsingException e) {
+ Log.e(TAG, e.getMessage());
+ return null;
+ }
+ break;
+ default:
+ Log.e(TAG, "Unknown node: " + child.getTag());
+ return null;
+ }
+ }
+ return config;
+ }
+
+ /**
+ * Parse a PerProviderSubscription node. Below is the format of the XML tree (with
+ * each XML element represent a node in the tree):
+ *
+ * <Node>
+ * <NodeName>PerProviderSubscription</NodeName>
+ * <RTProperties>
+ * ...
+ * </RTPProperties>
+ * <Node>
+ * <NodeName>UpdateIdentifier</NodeName>
+ * <Value>...</Value>
+ * </Node>
+ * <Node>
+ * ...
+ * </Node>
+ * </Node>
+ *
+ * @param node XMLNode that contains PerProviderSubscription node.
+ * @return PasspointConfiguration or null
+ * @throws ParsingException
+ */
+ private static PasspointConfiguration parsePpsNode(XMLNode node)
+ throws ParsingException {
+ PasspointConfiguration config = null;
+ String nodeName = null;
+ int updateIdentifier = Integer.MIN_VALUE;
+ for (XMLNode child : node.getChildren()) {
+ switch (child.getTag()) {
+ case TAG_NODE_NAME:
+ if (nodeName != null) {
+ throw new ParsingException("Duplicate NodeName: " + child.getText());
+ }
+ nodeName = child.getText();
+ if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
+ throw new ParsingException("Unexpected NodeName: " + nodeName);
+ }
+ break;
+ case TAG_NODE:
+ // A node can be either an UpdateIdentifier node or a PerProviderSubscription
+ // instance node. Flatten out the XML tree first by converting it to a PPS
+ // tree to reduce the complexity of the parsing code.
+ PPSNode ppsNodeRoot = buildPpsNode(child);
+ if (TextUtils.equals(ppsNodeRoot.getName(), NODE_UPDATE_IDENTIFIER)) {
+ if (updateIdentifier != Integer.MIN_VALUE) {
+ throw new ParsingException("Multiple node for UpdateIdentifier");
+ }
+ updateIdentifier = parseInteger(getPpsNodeValue(ppsNodeRoot));
+ } else {
+ // Only one PerProviderSubscription instance is expected and allowed.
+ if (config != null) {
+ throw new ParsingException("Multiple PPS instance");
+ }
+ config = parsePpsInstance(ppsNodeRoot);
+ }
+ break;
+ case TAG_RT_PROPERTIES:
+ // Parse and verify URN stored in the RT (Run Time) Properties.
+ String urn = parseUrn(child);
+ if (!TextUtils.equals(urn, PPS_MO_URN)) {
+ throw new ParsingException("Unknown URN: " + urn);
+ }
+ break;
+ default:
+ throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
+ }
+ }
+ if (config != null && updateIdentifier != Integer.MIN_VALUE) {
+ config.setUpdateIdentifier(updateIdentifier);
+ }
+ return config;
+ }
+
+ /**
+ * Parse the URN stored in the RTProperties. Below is the format of the RTPProperties node:
+ *
+ * <RTProperties>
+ * <Type>
+ * <DDFName>urn:...</DDFName>
+ * </Type>
+ * </RTProperties>
+ *
+ * @param node XMLNode that contains RTProperties node.
+ * @return URN String of URN.
+ * @throws ParsingException
+ */
+ private static String parseUrn(XMLNode node) throws ParsingException {
+ if (node.getChildren().size() != 1)
+ throw new ParsingException("Expect RTPProperties node to only have one child");
+
+ XMLNode typeNode = node.getChildren().get(0);
+ if (typeNode.getChildren().size() != 1) {
+ throw new ParsingException("Expect Type node to only have one child");
+ }
+ if (!TextUtils.equals(typeNode.getTag(), TAG_TYPE)) {
+ throw new ParsingException("Unexpected tag for Type: " + typeNode.getTag());
+ }
+
+ XMLNode ddfNameNode = typeNode.getChildren().get(0);
+ if (!ddfNameNode.getChildren().isEmpty()) {
+ throw new ParsingException("Expect DDFName node to have no child");
+ }
+ if (!TextUtils.equals(ddfNameNode.getTag(), TAG_DDF_NAME)) {
+ throw new ParsingException("Unexpected tag for DDFName: " + ddfNameNode.getTag());
+ }
+
+ return ddfNameNode.getText();
+ }
+
+ /**
+ * Convert a XML tree represented by XMLNode to a PPS (PerProviderSubscription) instance tree
+ * represented by PPSNode. This flattens out the XML tree to allow easier and cleaner parsing
+ * of the PPS configuration data. Only three types of XML tag are expected: "NodeName",
+ * "Node", and "Value".
+ *
+ * The original XML tree (each XML element represent a node):
+ *
+ * <Node>
+ * <NodeName>root</NodeName>
+ * <Node>
+ * <NodeName>child1</NodeName>
+ * <Value>value1</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>child2</NodeName>
+ * <Node>
+ * <NodeName>grandchild1</NodeName>
+ * ...
+ * </Node>
+ * </Node>
+ * ...
+ * </Node>
+ *
+ * The converted PPS tree:
+ *
+ * [root] --- [child1, value1]
+ * |
+ * ---------[child2] --------[grandchild1] --- ...
+ *
+ * @param node XMLNode pointed to the root of a XML tree
+ * @return PPSNode pointing to the root of a PPS tree
+ * @throws ParsingException
+ */
+ private static PPSNode buildPpsNode(XMLNode node) throws ParsingException {
+ String nodeName = null;
+ String nodeValue = null;
+ List<PPSNode> childNodes = new ArrayList<PPSNode>();
+ // Names of parsed child nodes, use for detecting multiple child nodes with the same name.
+ Set<String> parsedNodes = new HashSet<String>();
+
+ for (XMLNode child : node.getChildren()) {
+ String tag = child.getTag();
+ if (TextUtils.equals(tag, TAG_NODE_NAME)) {
+ if (nodeName != null) {
+ throw new ParsingException("Duplicate NodeName node");
+ }
+ nodeName = child.getText();
+ } else if (TextUtils.equals(tag, TAG_NODE)) {
+ PPSNode ppsNode = buildPpsNode(child);
+ if (parsedNodes.contains(ppsNode.getName())) {
+ throw new ParsingException("Duplicate node: " + ppsNode.getName());
+ }
+ parsedNodes.add(ppsNode.getName());
+ childNodes.add(ppsNode);
+ } else if (TextUtils.equals(tag, TAG_VALUE)) {
+ if (nodeValue != null) {
+ throw new ParsingException("Duplicate Value node");
+ }
+ nodeValue = child.getText();
+ } else {
+ throw new ParsingException("Unknown tag: " + tag);
+ }
+ }
+
+ if (nodeName == null) {
+ throw new ParsingException("Invalid node: missing NodeName");
+ }
+ if (nodeValue == null && childNodes.size() == 0) {
+ throw new ParsingException("Invalid node: " + nodeName +
+ " missing both value and children");
+ }
+ if (nodeValue != null && childNodes.size() > 0) {
+ throw new ParsingException("Invalid node: " + nodeName +
+ " contained both value and children");
+ }
+
+ if (nodeValue != null) {
+ return new LeafNode(nodeName, nodeValue);
+ }
+ return new InternalNode(nodeName, childNodes);
+ }
+
+ /**
+ * Return the value of a PPSNode. An exception will be thrown if the given node
+ * is not a leaf node.
+ *
+ * @param node PPSNode to retrieve the value from
+ * @return String representing the value of the node
+ * @throws ParsingException
+ */
+ private static String getPpsNodeValue(PPSNode node) throws ParsingException {
+ if (!node.isLeaf()) {
+ throw new ParsingException("Cannot get value from a non-leaf node: " + node.getName());
+ }
+ return node.getValue();
+ }
+
+ /**
+ * Parse a PPS (PerProviderSubscription) configurations from a PPS tree.
+ *
+ * @param root PPSNode representing the root of the PPS tree
+ * @return PasspointConfiguration
+ * @throws ParsingException
+ */
+ private static PasspointConfiguration parsePpsInstance(PPSNode root)
+ throws ParsingException {
+ if (root.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PPS instance");
+ }
+
+ PasspointConfiguration config = new PasspointConfiguration();
+ for (PPSNode child : root.getChildren()) {
+ switch(child.getName()) {
+ case NODE_HOMESP:
+ config.setHomeSp(parseHomeSP(child));
+ break;
+ case NODE_CREDENTIAL:
+ config.setCredential(parseCredential(child));
+ break;
+ case NODE_POLICY:
+ config.setPolicy(parsePolicy(child));
+ break;
+ case NODE_AAA_SERVER_TRUST_ROOT:
+ config.setTrustRootCertList(parseAAAServerTrustRootList(child));
+ break;
+ case NODE_SUBSCRIPTION_UPDATE:
+ config.setSubscriptionUpdate(parseUpdateParameter(child));
+ break;
+ case NODE_SUBSCRIPTION_PARAMETER:
+ parseSubscriptionParameter(child, config);
+ break;
+ case NODE_CREDENTIAL_PRIORITY:
+ config.setCredentialPriority(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node: " + child.getName());
+ }
+ }
+ return config;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP subtree
+ * @return HomeSP
+ * @throws ParsingException
+ */
+ private static HomeSp parseHomeSP(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeSP");
+ }
+
+ HomeSp homeSp = new HomeSp();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ homeSp.setFqdn(getPpsNodeValue(child));
+ break;
+ case NODE_FRIENDLY_NAME:
+ homeSp.setFriendlyName(getPpsNodeValue(child));
+ break;
+ case NODE_ROAMING_CONSORTIUM_OI:
+ homeSp.setRoamingConsortiumOis(
+ parseRoamingConsortiumOI(getPpsNodeValue(child)));
+ break;
+ case NODE_ICON_URL:
+ homeSp.setIconUrl(getPpsNodeValue(child));
+ break;
+ case NODE_NETWORK_ID:
+ homeSp.setHomeNetworkIds(parseNetworkIds(child));
+ break;
+ case NODE_HOME_OI_LIST:
+ Pair<List<Long>, List<Long>> homeOIs = parseHomeOIList(child);
+ homeSp.setMatchAllOis(convertFromLongList(homeOIs.first));
+ homeSp.setMatchAnyOis(convertFromLongList(homeOIs.second));
+ break;
+ case NODE_OTHER_HOME_PARTNERS:
+ homeSp.setOtherHomePartners(parseOtherHomePartners(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under HomeSP: " + child.getName());
+ }
+ }
+ return homeSp;
+ }
+
+ /**
+ * Parse the roaming consortium OI string, which contains a list of OIs separated by ",".
+ *
+ * @param oiStr string containing list of OIs (Organization Identifiers) separated by ","
+ * @return long[]
+ * @throws ParsingException
+ */
+ private static long[] parseRoamingConsortiumOI(String oiStr)
+ throws ParsingException {
+ String[] oiStrArray = oiStr.split(",");
+ long[] oiArray = new long[oiStrArray.length];
+ for (int i = 0; i < oiStrArray.length; i++) {
+ oiArray[i] = parseLong(oiStrArray[i], 16);
+ }
+ return oiArray;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/NetworkID
+ * subtree
+ * @return HashMap<String, Long> representing list of <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Map<String, Long> parseNetworkIds(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID");
+ }
+
+ Map<String, Long> networkIds = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<String, Long> networkId = parseNetworkIdInstance(child);
+ networkIds.put(networkId.first, networkId.second);
+ }
+ return networkIds;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/NetworkID/<X+> subtree
+ * @return Pair<String, Long> representing <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Pair<String, Long> parseNetworkIdInstance(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID instance");
+ }
+
+ String ssid = null;
+ Long hessid = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SSID:
+ ssid = getPpsNodeValue(child);
+ break;
+ case NODE_HESSID:
+ hessid = parseLong(getPpsNodeValue(child), 16);
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (ssid == null)
+ throw new ParsingException("NetworkID instance missing SSID");
+
+ return new Pair<String, Long>(ssid, hessid);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/HomeOIList
+ * subtree
+ * @return Pair<List<Long>, List<Long>> containing both MatchAllOIs and MatchAnyOIs list.
+ * @throws ParsingException
+ */
+ private static Pair<List<Long>, List<Long>> parseHomeOIList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOIList");
+ }
+
+ List<Long> matchAllOIs = new ArrayList<Long>();
+ List<Long> matchAnyOIs = new ArrayList<Long>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<Long, Boolean> homeOI = parseHomeOIInstance(child);
+ if (homeOI.second.booleanValue()) {
+ matchAllOIs.add(homeOI.first);
+ } else {
+ matchAnyOIs.add(homeOI.first);
+ }
+ }
+ return new Pair<List<Long>, List<Long>>(matchAllOIs, matchAnyOIs);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree
+ * @return Pair<Long, Boolean> containing a HomeOI and a HomeOIRequired flag
+ * @throws ParsingException
+ */
+ private static Pair<Long, Boolean> parseHomeOIInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOI instance");
+ }
+
+ Long oi = null;
+ Boolean required = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_HOME_OI:
+ try {
+ oi = Long.valueOf(getPpsNodeValue(child), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid HomeOI: " + getPpsNodeValue(child));
+ }
+ break;
+ case NODE_HOME_OI_REQUIRED:
+ required = Boolean.valueOf(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (oi == null) {
+ throw new ParsingException("HomeOI instance missing OI field");
+ }
+ if (required == null) {
+ throw new ParsingException("HomeOI instance missing required field");
+ }
+ return new Pair<Long, Boolean>(oi, required);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners subtree.
+ * This contains a list of FQDN (Fully Qualified Domain Name) that are considered
+ * home partners.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners subtree
+ * @return String[] list of partner's FQDN
+ * @throws ParsingException
+ */
+ private static String[] parseOtherHomePartners(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartners");
+ }
+ List<String> otherHomePartners = new ArrayList<String>();
+ for (PPSNode child : node.getChildren()) {
+ String fqdn = parseOtherHomePartnerInstance(child);
+ otherHomePartners.add(fqdn);
+ }
+ return otherHomePartners.toArray(new String[otherHomePartners.size()]);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree
+ * @return String FQDN of the partner
+ * @throws ParsingException
+ */
+ private static String parseOtherHomePartnerInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartner instance");
+ }
+ String fqdn = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ fqdn = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException(
+ "Unknown node under OtherHomePartner instance: " + child.getName());
+ }
+ }
+ if (fqdn == null) {
+ throw new ParsingException("OtherHomePartner instance missing FQDN field");
+ }
+ return fqdn;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Credential subtree
+ * @return Credential
+ * @throws ParsingException
+ */
+ private static Credential parseCredential(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeSP");
+ }
+
+ Credential credential = new Credential();
+ for (PPSNode child: node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CREATION_DATE:
+ credential.setCreationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_EXPIRATION_DATE:
+ credential.setExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_USERNAME_PASSWORD:
+ credential.setUserCredential(parseUserCredential(child));
+ break;
+ case NODE_DIGITAL_CERTIFICATE:
+ credential.setCertCredential(parseCertificateCredential(child));
+ break;
+ case NODE_REALM:
+ credential.setRealm(getPpsNodeValue(child));
+ break;
+ case NODE_CHECK_AAA_SERVER_CERT_STATUS:
+ credential.setCheckAaaServerCertStatus(
+ Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_SIM:
+ credential.setSimCredential(parseSimCredential(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under Credential: " +
+ child.getName());
+ }
+ }
+ return credential;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/UsernamePassword subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/UsernamePassword subtree
+ * @return Credential.UserCredential
+ * @throws ParsingException
+ */
+ private static Credential.UserCredential parseUserCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsernamePassword");
+ }
+
+ Credential.UserCredential userCred = new Credential.UserCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_USERNAME:
+ userCred.setUsername(getPpsNodeValue(child));
+ break;
+ case NODE_PASSWORD:
+ userCred.setPassword(getPpsNodeValue(child));
+ break;
+ case NODE_MACHINE_MANAGED:
+ userCred.setMachineManaged(Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_SOFT_TOKEN_APP:
+ userCred.setSoftTokenApp(getPpsNodeValue(child));
+ break;
+ case NODE_ABLE_TO_SHARE:
+ userCred.setAbleToShare(Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_EAP_METHOD:
+ parseEAPMethod(child, userCred);
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsernamPassword: " +
+ child.getName());
+ }
+ }
+ return userCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/UsernamePassword/EAPMethod
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/UsernamePassword/EAPMethod subtree
+ * @param userCred UserCredential to be updated with EAP method values.
+ * @throws ParsingException
+ */
+ private static void parseEAPMethod(PPSNode node, Credential.UserCredential userCred)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for EAPMethod");
+ }
+
+ for (PPSNode child : node.getChildren()) {
+ switch(child.getName()) {
+ case NODE_EAP_TYPE:
+ userCred.setEapType(parseInteger(getPpsNodeValue(child)));
+ break;
+ case NODE_INNER_METHOD:
+ userCred.setNonEapInnerMethod(getPpsNodeValue(child));
+ break;
+ case NODE_VENDOR_ID:
+ case NODE_VENDOR_TYPE:
+ case NODE_INNER_EAP_TYPE:
+ case NODE_INNER_VENDOR_ID:
+ case NODE_INNER_VENDOR_TYPE:
+ // Only EAP-TTLS is currently supported for user credential, which doesn't
+ // use any of these parameters.
+ Log.d(TAG, "Ignore unsupported EAP method parameter: " + child.getName());
+ break;
+ default:
+ throw new ParsingException("Unknown node under EAPMethod: " + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/DigitalCertificate subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/DigitalCertificate subtree
+ * @return Credential.CertificateCredential
+ * @throws ParsingException
+ */
+ private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for DigitalCertificate");
+ }
+
+ Credential.CertificateCredential certCred = new Credential.CertificateCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CERTIFICATE_TYPE:
+ certCred.setCertType(getPpsNodeValue(child));
+ break;
+ case NODE_CERT_SHA256_FINGERPRINT:
+ certCred.setCertSha256Fingerprint(parseHexString(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under DigitalCertificate: " +
+ child.getName());
+ }
+ }
+ return certCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/SIM subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Credential/SIM
+ * subtree
+ * @return Credential.SimCredential
+ * @throws ParsingException
+ */
+ private static Credential.SimCredential parseSimCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SIM");
+ }
+
+ Credential.SimCredential simCred = new Credential.SimCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SIM_IMSI:
+ simCred.setImsi(getPpsNodeValue(child));
+ break;
+ case NODE_EAP_TYPE:
+ simCred.setEapType(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under SIM: " + child.getName());
+ }
+ }
+ return simCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Policy subtree
+ * @return {@link Policy}
+ * @throws ParsingException
+ */
+ private static Policy parsePolicy(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for Policy");
+ }
+
+ Policy policy = new Policy();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_PREFERRED_ROAMING_PARTNER_LIST:
+ policy.setPreferredRoamingPartnerList(parsePreferredRoamingPartnerList(child));
+ break;
+ case NODE_MIN_BACKHAUL_THRESHOLD:
+ parseMinBackhaulThreshold(child, policy);
+ break;
+ case NODE_POLICY_UPDATE:
+ policy.setPolicyUpdate(parseUpdateParameter(child));
+ break;
+ case NODE_SP_EXCLUSION_LIST:
+ policy.setExcludedSsidList(parseSpExclusionList(child));
+ break;
+ case NODE_REQUIRED_PROTO_PORT_TUPLE:
+ policy.setRequiredProtoPortMap(parseRequiredProtoPortTuple(child));
+ break;
+ case NODE_MAXIMUM_BSS_LOAD_VALUE:
+ policy.setMaximumBssLoadValue(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under Policy: " + child.getName());
+ }
+ }
+ return policy;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/PreferredRoamingPartnerList subtree
+ * @return List of {@link Policy#RoamingPartner}
+ * @throws ParsingException
+ */
+ private static List<Policy.RoamingPartner> parsePreferredRoamingPartnerList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PreferredRoamingPartnerList");
+ }
+ List<Policy.RoamingPartner> partnerList = new ArrayList<>();
+ for (PPSNode child : node.getChildren()) {
+ partnerList.add(parsePreferredRoamingPartner(child));
+ }
+ return partnerList;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+>
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> subtree
+ * @return {@link Policy#RoamingPartner}
+ * @throws ParsingException
+ */
+ private static Policy.RoamingPartner parsePreferredRoamingPartner(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PreferredRoamingPartner "
+ + "instance");
+ }
+
+ Policy.RoamingPartner roamingPartner = new Policy.RoamingPartner();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN_MATCH:
+ // FQDN_Match field is in the format of "[FQDN],[MatchInfo]", where [MatchInfo]
+ // is either "exactMatch" for exact match of FQDN or "includeSubdomains" for
+ // matching all FQDNs with the same sub-domain.
+ String fqdnMatch = getPpsNodeValue(child);
+ String[] fqdnMatchArray = fqdnMatch.split(",");
+ if (fqdnMatchArray.length != 2) {
+ throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
+ }
+ roamingPartner.setFqdn(fqdnMatchArray[0]);
+ if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) {
+ roamingPartner.setFqdnExactMatch(true);
+ } else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) {
+ roamingPartner.setFqdnExactMatch(false);
+ } else {
+ throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
+ }
+ break;
+ case NODE_PRIORITY:
+ roamingPartner.setPriority(parseInteger(getPpsNodeValue(child)));
+ break;
+ case NODE_COUNTRY:
+ roamingPartner.setCountries(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under PreferredRoamingPartnerList "
+ + "instance " + child.getName());
+ }
+ }
+ return roamingPartner;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold subtree
+ * into the given policy.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/MinBackhaulThreshold subtree
+ * @param policy The policy to store the MinBackhualThreshold configuration
+ * @throws ParsingException
+ */
+ private static void parseMinBackhaulThreshold(PPSNode node, Policy policy)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for MinBackhaulThreshold");
+ }
+ for (PPSNode child : node.getChildren()) {
+ parseMinBackhaulThresholdInstance(child, policy);
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
+ * into the given policy.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
+ * @param policy The policy to store the MinBackhaulThreshold configuration
+ * @throws ParsingException
+ */
+ private static void parseMinBackhaulThresholdInstance(PPSNode node, Policy policy)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for MinBackhaulThreshold instance");
+ }
+ String networkType = null;
+ long downlinkBandwidth = Long.MIN_VALUE;
+ long uplinkBandwidth = Long.MIN_VALUE;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_NETWORK_TYPE:
+ networkType = getPpsNodeValue(child);
+ break;
+ case NODE_DOWNLINK_BANDWIDTH:
+ downlinkBandwidth = parseLong(getPpsNodeValue(child), 10);
+ break;
+ case NODE_UPLINK_BANDWIDTH:
+ uplinkBandwidth = parseLong(getPpsNodeValue(child), 10);
+ break;
+ default:
+ throw new ParsingException("Unknown node under MinBackhaulThreshold instance "
+ + child.getName());
+ }
+ }
+ if (networkType == null) {
+ throw new ParsingException("Missing NetworkType field");
+ }
+
+ if (TextUtils.equals(networkType, "home")) {
+ policy.setMinHomeDownlinkBandwidth(downlinkBandwidth);
+ policy.setMinHomeUplinkBandwidth(uplinkBandwidth);
+ } else if (TextUtils.equals(networkType, "roaming")) {
+ policy.setMinRoamingDownlinkBandwidth(downlinkBandwidth);
+ policy.setMinRoamingUplinkBandwidth(uplinkBandwidth);
+ } else {
+ throw new ParsingException("Invalid network type: " + networkType);
+ }
+ }
+
+ /**
+ * Parse update parameters. This contained configurations from either
+ * PerProviderSubscription/Policy/PolicyUpdate or PerProviderSubscription/SubscriptionUpdate
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Policy/PolicyUpdate
+ * or PerProviderSubscription/SubscriptionUpdate subtree
+ * @return {@link UpdateParameter}
+ * @throws ParsingException
+ */
+ private static UpdateParameter parseUpdateParameter(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for Update Parameters");
+ }
+
+ UpdateParameter updateParam = new UpdateParameter();
+ for (PPSNode child : node.getChildren()) {
+ switch(child.getName()) {
+ case NODE_UPDATE_INTERVAL:
+ updateParam.setUpdateIntervalInMinutes(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_UPDATE_METHOD:
+ updateParam.setUpdateMethod(getPpsNodeValue(child));
+ break;
+ case NODE_RESTRICTION:
+ updateParam.setRestriction(getPpsNodeValue(child));
+ break;
+ case NODE_URI:
+ updateParam.setServerUri(getPpsNodeValue(child));
+ break;
+ case NODE_USERNAME_PASSWORD:
+ Pair<String, String> usernamePassword = parseUpdateUserCredential(child);
+ updateParam.setUsername(usernamePassword.first);
+ updateParam.setBase64EncodedPassword(usernamePassword.second);
+ break;
+ case NODE_TRUST_ROOT:
+ Pair<String, byte[]> trustRoot = parseTrustRoot(child);
+ updateParam.setTrustRootCertUrl(trustRoot.first);
+ updateParam.setTrustRootCertSha256Fingerprint(trustRoot.second);
+ break;
+ case NODE_OTHER:
+ Log.d(TAG, "Ignore unsupported paramter: " + child.getName());
+ break;
+ default:
+ throw new ParsingException("Unknown node under Update Parameters: "
+ + child.getName());
+ }
+ }
+ return updateParam;
+ }
+
+ /**
+ * Parse username and password parameters associated with policy or subscription update.
+ * This contained configurations under either
+ * PerProviderSubscription/Policy/PolicyUpdate/UsernamePassword or
+ * PerProviderSubscription/SubscriptionUpdate/UsernamePassword subtree.
+ *
+ * @param node PPSNode representing the root of the UsernamePassword subtree
+ * @return Pair of username and password
+ * @throws ParsingException
+ */
+ private static Pair<String, String> parseUpdateUserCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsernamePassword");
+ }
+
+ String username = null;
+ String password = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_USERNAME:
+ username = getPpsNodeValue(child);
+ break;
+ case NODE_PASSWORD:
+ password = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsernamePassword: "
+ + child.getName());
+ }
+ }
+ return Pair.create(username, password);
+ }
+
+ /**
+ * Parse the trust root parameters associated with policy update, subscription update, or AAA
+ * server trust root.
+ *
+ * This contained configurations under either
+ * PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or
+ * PerProviderSubscription/SubscriptionUpdate/TrustRoot or
+ * PerProviderSubscription/AAAServerTrustRoot/<X+> subtree.
+ *
+ * @param node PPSNode representing the root of the TrustRoot subtree
+ * @return Pair of Certificate URL and fingerprint
+ * @throws ParsingException
+ */
+ private static Pair<String, byte[]> parseTrustRoot(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for TrustRoot");
+ }
+
+ String certUrl = null;
+ byte[] certFingerprint = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CERT_URL:
+ certUrl = getPpsNodeValue(child);
+ break;
+ case NODE_CERT_SHA256_FINGERPRINT:
+ certFingerprint = parseHexString(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under TrustRoot: "
+ + child.getName());
+ }
+ }
+ return Pair.create(certUrl, certFingerprint);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/SPExclusionList subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/SPExclusionList subtree
+ * @return Array of excluded SSIDs
+ * @throws ParsingException
+ */
+ private static String[] parseSpExclusionList(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SPExclusionList");
+ }
+ List<String> ssidList = new ArrayList<>();
+ for (PPSNode child : node.getChildren()) {
+ ssidList.add(parseSpExclusionInstance(child));
+ }
+ return ssidList.toArray(new String[ssidList.size()]);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/SPExclusionList/<X+> subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/SPExclusionList/<X+> subtree
+ * @return String
+ * @throws ParsingException
+ */
+ private static String parseSpExclusionInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SPExclusion instance");
+ }
+ String ssid = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SSID:
+ ssid = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under SPExclusion instance");
+ }
+ }
+ return ssid;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/RequiredProtoPortTuple subtree
+ * @return Map of IP Protocol to Port Number tuples
+ * @throws ParsingException
+ */
+ private static Map<Integer, String> parseRequiredProtoPortTuple(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple");
+ }
+ Map<Integer, String> protoPortTupleMap = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<Integer, String> protoPortTuple = parseProtoPortTuple(child);
+ protoPortTupleMap.put(protoPortTuple.first, protoPortTuple.second);
+ }
+ return protoPortTupleMap;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+>
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> subtree
+ * @return Pair of IP Protocol to Port Number tuple
+ * @throws ParsingException
+ */
+ private static Pair<Integer, String> parseProtoPortTuple(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple "
+ + "instance");
+ }
+ int proto = Integer.MIN_VALUE;
+ String ports = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_IP_PROTOCOL:
+ proto = parseInteger(getPpsNodeValue(child));
+ break;
+ case NODE_PORT_NUMBER:
+ ports = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under RequiredProtoPortTuple instance"
+ + child.getName());
+ }
+ }
+ if (proto == Integer.MIN_VALUE) {
+ throw new ParsingException("Missing IPProtocol field");
+ }
+ if (ports == null) {
+ throw new ParsingException("Missing PortNumber field");
+ }
+ return Pair.create(proto, ports);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/AAAServerTrustRoot subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/AAAServerTrustRoot
+ * subtree
+ * @return Map of certificate URL with the corresponding certificate fingerprint
+ * @throws ParsingException
+ */
+ private static Map<String, byte[]> parseAAAServerTrustRootList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for AAAServerTrustRoot");
+ }
+ Map<String, byte[]> certList = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<String, byte[]> certTuple = parseTrustRoot(child);
+ certList.put(certTuple.first, certTuple.second);
+ }
+ return certList;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/SubscriptionParameter subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/SubscriptionParameter
+ * subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseSubscriptionParameter(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SubscriptionParameter");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CREATION_DATE:
+ config.setSubscriptionCreationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_EXPIRATION_DATE:
+ config.setSubscriptionExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_TYPE_OF_SUBSCRIPTION:
+ config.setSubscriptionType(getPpsNodeValue(child));
+ break;
+ case NODE_USAGE_LIMITS:
+ parseUsageLimits(child, config);
+ break;
+ default:
+ throw new ParsingException("Unknown node under SubscriptionParameter"
+ + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/SubscriptionParameter/UsageLimits
+ * subtree.
+ *
+ * @param node PPSNode representing the root of
+ * PerProviderSubscription/SubscriptionParameter/UsageLimits subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseUsageLimits(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsageLimits");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_DATA_LIMIT:
+ config.setUsageLimitDataLimit(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_START_DATE:
+ config.setUsageLimitStartTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_TIME_LIMIT:
+ config.setUsageLimitTimeLimitInMinutes(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_USAGE_TIME_PERIOD:
+ config.setUsageLimitUsageTimePeriodInMinutes(
+ parseLong(getPpsNodeValue(child), 10));
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsageLimits"
+ + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Convert a hex string to a byte array.
+ *
+ * @param str String containing hex values
+ * @return byte[]
+ * @throws ParsingException
+ */
+ private static byte[] parseHexString(String str) throws ParsingException {
+ if ((str.length() & 1) == 1) {
+ throw new ParsingException("Odd length hex string: " + str.length());
+ }
+
+ byte[] result = new byte[str.length() / 2];
+ for (int i = 0; i < result.length; i++) {
+ int index = i * 2;
+ try {
+ result[i] = (byte) Integer.parseInt(str.substring(index, index + 2), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid hex string: " + str);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Convert a date string to the number of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * @param dateStr String in the format of yyyy-MM-dd'T'HH:mm:ss'Z'
+ * @return number of milliseconds
+ * @throws ParsingException
+ */
+ private static long parseDate(String dateStr) throws ParsingException {
+ try {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ return format.parse(dateStr).getTime();
+ } catch (ParseException pe) {
+ throw new ParsingException("Badly formatted time: " + dateStr);
+ }
+ }
+
+ /**
+ * Parse an integer string.
+ *
+ * @param value String of integer value
+ * @return int
+ * @throws ParsingException
+ */
+ private static int parseInteger(String value) throws ParsingException {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid integer value: " + value);
+ }
+ }
+
+ /**
+ * Parse a string representing a long integer.
+ *
+ * @param value String of long integer value
+ * @return long
+ * @throws ParsingException
+ */
+ private static long parseLong(String value, int radix) throws ParsingException {
+ try {
+ return Long.parseLong(value, radix);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid long integer value: " + value);
+ }
+ }
+
+ /**
+ * Convert a List<Long> to a primitive long array long[].
+ *
+ * @param list List to be converted
+ * @return long[]
+ */
+ private static long[] convertFromLongList(List<Long> list) {
+ Long[] objectArray = list.toArray(new Long[list.size()]);
+ long[] primitiveArray = new long[objectArray.length];
+ for (int i = 0; i < objectArray.length; i++) {
+ primitiveArray[i] = objectArray[i].longValue();
+ }
+ return primitiveArray;
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
index e87698cb7ed1..959d5057e257 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
@@ -20,6 +20,7 @@ import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A class represent a node in an XML tree. Each node is an XML element.
@@ -100,4 +101,9 @@ public class XMLNode {
TextUtils.equals(mText, that.mText) &&
mChildren.equals(that.mChildren);
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTag, mText, mChildren);
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 790dfaf643ca..025d4d389253 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -23,6 +23,7 @@ import android.os.Parcel;
import android.text.TextUtils;
import android.util.Log;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -30,6 +31,7 @@ import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
/**
@@ -40,10 +42,6 @@ import java.util.Set;
*
* In addition to the fields in the Credential subtree, this will also maintain necessary
* information for the private key and certificates associated with this credential.
- *
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
- * @hide
*/
public final class Credential implements Parcelable {
private static final String TAG = "Credential";
@@ -52,14 +50,59 @@ public final class Credential implements Parcelable {
* Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2
* Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_REALM_LENGTH = 253;
+ private static final int MAX_REALM_BYTES = 253;
+
+ /**
+ * The time this credential is created. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mCreationTimeInMs = Long.MIN_VALUE;
+ public void setCreationTimeInMs(long creationTimeInMs) {
+ mCreationTimeInMs = creationTimeInMs;
+ }
+ public long getCreationTimeInMs() {
+ return mCreationTimeInMs;
+ }
+
+ /**
+ * The time this credential will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mExpirationTimeInMs = Long.MIN_VALUE;
+ public void setExpirationTimeInMs(long expirationTimeInMs) {
+ mExpirationTimeInMs = expirationTimeInMs;
+ }
+ public long getExpirationTimeInMs() {
+ return mExpirationTimeInMs;
+ }
/**
* The realm associated with this credential. It will be used to determine
* if this credential can be used to authenticate with a given hotspot by
* comparing the realm specified in that hotspot's ANQP element.
*/
- public String realm = null;
+ private String mRealm = null;
+ public void setRealm(String realm) {
+ mRealm = realm;
+ }
+ public String getRealm() {
+ return mRealm;
+ }
+
+ /**
+ * When set to true, the device should check AAA (Authentication, Authorization,
+ * and Accounting) server's certificate during EAP (Extensible Authentication
+ * Protocol) authentication.
+ */
+ private boolean mCheckAaaServerCertStatus = false;
+ public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
+ mCheckAaaServerCertStatus = checkAaaServerCertStatus;
+ }
+ public boolean getCheckAaaServerStatus() {
+ return mCheckAaaServerCertStatus;
+ }
/**
* Username-password based credential.
@@ -70,13 +113,13 @@ public final class Credential implements Parcelable {
* Maximum string length for username. Refer to Credential/UsernamePassword/Username
* node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_USERNAME_LENGTH = 63;
+ private static final int MAX_USERNAME_BYTES = 63;
/**
* Maximum string length for password. Refer to Credential/UsernamePassword/Password
* in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_PASSWORD_LENGTH = 255;
+ private static final int MAX_PASSWORD_BYTES = 255;
/**
* Supported Non-EAP inner methods. Refer to
@@ -89,12 +132,57 @@ public final class Credential implements Parcelable {
/**
* Username of the credential.
*/
- public String username = null;
+ private String mUsername = null;
+ public void setUsername(String username) {
+ mUsername = username;
+ }
+ public String getUsername() {
+ return mUsername;
+ }
/**
* Base64-encoded password.
*/
- public String password = null;
+ private String mPassword = null;
+ public void setPassword(String password) {
+ mPassword = password;
+ }
+ public String getPassword() {
+ return mPassword;
+ }
+
+ /**
+ * Flag indicating if the password is machine managed.
+ */
+ private boolean mMachineManaged = false;
+ public void setMachineManaged(boolean machineManaged) {
+ mMachineManaged = machineManaged;
+ }
+ public boolean getMachineManaged() {
+ return mMachineManaged;
+ }
+
+ /**
+ * The name of the application used to generate the password.
+ */
+ private String mSoftTokenApp = null;
+ public void setSoftTokenApp(String softTokenApp) {
+ mSoftTokenApp = softTokenApp;
+ }
+ public String getSoftTokenApp() {
+ return mSoftTokenApp;
+ }
+
+ /**
+ * Flag indicating if this credential is usable on other mobile devices as well.
+ */
+ private boolean mAbleToShare = false;
+ public void setAbleToShare(boolean ableToShare) {
+ mAbleToShare = ableToShare;
+ }
+ public boolean getAbleToShare() {
+ return mAbleToShare;
+ }
/**
* EAP (Extensible Authentication Protocol) method type.
@@ -102,12 +190,24 @@ public final class Credential implements Parcelable {
* for valid values.
* Using Integer.MIN_VALUE to indicate unset value.
*/
- public int eapType = Integer.MIN_VALUE;
+ private int mEapType = Integer.MIN_VALUE;
+ public void setEapType(int eapType) {
+ mEapType = eapType;
+ }
+ public int getEapType() {
+ return mEapType;
+ }
/**
* Non-EAP inner authentication method.
*/
- public String nonEapInnerMethod = null;
+ private String mNonEapInnerMethod = null;
+ public void setNonEapInnerMethod(String nonEapInnerMethod) {
+ mNonEapInnerMethod = nonEapInnerMethod;
+ }
+ public String getNonEapInnerMethod() {
+ return mNonEapInnerMethod;
+ }
/**
* Constructor for creating UserCredential with default values.
@@ -121,10 +221,13 @@ public final class Credential implements Parcelable {
*/
public UserCredential(UserCredential source) {
if (source != null) {
- username = source.username;
- password = source.password;
- eapType = source.eapType;
- nonEapInnerMethod = source.nonEapInnerMethod;
+ mUsername = source.mUsername;
+ mPassword = source.mPassword;
+ mMachineManaged = source.mMachineManaged;
+ mSoftTokenApp = source.mSoftTokenApp;
+ mAbleToShare = source.mAbleToShare;
+ mEapType = source.mEapType;
+ mNonEapInnerMethod = source.mNonEapInnerMethod;
}
}
@@ -135,10 +238,13 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(username);
- dest.writeString(password);
- dest.writeInt(eapType);
- dest.writeString(nonEapInnerMethod);
+ dest.writeString(mUsername);
+ dest.writeString(mPassword);
+ dest.writeInt(mMachineManaged ? 1 : 0);
+ dest.writeString(mSoftTokenApp);
+ dest.writeInt(mAbleToShare ? 1 : 0);
+ dest.writeInt(mEapType);
+ dest.writeString(mNonEapInnerMethod);
}
@Override
@@ -151,10 +257,19 @@ public final class Credential implements Parcelable {
}
UserCredential that = (UserCredential) thatObject;
- return TextUtils.equals(username, that.username) &&
- TextUtils.equals(password, that.password) &&
- eapType == that.eapType &&
- TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
+ return TextUtils.equals(mUsername, that.mUsername)
+ && TextUtils.equals(mPassword, that.mPassword)
+ && mMachineManaged == that.mMachineManaged
+ && TextUtils.equals(mSoftTokenApp, that.mSoftTokenApp)
+ && mAbleToShare == that.mAbleToShare
+ && mEapType == that.mEapType
+ && TextUtils.equals(mNonEapInnerMethod, that.mNonEapInnerMethod);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUsername, mPassword, mMachineManaged, mSoftTokenApp,
+ mAbleToShare, mEapType, mNonEapInnerMethod);
}
/**
@@ -163,33 +278,35 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (TextUtils.isEmpty(username)) {
+ if (TextUtils.isEmpty(mUsername)) {
Log.d(TAG, "Missing username");
return false;
}
- if (username.length() > MAX_USERNAME_LENGTH) {
- Log.d(TAG, "username exceeding maximum length: " + username.length());
+ if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+ Log.d(TAG, "username exceeding maximum length: "
+ + mUsername.getBytes(StandardCharsets.UTF_8).length);
return false;
}
- if (TextUtils.isEmpty(password)) {
+ if (TextUtils.isEmpty(mPassword)) {
Log.d(TAG, "Missing password");
return false;
}
- if (password.length() > MAX_PASSWORD_LENGTH) {
- Log.d(TAG, "password exceeding maximum length: " + password.length());
+ if (mPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+ Log.d(TAG, "password exceeding maximum length: "
+ + mPassword.getBytes(StandardCharsets.UTF_8).length);
return false;
}
// Only supports EAP-TTLS for user credential.
- if (eapType != EAPConstants.EAP_TTLS) {
- Log.d(TAG, "Invalid EAP Type for user credential: " + eapType);
+ if (mEapType != EAPConstants.EAP_TTLS) {
+ Log.d(TAG, "Invalid EAP Type for user credential: " + mEapType);
return false;
}
// Verify Non-EAP inner method for EAP-TTLS.
- if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) {
- Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod);
+ if (!SUPPORTED_AUTH.contains(mNonEapInnerMethod)) {
+ Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + mNonEapInnerMethod);
return false;
}
return true;
@@ -200,10 +317,13 @@ public final class Credential implements Parcelable {
@Override
public UserCredential createFromParcel(Parcel in) {
UserCredential userCredential = new UserCredential();
- userCredential.username = in.readString();
- userCredential.password = in.readString();
- userCredential.eapType = in.readInt();
- userCredential.nonEapInnerMethod = in.readString();
+ userCredential.setUsername(in.readString());
+ userCredential.setPassword(in.readString());
+ userCredential.setMachineManaged(in.readInt() != 0);
+ userCredential.setSoftTokenApp(in.readString());
+ userCredential.setAbleToShare(in.readInt() != 0);
+ userCredential.setEapType(in.readInt());
+ userCredential.setNonEapInnerMethod(in.readString());
return userCredential;
}
@@ -213,7 +333,13 @@ public final class Credential implements Parcelable {
}
};
}
- public UserCredential userCredential = null;
+ private UserCredential mUserCredential = null;
+ public void setUserCredential(UserCredential userCredential) {
+ mUserCredential = userCredential;
+ }
+ public UserCredential getUserCredential() {
+ return mUserCredential;
+ }
/**
* Certificate based credential. This is used for EAP-TLS.
@@ -233,12 +359,24 @@ public final class Credential implements Parcelable {
/**
* Certificate type.
*/
- public String certType = null;
+ private String mCertType = null;
+ public void setCertType(String certType) {
+ mCertType = certType;
+ }
+ public String getCertType() {
+ return mCertType;
+ }
/**
* The SHA-256 fingerprint of the certificate.
*/
- public byte[] certSha256FingerPrint = null;
+ private byte[] mCertSha256Fingerprint = null;
+ public void setCertSha256Fingerprint(byte[] certSha256Fingerprint) {
+ mCertSha256Fingerprint = certSha256Fingerprint;
+ }
+ public byte[] getCertSha256Fingerprint() {
+ return mCertSha256Fingerprint;
+ }
/**
* Constructor for creating CertificateCredential with default values.
@@ -252,10 +390,10 @@ public final class Credential implements Parcelable {
*/
public CertificateCredential(CertificateCredential source) {
if (source != null) {
- certType = source.certType;
- if (source.certSha256FingerPrint != null) {
- certSha256FingerPrint = Arrays.copyOf(source.certSha256FingerPrint,
- source.certSha256FingerPrint.length);
+ mCertType = source.mCertType;
+ if (source.mCertSha256Fingerprint != null) {
+ mCertSha256Fingerprint = Arrays.copyOf(source.mCertSha256Fingerprint,
+ source.mCertSha256Fingerprint.length);
}
}
}
@@ -267,8 +405,8 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(certType);
- dest.writeByteArray(certSha256FingerPrint);
+ dest.writeString(mCertType);
+ dest.writeByteArray(mCertSha256Fingerprint);
}
@Override
@@ -281,8 +419,13 @@ public final class Credential implements Parcelable {
}
CertificateCredential that = (CertificateCredential) thatObject;
- return TextUtils.equals(certType, that.certType) &&
- Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
+ return TextUtils.equals(mCertType, that.mCertType)
+ && Arrays.equals(mCertSha256Fingerprint, that.mCertSha256Fingerprint);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCertType, mCertSha256Fingerprint);
}
/**
@@ -291,12 +434,12 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) {
- Log.d(TAG, "Unsupported certificate type: " + certType);
+ if (!TextUtils.equals(CERT_TYPE_X509V3, mCertType)) {
+ Log.d(TAG, "Unsupported certificate type: " + mCertType);
return false;
}
- if (certSha256FingerPrint == null ||
- certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
+ if (mCertSha256Fingerprint == null
+ || mCertSha256Fingerprint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
Log.d(TAG, "Invalid SHA-256 fingerprint");
return false;
}
@@ -308,8 +451,8 @@ public final class Credential implements Parcelable {
@Override
public CertificateCredential createFromParcel(Parcel in) {
CertificateCredential certCredential = new CertificateCredential();
- certCredential.certType = in.readString();
- certCredential.certSha256FingerPrint = in.createByteArray();
+ certCredential.setCertType(in.readString());
+ certCredential.setCertSha256Fingerprint(in.createByteArray());
return certCredential;
}
@@ -319,7 +462,13 @@ public final class Credential implements Parcelable {
}
};
}
- public CertificateCredential certCredential = null;
+ private CertificateCredential mCertCredential = null;
+ public void setCertCredential(CertificateCredential certCredential) {
+ mCertCredential = certCredential;
+ }
+ public CertificateCredential getCertCredential() {
+ return mCertCredential;
+ }
/**
* SIM (Subscriber Identify Module) based credential.
@@ -329,14 +478,20 @@ public final class Credential implements Parcelable {
/**
* Maximum string length for IMSI.
*/
- public static final int MAX_IMSI_LENGTH = 15;
+ private static final int MAX_IMSI_LENGTH = 15;
/**
* International Mobile Subscriber Identity, is used to identify the user
* of a cellular network and is a unique identification associated with all
* cellular networks
*/
- public String imsi = null;
+ private String mImsi = null;
+ public void setImsi(String imsi) {
+ mImsi = imsi;
+ }
+ public String getImsi() {
+ return mImsi;
+ }
/**
* EAP (Extensible Authentication Protocol) method type for using SIM credential.
@@ -344,7 +499,13 @@ public final class Credential implements Parcelable {
* for valid values.
* Using Integer.MIN_VALUE to indicate unset value.
*/
- public int eapType = Integer.MIN_VALUE;
+ private int mEapType = Integer.MIN_VALUE;
+ public void setEapType(int eapType) {
+ mEapType = eapType;
+ }
+ public int getEapType() {
+ return mEapType;
+ }
/**
* Constructor for creating SimCredential with default values.
@@ -358,8 +519,8 @@ public final class Credential implements Parcelable {
*/
public SimCredential(SimCredential source) {
if (source != null) {
- imsi = source.imsi;
- eapType = source.eapType;
+ mImsi = source.mImsi;
+ mEapType = source.mEapType;
}
}
@@ -378,14 +539,19 @@ public final class Credential implements Parcelable {
}
SimCredential that = (SimCredential) thatObject;
- return TextUtils.equals(imsi, that.imsi) &&
- eapType == that.eapType;
+ return TextUtils.equals(mImsi, that.mImsi)
+ && mEapType == that.mEapType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mImsi, mEapType);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(imsi);
- dest.writeInt(eapType);
+ dest.writeString(mImsi);
+ dest.writeInt(mEapType);
}
/**
@@ -400,9 +566,9 @@ public final class Credential implements Parcelable {
if (!verifyImsi()) {
return false;
}
- if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA &&
- eapType != EAPConstants.EAP_AKA_PRIME) {
- Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType);
+ if (mEapType != EAPConstants.EAP_SIM && mEapType != EAPConstants.EAP_AKA
+ && mEapType != EAPConstants.EAP_AKA_PRIME) {
+ Log.d(TAG, "Invalid EAP Type for SIM credential: " + mEapType);
return false;
}
return true;
@@ -413,8 +579,8 @@ public final class Credential implements Parcelable {
@Override
public SimCredential createFromParcel(Parcel in) {
SimCredential simCredential = new SimCredential();
- simCredential.imsi = in.readString();
- simCredential.eapType = in.readInt();
+ simCredential.setImsi(in.readString());
+ simCredential.setEapType(in.readInt());
return simCredential;
}
@@ -432,51 +598,75 @@ public final class Credential implements Parcelable {
* @return true if IMSI is valid, false otherwise.
*/
private boolean verifyImsi() {
- if (TextUtils.isEmpty(imsi)) {
+ if (TextUtils.isEmpty(mImsi)) {
Log.d(TAG, "Missing IMSI");
return false;
}
- if (imsi.length() > MAX_IMSI_LENGTH) {
- Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length());
+ if (mImsi.length() > MAX_IMSI_LENGTH) {
+ Log.d(TAG, "IMSI exceeding maximum length: " + mImsi.length());
return false;
}
// Locate the first non-digit character.
int nonDigit;
char stopChar = '\0';
- for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
- stopChar = imsi.charAt(nonDigit);
+ for (nonDigit = 0; nonDigit < mImsi.length(); nonDigit++) {
+ stopChar = mImsi.charAt(nonDigit);
if (stopChar < '0' || stopChar > '9') {
break;
}
}
- if (nonDigit == imsi.length()) {
+ if (nonDigit == mImsi.length()) {
return true;
}
- else if (nonDigit == imsi.length()-1 && stopChar == '*') {
+ else if (nonDigit == mImsi.length()-1 && stopChar == '*') {
// Prefix matching.
return true;
}
return false;
}
}
- public SimCredential simCredential = null;
+ private SimCredential mSimCredential = null;
+ public void setSimCredential(SimCredential simCredential) {
+ mSimCredential = simCredential;
+ }
+ public SimCredential getSimCredential() {
+ return mSimCredential;
+ }
/**
* CA (Certificate Authority) X509 certificate.
*/
- public X509Certificate caCertificate = null;
+ private X509Certificate mCaCertificate = null;
+ public void setCaCertificate(X509Certificate caCertificate) {
+ mCaCertificate = caCertificate;
+ }
+ public X509Certificate getCaCertificate() {
+ return mCaCertificate;
+ }
/**
* Client side X509 certificate chain.
*/
- public X509Certificate[] clientCertificateChain = null;
+ private X509Certificate[] mClientCertificateChain = null;
+ public void setClientCertificateChain(X509Certificate[] certificateChain) {
+ mClientCertificateChain = certificateChain;
+ }
+ public X509Certificate[] getClientCertificateChain() {
+ return mClientCertificateChain;
+ }
/**
* Client side private key.
*/
- public PrivateKey clientPrivateKey = null;
+ private PrivateKey mClientPrivateKey = null;
+ public void setClientPrivateKey(PrivateKey clientPrivateKey) {
+ mClientPrivateKey = clientPrivateKey;
+ }
+ public PrivateKey getClientPrivateKey() {
+ return mClientPrivateKey;
+ }
/**
* Constructor for creating Credential with default values.
@@ -490,22 +680,25 @@ public final class Credential implements Parcelable {
*/
public Credential(Credential source) {
if (source != null) {
- realm = source.realm;
- if (source.userCredential != null) {
- userCredential = new UserCredential(source.userCredential);
+ mCreationTimeInMs = source.mCreationTimeInMs;
+ mExpirationTimeInMs = source.mExpirationTimeInMs;
+ mRealm = source.mRealm;
+ mCheckAaaServerCertStatus = source.mCheckAaaServerCertStatus;
+ if (source.mUserCredential != null) {
+ mUserCredential = new UserCredential(source.mUserCredential);
}
- if (source.certCredential != null) {
- certCredential = new CertificateCredential(source.certCredential);
+ if (source.mCertCredential != null) {
+ mCertCredential = new CertificateCredential(source.mCertCredential);
}
- if (source.simCredential != null) {
- simCredential = new SimCredential(source.simCredential);
+ if (source.mSimCredential != null) {
+ mSimCredential = new SimCredential(source.mSimCredential);
}
- if (source.clientCertificateChain != null) {
- clientCertificateChain = Arrays.copyOf(source.clientCertificateChain,
- source.clientCertificateChain.length);
+ if (source.mClientCertificateChain != null) {
+ mClientCertificateChain = Arrays.copyOf(source.mClientCertificateChain,
+ source.mClientCertificateChain.length);
}
- caCertificate = source.caCertificate;
- clientPrivateKey = source.clientPrivateKey;
+ mCaCertificate = source.mCaCertificate;
+ mClientPrivateKey = source.mClientPrivateKey;
}
}
@@ -516,13 +709,16 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(realm);
- dest.writeParcelable(userCredential, flags);
- dest.writeParcelable(certCredential, flags);
- dest.writeParcelable(simCredential, flags);
- ParcelUtil.writeCertificate(dest, caCertificate);
- ParcelUtil.writeCertificates(dest, clientCertificateChain);
- ParcelUtil.writePrivateKey(dest, clientPrivateKey);
+ dest.writeLong(mCreationTimeInMs);
+ dest.writeLong(mExpirationTimeInMs);
+ dest.writeString(mRealm);
+ dest.writeInt(mCheckAaaServerCertStatus ? 1 : 0);
+ dest.writeParcelable(mUserCredential, flags);
+ dest.writeParcelable(mCertCredential, flags);
+ dest.writeParcelable(mSimCredential, flags);
+ ParcelUtil.writeCertificate(dest, mCaCertificate);
+ ParcelUtil.writeCertificates(dest, mClientCertificateChain);
+ ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
}
@Override
@@ -535,16 +731,26 @@ public final class Credential implements Parcelable {
}
Credential that = (Credential) thatObject;
- return TextUtils.equals(realm, that.realm) &&
- (userCredential == null ? that.userCredential == null :
- userCredential.equals(that.userCredential)) &&
- (certCredential == null ? that.certCredential == null :
- certCredential.equals(that.certCredential)) &&
- (simCredential == null ? that.simCredential == null :
- simCredential.equals(that.simCredential)) &&
- isX509CertificateEquals(caCertificate, that.caCertificate) &&
- isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) &&
- isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
+ return TextUtils.equals(mRealm, that.mRealm)
+ && mCreationTimeInMs == that.mCreationTimeInMs
+ && mExpirationTimeInMs == that.mExpirationTimeInMs
+ && mCheckAaaServerCertStatus == that.mCheckAaaServerCertStatus
+ && (mUserCredential == null ? that.mUserCredential == null
+ : mUserCredential.equals(that.mUserCredential))
+ && (mCertCredential == null ? that.mCertCredential == null
+ : mCertCredential.equals(that.mCertCredential))
+ && (mSimCredential == null ? that.mSimCredential == null
+ : mSimCredential.equals(that.mSimCredential))
+ && isX509CertificateEquals(mCaCertificate, that.mCaCertificate)
+ && isX509CertificatesEquals(mClientCertificateChain, that.mClientCertificateChain)
+ && isPrivateKeyEquals(mClientPrivateKey, that.mClientPrivateKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRealm, mCreationTimeInMs, mExpirationTimeInMs,
+ mCheckAaaServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
+ mCaCertificate, mClientCertificateChain, mClientPrivateKey);
}
/**
@@ -553,25 +759,26 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (TextUtils.isEmpty(realm)) {
+ if (TextUtils.isEmpty(mRealm)) {
Log.d(TAG, "Missing realm");
return false;
}
- if (realm.length() > MAX_REALM_LENGTH) {
- Log.d(TAG, "realm exceeding maximum length: " + realm.length());
+ if (mRealm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) {
+ Log.d(TAG, "realm exceeding maximum length: "
+ + mRealm.getBytes(StandardCharsets.UTF_8).length);
return false;
}
// Verify the credential.
- if (userCredential != null) {
+ if (mUserCredential != null) {
if (!verifyUserCredential()) {
return false;
}
- } else if (certCredential != null) {
+ } else if (mCertCredential != null) {
if (!verifyCertCredential()) {
return false;
}
- } else if (simCredential != null) {
+ } else if (mSimCredential != null) {
if (!verifySimCredential()) {
return false;
}
@@ -588,13 +795,16 @@ public final class Credential implements Parcelable {
@Override
public Credential createFromParcel(Parcel in) {
Credential credential = new Credential();
- credential.realm = in.readString();
- credential.userCredential = in.readParcelable(null);
- credential.certCredential = in.readParcelable(null);
- credential.simCredential = in.readParcelable(null);
- credential.caCertificate = ParcelUtil.readCertificate(in);
- credential.clientCertificateChain = ParcelUtil.readCertificates(in);
- credential.clientPrivateKey = ParcelUtil.readPrivateKey(in);
+ credential.setCreationTimeInMs(in.readLong());
+ credential.setExpirationTimeInMs(in.readLong());
+ credential.setRealm(in.readString());
+ credential.setCheckAaaServerCertStatus(in.readInt() != 0);
+ credential.setUserCredential(in.readParcelable(null));
+ credential.setCertCredential(in.readParcelable(null));
+ credential.setSimCredential(in.readParcelable(null));
+ credential.setCaCertificate(ParcelUtil.readCertificate(in));
+ credential.setClientCertificateChain(ParcelUtil.readCertificates(in));
+ credential.setClientPrivateKey(ParcelUtil.readPrivateKey(in));
return credential;
}
@@ -610,18 +820,18 @@ public final class Credential implements Parcelable {
* @return true if user credential is valid, false otherwise.
*/
private boolean verifyUserCredential() {
- if (userCredential == null) {
+ if (mUserCredential == null) {
Log.d(TAG, "Missing user credential");
return false;
}
- if (certCredential != null || simCredential != null) {
+ if (mCertCredential != null || mSimCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- if (!userCredential.validate()) {
+ if (!mUserCredential.validate()) {
return false;
}
- if (caCertificate == null) {
+ if (mCaCertificate == null) {
Log.d(TAG, "Missing CA Certificate for user credential");
return false;
}
@@ -635,32 +845,32 @@ public final class Credential implements Parcelable {
* @return true if certificate credential is valid, false otherwise.
*/
private boolean verifyCertCredential() {
- if (certCredential == null) {
+ if (mCertCredential == null) {
Log.d(TAG, "Missing certificate credential");
return false;
}
- if (userCredential != null || simCredential != null) {
+ if (mUserCredential != null || mSimCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- if (!certCredential.validate()) {
+ if (!mCertCredential.validate()) {
return false;
}
// Verify required key and certificates for certificate credential.
- if (caCertificate == null) {
+ if (mCaCertificate == null) {
Log.d(TAG, "Missing CA Certificate for certificate credential");
return false;
}
- if (clientPrivateKey == null) {
+ if (mClientPrivateKey == null) {
Log.d(TAG, "Missing client private key for certificate credential");
return false;
}
try {
// Verify SHA-256 fingerprint for client certificate.
- if (!verifySha256Fingerprint(clientCertificateChain,
- certCredential.certSha256FingerPrint)) {
+ if (!verifySha256Fingerprint(mClientCertificateChain,
+ mCertCredential.getCertSha256Fingerprint())) {
Log.d(TAG, "SHA-256 fingerprint mismatch");
return false;
}
@@ -678,15 +888,15 @@ public final class Credential implements Parcelable {
* @return true if SIM credential is valid, false otherwise.
*/
private boolean verifySimCredential() {
- if (simCredential == null) {
+ if (mSimCredential == null) {
Log.d(TAG, "Missing SIM credential");
return false;
}
- if (userCredential != null || certCredential != null) {
+ if (mUserCredential != null || mCertCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- return simCredential.validate();
+ return mSimCredential.validate();
}
private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) {
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
deleted file mode 100644
index d4a5792d93fc..000000000000
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.pps;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Class representing HomeSP subtree in PerProviderSubscription (PPS)
- * Management Object (MO) tree.
- *
- * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
- * Release 2 Technical Specification.
- *
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
- * @hide
- */
-public final class HomeSP implements Parcelable {
- private static final String TAG = "HomeSP";
-
- /**
- * FQDN (Fully Qualified Domain Name) of this home service provider.
- */
- public String fqdn = null;
-
- /**
- * Friendly name of this home service provider.
- */
- public String friendlyName = null;
-
- /**
- * List of Organization Identifiers (OIs) identifying a roaming consortium of
- * which this provider is a member.
- */
- public long[] roamingConsortiumOIs = null;
-
- /**
- * Constructor for creating HomeSP with default values.
- */
- public HomeSP() {}
-
- /**
- * Copy constructor.
- *
- * @param source The source to copy from
- */
- public HomeSP(HomeSP source) {
- if (source != null) {
- fqdn = source.fqdn;
- friendlyName = source.friendlyName;
- if (source.roamingConsortiumOIs != null) {
- roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
- source.roamingConsortiumOIs.length);
- }
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(fqdn);
- dest.writeString(friendlyName);
- dest.writeLongArray(roamingConsortiumOIs);
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (!(thatObject instanceof HomeSP)) {
- return false;
- }
- HomeSP that = (HomeSP) thatObject;
-
- return TextUtils.equals(fqdn, that.fqdn) &&
- TextUtils.equals(friendlyName, that.friendlyName) &&
- Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
- }
-
- /**
- * Validate HomeSP data.
- *
- * @return true on success or false on failure
- */
- public boolean validate() {
- if (TextUtils.isEmpty(fqdn)) {
- Log.d(TAG, "Missing FQDN");
- return false;
- }
- if (TextUtils.isEmpty(friendlyName)) {
- Log.d(TAG, "Missing friendly name");
- return false;
- }
- return true;
- }
-
- public static final Creator<HomeSP> CREATOR =
- new Creator<HomeSP>() {
- @Override
- public HomeSP createFromParcel(Parcel in) {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = in.readString();
- homeSp.friendlyName = in.readString();
- homeSp.roamingConsortiumOIs = in.createLongArray();
- return homeSp;
- }
-
- @Override
- public HomeSP[] newArray(int size) {
- return new HomeSP[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
index 62d5603b5982..6d343bde7081 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
@@ -16,4 +16,4 @@
package android.net.wifi.hotspot2.pps;
-parcelable HomeSP;
+parcelable HomeSp;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
new file mode 100644
index 000000000000..7a4612916bb9
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class representing HomeSP subtree in PerProviderSubscription (PPS)
+ * Management Object (MO) tree.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class HomeSp implements Parcelable {
+ private static final String TAG = "HomeSp";
+
+ /**
+ * Maximum number of bytes allowed for a SSID.
+ */
+ private static final int MAX_SSID_BYTES = 32;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * FQDN (Fully Qualified Domain Name) of this home service provider.
+ */
+ private String mFqdn = null;
+ public void setFqdn(String fqdn) {
+ mFqdn = fqdn;
+ }
+ public String getFqdn() {
+ return mFqdn;
+ }
+
+ /**
+ * Friendly name of this home service provider.
+ */
+ private String mFriendlyName = null;
+ public void setFriendlyName(String friendlyName) {
+ mFriendlyName = friendlyName;
+ }
+ public String getFriendlyName() {
+ return mFriendlyName;
+ }
+
+ /**
+ * Icon URL of this home service provider.
+ */
+ private String mIconUrl = null;
+ public void setIconUrl(String iconUrl) {
+ mIconUrl = iconUrl;
+ }
+ public String getIconUrl() {
+ return mIconUrl;
+ }
+
+ /**
+ * <SSID, HESSID> duple of the networks that are consider home networks.
+ *
+ * According to the Section 9.1.2 of the Hotspot 2.0 Release 2 Technical Specification,
+ * all nodes in the PSS MO are encoded using UTF-8 unless stated otherwise. Thus, the SSID
+ * string is assumed to be encoded using UTF-8.
+ */
+ private Map<String, Long> mHomeNetworkIds = null;
+ public void setHomeNetworkIds(Map<String, Long> homeNetworkIds) {
+ mHomeNetworkIds = homeNetworkIds;
+ }
+ public Map<String, Long> getHomeNetworkIds() {
+ return mHomeNetworkIds;
+ }
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Every Organization Identifiers (OIs) in this list are required to match an OI in the
+ * the Roaming Consortium advertised by a Hotspot, in order to consider this provider
+ * as a member of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ private long[] mMatchAllOis = null;
+ public void setMatchAllOis(long[] matchAllOis) {
+ mMatchAllOis = matchAllOis;
+ }
+ public long[] getMatchAllOis() {
+ return mMatchAllOis;
+ }
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Matching of any Organization Identifiers (OIs) in this list with an OI in the
+ * Roaming Consortium advertised by a Hotspot, will consider this provider as a member
+ * of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
+ * only be used for matching if {@link #mMatchAllOIs} is null or empty.
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ private long[] mMatchAnyOis = null;
+ public void setMatchAnyOis(long[] matchAnyOis) {
+ mMatchAnyOis = matchAnyOis;
+ }
+ public long[] getMatchAnysOis() {
+ return mMatchAnyOis;
+ }
+
+ /**
+ * List of FQDN (Fully Qualified Domain Name) of partner providers.
+ * These providers should also be regarded as home Hotspot operators.
+ * This relationship is most likely achieved via a commercial agreement or
+ * operator merges between the providers.
+ */
+ private String[] mOtherHomePartners = null;
+ public void setOtherHomePartners(String[] otherHomePartners) {
+ mOtherHomePartners = otherHomePartners;
+ }
+ public String[] getOtherHomePartners() {
+ return mOtherHomePartners;
+ }
+
+ /**
+ * List of Organization Identifiers (OIs) identifying a roaming consortium of
+ * which this provider is a member.
+ */
+ private long[] mRoamingConsortiumOis = null;
+ public void setRoamingConsortiumOis(long[] roamingConsortiumOis) {
+ mRoamingConsortiumOis = roamingConsortiumOis;
+ }
+ public long[] getRoamingConsortiumOis() {
+ return mRoamingConsortiumOis;
+ }
+
+ /**
+ * Constructor for creating HomeSp with default values.
+ */
+ public HomeSp() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public HomeSp(HomeSp source) {
+ if (source == null) {
+ return;
+ }
+ mFqdn = source.mFqdn;
+ mFriendlyName = source.mFriendlyName;
+ mIconUrl = source.mIconUrl;
+ if (source.mHomeNetworkIds != null) {
+ mHomeNetworkIds = Collections.unmodifiableMap(source.mHomeNetworkIds);
+ }
+ if (source.mMatchAllOis != null) {
+ mMatchAllOis = Arrays.copyOf(source.mMatchAllOis, source.mMatchAllOis.length);
+ }
+ if (source.mMatchAnyOis != null) {
+ mMatchAnyOis = Arrays.copyOf(source.mMatchAnyOis, source.mMatchAnyOis.length);
+ }
+ if (source.mOtherHomePartners != null) {
+ mOtherHomePartners = Arrays.copyOf(source.mOtherHomePartners,
+ source.mOtherHomePartners.length);
+ }
+ if (source.mRoamingConsortiumOis != null) {
+ mRoamingConsortiumOis = Arrays.copyOf(source.mRoamingConsortiumOis,
+ source.mRoamingConsortiumOis.length);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFqdn);
+ dest.writeString(mFriendlyName);
+ dest.writeString(mIconUrl);
+ writeHomeNetworkIds(dest, mHomeNetworkIds);
+ dest.writeLongArray(mMatchAllOis);
+ dest.writeLongArray(mMatchAnyOis);
+ dest.writeStringArray(mOtherHomePartners);
+ dest.writeLongArray(mRoamingConsortiumOis);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof HomeSp)) {
+ return false;
+ }
+ HomeSp that = (HomeSp) thatObject;
+
+ return TextUtils.equals(mFqdn, that.mFqdn)
+ && TextUtils.equals(mFriendlyName, that.mFriendlyName)
+ && TextUtils.equals(mIconUrl, that.mIconUrl)
+ && (mHomeNetworkIds == null ? that.mHomeNetworkIds == null
+ : mHomeNetworkIds.equals(that.mHomeNetworkIds))
+ && Arrays.equals(mMatchAllOis, that.mMatchAllOis)
+ && Arrays.equals(mMatchAnyOis, that.mMatchAnyOis)
+ && Arrays.equals(mOtherHomePartners, that.mOtherHomePartners)
+ && Arrays.equals(mRoamingConsortiumOis, that.mRoamingConsortiumOis);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
+ mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
+ }
+
+ /**
+ * Validate HomeSp data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(mFqdn)) {
+ Log.d(TAG, "Missing FQDN");
+ return false;
+ }
+ if (TextUtils.isEmpty(mFriendlyName)) {
+ Log.d(TAG, "Missing friendly name");
+ return false;
+ }
+ // Verify SSIDs specified in the NetworkID
+ if (mHomeNetworkIds != null) {
+ for (Map.Entry<String, Long> entry : mHomeNetworkIds.entrySet()) {
+ if (entry.getKey() == null ||
+ entry.getKey().getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
+ Log.d(TAG, "Invalid SSID in HomeNetworkIDs");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static final Creator<HomeSp> CREATOR =
+ new Creator<HomeSp>() {
+ @Override
+ public HomeSp createFromParcel(Parcel in) {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn(in.readString());
+ homeSp.setFriendlyName(in.readString());
+ homeSp.setIconUrl(in.readString());
+ homeSp.setHomeNetworkIds(readHomeNetworkIds(in));
+ homeSp.setMatchAllOis(in.createLongArray());
+ homeSp.setMatchAnyOis(in.createLongArray());
+ homeSp.setOtherHomePartners(in.createStringArray());
+ homeSp.setRoamingConsortiumOis(in.createLongArray());
+ return homeSp;
+ }
+
+ @Override
+ public HomeSp[] newArray(int size) {
+ return new HomeSp[size];
+ }
+
+ /**
+ * Helper function for reading a Home Network IDs map from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return Map of home network IDs
+ */
+ private Map<String, Long> readHomeNetworkIds(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<String, Long> networkIds = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String key = in.readString();
+ Long value = null;
+ long readValue = in.readLong();
+ if (readValue != NULL_VALUE) {
+ value = Long.valueOf(readValue);
+ }
+ networkIds.put(key, value);
+ }
+ return networkIds;
+ }
+ };
+
+ /**
+ * Helper function for writing Home Network IDs map to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param networkIds The map of home network IDs
+ */
+ private static void writeHomeNetworkIds(Parcel dest, Map<String, Long> networkIds) {
+ if (networkIds == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(networkIds.size());
+ for (Map.Entry<String, Long> entry : networkIds.entrySet()) {
+ dest.writeString(entry.getKey());
+ if (entry.getValue() == null) {
+ dest.writeLong(NULL_VALUE);
+ } else {
+ dest.writeLong(entry.getValue());
+ }
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl b/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
new file mode 100644
index 000000000000..e923f1f0fee8
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+parcelable Policy;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
new file mode 100644
index 000000000000..caca0e4bd1d2
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -0,0 +1,539 @@
+/**
+ * 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.net.wifi.hotspot2.pps;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class representing Policy subtree in PerProviderSubscription (PPS)
+ * Management Object (MO) tree.
+ *
+ * The Policy specifies additional criteria for Passpoint network selections, such as preferred
+ * roaming partner, minimum backhaul bandwidth, and etc. It also provides the meta data for
+ * updating the policy.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class Policy implements Parcelable {
+ private static final String TAG = "Policy";
+
+ /**
+ * Maximum number of SSIDs in the exclusion list.
+ */
+ private static final int MAX_EXCLUSION_SSIDS = 128;
+
+ /**
+ * Maximum byte for SSID.
+ */
+ private static final int MAX_SSID_BYTES = 32;
+
+ /**
+ * Maximum bytes for port string in {@link #requiredProtoPortMap}.
+ */
+ private static final int MAX_PORT_STRING_BYTES = 64;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * Minimum available downlink/uplink bandwidth (in kilobits per second) required when
+ * selecting a network from home providers.
+ *
+ * The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
+ * and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mMinHomeDownlinkBandwidth = Long.MIN_VALUE;
+ public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
+ mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
+ }
+ public long getMinHomeDownlinkBandWidht() {
+ return mMinHomeDownlinkBandwidth;
+ }
+ private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
+ public void setMinHomeUplinkBandwidth(long minHomeUplinkBandwidth) {
+ mMinHomeUplinkBandwidth = minHomeUplinkBandwidth;
+ }
+ public long getMinHomeUplinkBandwidth() {
+ return mMinHomeUplinkBandwidth;
+ }
+
+ /**
+ * Minimum available downlink/uplink bandwidth (in kilobits per second) required when
+ * selecting a network from roaming providers.
+ *
+ * The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
+ * and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mMinRoamingDownlinkBandwidth = Long.MIN_VALUE;
+ public void setMinRoamingDownlinkBandwidth(long minRoamingDownlinkBandwidth) {
+ mMinRoamingDownlinkBandwidth = minRoamingDownlinkBandwidth;
+ }
+ public long getMinRoamingDownlinkBandwidth() {
+ return mMinRoamingDownlinkBandwidth;
+ }
+ private long mMinRoamingUplinkBandwidth = Long.MIN_VALUE;
+ public void setMinRoamingUplinkBandwidth(long minRoamingUplinkBandwidth) {
+ mMinRoamingUplinkBandwidth = minRoamingUplinkBandwidth;
+ }
+ public long getMinRoamingUplinkBandwidth() {
+ return mMinRoamingUplinkBandwidth;
+ }
+
+ /**
+ * List of SSIDs that are not preferred by the Home SP.
+ */
+ private String[] mExcludedSsidList = null;
+ public void setExcludedSsidList(String[] excludedSsidList) {
+ mExcludedSsidList = excludedSsidList;
+ }
+ public String[] getExcludedSsidList() {
+ return mExcludedSsidList;
+ }
+
+ /**
+ * List of IP protocol and port number required by one or more operator supported application.
+ * The port string contained one or more port numbers delimited by ",".
+ */
+ private Map<Integer, String> mRequiredProtoPortMap = null;
+ public void setRequiredProtoPortMap(Map<Integer, String> requiredProtoPortMap) {
+ mRequiredProtoPortMap = requiredProtoPortMap;
+ }
+ public Map<Integer, String> getRequiredProtoPortMap() {
+ return mRequiredProtoPortMap;
+ }
+
+ /**
+ * This specifies the maximum acceptable BSS load policy. This is used to prevent device
+ * from joining an AP whose channel is overly congested with traffic.
+ * Using Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mMaximumBssLoadValue = Integer.MIN_VALUE;
+ public void setMaximumBssLoadValue(int maximumBssLoadValue) {
+ mMaximumBssLoadValue = maximumBssLoadValue;
+ }
+ public int getMaximumBssLoadValue() {
+ return mMaximumBssLoadValue;
+ }
+
+ /**
+ * Policy associated with a roaming provider. This specifies a priority associated
+ * with a roaming provider for given list of countries.
+ *
+ * Contains field under PerProviderSubscription/Policy/PreferredRoamingPartnerList.
+ */
+ public static final class RoamingPartner implements Parcelable {
+ /**
+ * FQDN of the roaming partner.
+ */
+ private String mFqdn = null;
+ public void setFqdn(String fqdn) {
+ mFqdn = fqdn;
+ }
+ public String getFqdn() {
+ return mFqdn;
+ }
+
+ /**
+ * Flag indicating the exact match of FQDN is required for FQDN matching.
+ *
+ * When this flag is set to false, sub-domain matching is used. For example, when
+ * {@link #fqdn} s set to "example.com", "host.example.com" would be a match.
+ */
+ private boolean mFqdnExactMatch = false;
+ public void setFqdnExactMatch(boolean fqdnExactMatch) {
+ mFqdnExactMatch = fqdnExactMatch;
+ }
+ public boolean getFqdnExactMatch() {
+ return mFqdnExactMatch;
+ }
+
+ /**
+ * Priority associated with this roaming partner policy.
+ * Using Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mPriority = Integer.MIN_VALUE;
+ public void setPriority(int priority) {
+ mPriority = priority;
+ }
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * A string contained One or more, comma delimited (i.e., ",") ISO/IEC 3166-1 two
+ * character country strings or the country-independent value, "*".
+ */
+ private String mCountries = null;
+ public void setCountries(String countries) {
+ mCountries = countries;
+ }
+ public String getCountries() {
+ return mCountries;
+ }
+
+ public RoamingPartner() {}
+
+ public RoamingPartner(RoamingPartner source) {
+ if (source != null) {
+ mFqdn = source.mFqdn;
+ mFqdnExactMatch = source.mFqdnExactMatch;
+ mPriority = source.mPriority;
+ mCountries = source.mCountries;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFqdn);
+ dest.writeInt(mFqdnExactMatch ? 1 : 0);
+ dest.writeInt(mPriority);
+ dest.writeString(mCountries);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof RoamingPartner)) {
+ return false;
+ }
+
+ RoamingPartner that = (RoamingPartner) thatObject;
+ return TextUtils.equals(mFqdn, that.mFqdn)
+ && mFqdnExactMatch == that.mFqdnExactMatch
+ && mPriority == that.mPriority
+ && TextUtils.equals(mCountries, that.mCountries);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFqdn, mFqdnExactMatch, mPriority, mCountries);
+ }
+
+ /**
+ * Validate RoamingParnter data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(mFqdn)) {
+ Log.d(TAG, "Missing FQDN");
+ return false;
+ }
+ if (TextUtils.isEmpty(mCountries)) {
+ Log.d(TAG, "Missing countries");
+ return false;
+ }
+ return true;
+ }
+
+ public static final Creator<RoamingPartner> CREATOR =
+ new Creator<RoamingPartner>() {
+ @Override
+ public RoamingPartner createFromParcel(Parcel in) {
+ RoamingPartner roamingPartner = new RoamingPartner();
+ roamingPartner.setFqdn(in.readString());
+ roamingPartner.setFqdnExactMatch(in.readInt() != 0);
+ roamingPartner.setPriority(in.readInt());
+ roamingPartner.setCountries(in.readString());
+ return roamingPartner;
+ }
+
+ @Override
+ public RoamingPartner[] newArray(int size) {
+ return new RoamingPartner[size];
+ }
+ };
+ }
+ private List<RoamingPartner> mPreferredRoamingPartnerList = null;
+ public void setPreferredRoamingPartnerList(List<RoamingPartner> partnerList) {
+ mPreferredRoamingPartnerList = partnerList;
+ }
+ public List<RoamingPartner> getPreferredRoamingPartnerList() {
+ return mPreferredRoamingPartnerList;
+ }
+
+ /**
+ * Meta data used for policy update.
+ */
+ private UpdateParameter mPolicyUpdate = null;
+ public void setPolicyUpdate(UpdateParameter policyUpdate) {
+ mPolicyUpdate = policyUpdate;
+ }
+ public UpdateParameter getPolicyUpdate() {
+ return mPolicyUpdate;
+ }
+
+ /**
+ * Constructor for creating Policy with default values.
+ */
+ public Policy() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public Policy(Policy source) {
+ if (source == null) {
+ return;
+ }
+ mMinHomeDownlinkBandwidth = source.mMinHomeDownlinkBandwidth;
+ mMinHomeUplinkBandwidth = source.mMinHomeUplinkBandwidth;
+ mMinRoamingDownlinkBandwidth = source.mMinRoamingDownlinkBandwidth;
+ mMinRoamingUplinkBandwidth = source.mMinRoamingUplinkBandwidth;
+ mMaximumBssLoadValue = source.mMaximumBssLoadValue;
+ if (source.mExcludedSsidList != null) {
+ mExcludedSsidList = Arrays.copyOf(source.mExcludedSsidList,
+ source.mExcludedSsidList.length);
+ }
+ if (source.mRequiredProtoPortMap != null) {
+ mRequiredProtoPortMap = Collections.unmodifiableMap(source.mRequiredProtoPortMap);
+ }
+ if (source.mPreferredRoamingPartnerList != null) {
+ mPreferredRoamingPartnerList = Collections.unmodifiableList(
+ source.mPreferredRoamingPartnerList);
+ }
+ if (source.mPolicyUpdate != null) {
+ mPolicyUpdate = new UpdateParameter(source.mPolicyUpdate);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mMinHomeDownlinkBandwidth);
+ dest.writeLong(mMinHomeUplinkBandwidth);
+ dest.writeLong(mMinRoamingDownlinkBandwidth);
+ dest.writeLong(mMinRoamingUplinkBandwidth);
+ dest.writeStringArray(mExcludedSsidList);
+ writeProtoPortMap(dest, mRequiredProtoPortMap);
+ dest.writeInt(mMaximumBssLoadValue);
+ writeRoamingPartnerList(dest, flags, mPreferredRoamingPartnerList);
+ dest.writeParcelable(mPolicyUpdate, flags);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof Policy)) {
+ return false;
+ }
+ Policy that = (Policy) thatObject;
+
+ return mMinHomeDownlinkBandwidth == that.mMinHomeDownlinkBandwidth
+ && mMinHomeUplinkBandwidth == that.mMinHomeUplinkBandwidth
+ && mMinRoamingDownlinkBandwidth == that.mMinRoamingDownlinkBandwidth
+ && mMinRoamingUplinkBandwidth == that.mMinRoamingUplinkBandwidth
+ && Arrays.equals(mExcludedSsidList, that.mExcludedSsidList)
+ && (mRequiredProtoPortMap == null ? that.mRequiredProtoPortMap == null
+ : mRequiredProtoPortMap.equals(that.mRequiredProtoPortMap))
+ && mMaximumBssLoadValue == that.mMaximumBssLoadValue
+ && (mPreferredRoamingPartnerList == null
+ ? that.mPreferredRoamingPartnerList == null
+ : mPreferredRoamingPartnerList.equals(that.mPreferredRoamingPartnerList))
+ && (mPolicyUpdate == null ? that.mPolicyUpdate == null
+ : mPolicyUpdate.equals(that.mPolicyUpdate));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMinHomeDownlinkBandwidth, mMinHomeUplinkBandwidth,
+ mMinRoamingDownlinkBandwidth, mMinRoamingUplinkBandwidth, mExcludedSsidList,
+ mRequiredProtoPortMap, mMaximumBssLoadValue, mPreferredRoamingPartnerList,
+ mPolicyUpdate);
+ }
+
+ /**
+ * Validate Policy data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (mPolicyUpdate == null) {
+ Log.d(TAG, "PolicyUpdate not specified");
+ return false;
+ }
+ if (!mPolicyUpdate.validate()) {
+ return false;
+ }
+
+ // Validate SSID exclusion list.
+ if (mExcludedSsidList != null) {
+ if (mExcludedSsidList.length > MAX_EXCLUSION_SSIDS) {
+ Log.d(TAG, "SSID exclusion list size exceeded the max: "
+ + mExcludedSsidList.length);
+ return false;
+ }
+ for (String ssid : mExcludedSsidList) {
+ if (ssid.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
+ Log.d(TAG, "Invalid SSID: " + ssid);
+ return false;
+ }
+ }
+ }
+ // Validate required protocol to port map.
+ if (mRequiredProtoPortMap != null) {
+ for (Map.Entry<Integer, String> entry : mRequiredProtoPortMap.entrySet()) {
+ String portNumber = entry.getValue();
+ if (portNumber.getBytes(StandardCharsets.UTF_8).length > MAX_PORT_STRING_BYTES) {
+ Log.d(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
+ return false;
+ }
+ }
+ }
+ // Validate preferred roaming partner list.
+ if (mPreferredRoamingPartnerList != null) {
+ for (RoamingPartner partner : mPreferredRoamingPartnerList) {
+ if (!partner.validate()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static final Creator<Policy> CREATOR =
+ new Creator<Policy>() {
+ @Override
+ public Policy createFromParcel(Parcel in) {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(in.readLong());
+ policy.setMinHomeUplinkBandwidth(in.readLong());
+ policy.setMinRoamingDownlinkBandwidth(in.readLong());
+ policy.setMinRoamingUplinkBandwidth(in.readLong());
+ policy.setExcludedSsidList(in.createStringArray());
+ policy.setRequiredProtoPortMap(readProtoPortMap(in));
+ policy.setMaximumBssLoadValue(in.readInt());
+ policy.setPreferredRoamingPartnerList(readRoamingPartnerList(in));
+ policy.setPolicyUpdate(in.readParcelable(null));
+ return policy;
+ }
+
+ @Override
+ public Policy[] newArray(int size) {
+ return new Policy[size];
+ }
+
+ /**
+ * Helper function for reading IP Protocol to Port Number map from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return Map of IP protocol to port number
+ */
+ private Map<Integer, String> readProtoPortMap(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<Integer, String> protoPortMap = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ int key = in.readInt();
+ String value = in.readString();
+ protoPortMap.put(key, value);
+ }
+ return protoPortMap;
+ }
+
+ /**
+ * Helper function for reading roaming partner list from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return List of roaming partners
+ */
+ private List<RoamingPartner> readRoamingPartnerList(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ List<RoamingPartner> partnerList = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ partnerList.add(in.readParcelable(null));
+ }
+ return partnerList;
+ }
+
+ };
+
+ /**
+ * Helper function for writing IP Protocol to Port Number map to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param protoPortMap The map to write
+ */
+ private static void writeProtoPortMap(Parcel dest, Map<Integer, String> protoPortMap) {
+ if (protoPortMap == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(protoPortMap.size());
+ for (Map.Entry<Integer, String> entry : protoPortMap.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeString(entry.getValue());
+ }
+ }
+
+ /**
+ * Helper function for writing roaming partner list to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param flags The flag about how the object should be written
+ * @param partnerList The partner list to write
+ */
+ private static void writeRoamingPartnerList(Parcel dest, int flags,
+ List<RoamingPartner> partnerList) {
+ if (partnerList == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(partnerList.size());
+ for (RoamingPartner partner : partnerList) {
+ dest.writeParcelable(partner, flags);
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
new file mode 100644
index 000000000000..701db479076a
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+parcelable UpdateParameter;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
new file mode 100644
index 000000000000..70264b0e625a
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
@@ -0,0 +1,357 @@
+/**
+ * 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.net.wifi.hotspot2.pps;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Class representing configuration parameters for subscription or policy update in
+ * PerProviderSubscription (PPS) Management Object (MO) tree. This is used by both
+ * PerProviderSubscription/Policy/PolicyUpdate and PerProviderSubscription/SubscriptionUpdate
+ * subtree.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class UpdateParameter implements Parcelable {
+ private static final String TAG = "UpdateParameter";
+
+ /**
+ * Value indicating policy update is not applicable. Thus, never check with policy server
+ * for updates.
+ */
+ public static final long UPDATE_CHECK_INTERVAL_NEVER = 0xFFFFFFFFL;
+
+ /**
+ * Valid string for UpdateMethod.
+ */
+ public static final String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ public static final String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+
+ /**
+ * Valid string for Restriction.
+ */
+ public static final String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ public static final String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ public static final String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+
+ /**
+ * Maximum bytes for URI string.
+ */
+ private static final int MAX_URI_BYTES = 1023;
+
+ /**
+ * Maximum bytes for URI string.
+ */
+ private static final int MAX_URL_BYTES = 1023;
+
+ /**
+ * Maximum bytes for username.
+ */
+ private static final int MAX_USERNAME_BYTES = 63;
+
+ /**
+ * Maximum bytes for password.
+ */
+ private static final int MAX_PASSWORD_BYTES = 255;
+
+ /**
+ * Number of bytes for certificate SHA-256 fingerprint byte array.
+ */
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * This specifies how often the mobile device shall check with policy server for updates.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUpdateIntervalInMinutes = Long.MIN_VALUE;
+ public void setUpdateIntervalInMinutes(long updateIntervalInMinutes) {
+ mUpdateIntervalInMinutes = updateIntervalInMinutes;
+ }
+ public long getUpdateIntervalInMinutes() {
+ return mUpdateIntervalInMinutes;
+ }
+
+ /**
+ * The method used to update the policy. Permitted values are "OMA-DM-ClientInitiated"
+ * and "SPP-ClientInitiated".
+ */
+ private String mUpdateMethod = null;
+ public void setUpdateMethod(String updateMethod) {
+ mUpdateMethod = updateMethod;
+ }
+ public String getUpdateMethod() {
+ return mUpdateMethod;
+ }
+
+ /**
+ * This specifies the hotspots at which the subscription update is permitted. Permitted
+ * values are "HomeSP", "RoamingPartner", or "Unrestricted";
+ */
+ private String mRestriction = null;
+ public void setRestriction(String restriction) {
+ mRestriction = restriction;
+ }
+ public String getRestriction() {
+ return mRestriction;
+ }
+
+ /**
+ * The URI of the update server.
+ */
+ private String mServerUri = null;
+ public void setServerUri(String serverUri) {
+ mServerUri = serverUri;
+ }
+ public String getServerUri() {
+ return mServerUri;
+ }
+
+ /**
+ * Username used to authenticate with the policy server.
+ */
+ private String mUsername = null;
+ public void setUsername(String username) {
+ mUsername = username;
+ }
+ public String getUsername() {
+ return mUsername;
+ }
+
+ /**
+ * Base64 encoded password used to authenticate with the policy server.
+ */
+ private String mBase64EncodedPassword = null;
+ public void setBase64EncodedPassword(String password) {
+ mBase64EncodedPassword = password;
+ }
+ public String getBase64EncodedPassword() {
+ return mBase64EncodedPassword;
+ }
+
+ /**
+ * HTTPS URL for retrieving certificate for trust root. The trust root is used to validate
+ * policy server's identity.
+ */
+ private String mTrustRootCertUrl = null;
+ public void setTrustRootCertUrl(String trustRootCertUrl) {
+ mTrustRootCertUrl = trustRootCertUrl;
+ }
+ public String getTrustRootCertUrl() {
+ return mTrustRootCertUrl;
+ }
+
+ /**
+ * SHA-256 fingerprint of the certificate located at {@link #trustRootCertUrl}
+ */
+ private byte[] mTrustRootCertSha256Fingerprint = null;
+ public void setTrustRootCertSha256Fingerprint(byte[] fingerprint) {
+ mTrustRootCertSha256Fingerprint = fingerprint;
+ }
+ public byte[] getTrustRootCertSha256Fingerprint() {
+ return mTrustRootCertSha256Fingerprint;
+ }
+
+ /**
+ * Constructor for creating Policy with default values.
+ */
+ public UpdateParameter() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public UpdateParameter(UpdateParameter source) {
+ if (source == null) {
+ return;
+ }
+ mUpdateIntervalInMinutes = source.mUpdateIntervalInMinutes;
+ mUpdateMethod = source.mUpdateMethod;
+ mRestriction = source.mRestriction;
+ mServerUri = source.mServerUri;
+ mUsername = source.mUsername;
+ mBase64EncodedPassword = source.mBase64EncodedPassword;
+ mTrustRootCertUrl = source.mTrustRootCertUrl;
+ if (source.mTrustRootCertSha256Fingerprint != null) {
+ mTrustRootCertSha256Fingerprint = Arrays.copyOf(source.mTrustRootCertSha256Fingerprint,
+ source.mTrustRootCertSha256Fingerprint.length);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mUpdateIntervalInMinutes);
+ dest.writeString(mUpdateMethod);
+ dest.writeString(mRestriction);
+ dest.writeString(mServerUri);
+ dest.writeString(mUsername);
+ dest.writeString(mBase64EncodedPassword);
+ dest.writeString(mTrustRootCertUrl);
+ dest.writeByteArray(mTrustRootCertSha256Fingerprint);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof UpdateParameter)) {
+ return false;
+ }
+ UpdateParameter that = (UpdateParameter) thatObject;
+
+ return mUpdateIntervalInMinutes == that.mUpdateIntervalInMinutes
+ && TextUtils.equals(mUpdateMethod, that.mUpdateMethod)
+ && TextUtils.equals(mRestriction, that.mRestriction)
+ && TextUtils.equals(mServerUri, that.mServerUri)
+ && TextUtils.equals(mUsername, that.mUsername)
+ && TextUtils.equals(mBase64EncodedPassword, that.mBase64EncodedPassword)
+ && TextUtils.equals(mTrustRootCertUrl, that.mTrustRootCertUrl)
+ && Arrays.equals(mTrustRootCertSha256Fingerprint,
+ that.mTrustRootCertSha256Fingerprint);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUpdateIntervalInMinutes, mUpdateMethod, mRestriction, mServerUri,
+ mUsername, mBase64EncodedPassword, mTrustRootCertUrl,
+ mTrustRootCertSha256Fingerprint);
+ }
+
+ /**
+ * Validate UpdateParameter data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (mUpdateIntervalInMinutes == Long.MIN_VALUE) {
+ Log.d(TAG, "Update interval not specified");
+ return false;
+ }
+ // Update not applicable.
+ if (mUpdateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
+ return true;
+ }
+
+ if (!TextUtils.equals(mUpdateMethod, UPDATE_METHOD_OMADM)
+ && !TextUtils.equals(mUpdateMethod, UPDATE_METHOD_SSP)) {
+ Log.d(TAG, "Unknown update method: " + mUpdateMethod);
+ return false;
+ }
+
+ if (!TextUtils.equals(mRestriction, UPDATE_RESTRICTION_HOMESP)
+ && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
+ && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
+ Log.d(TAG, "Unknown restriction: " + mRestriction);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mServerUri)) {
+ Log.d(TAG, "Missing update server URI");
+ return false;
+ }
+ if (mServerUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
+ Log.d(TAG, "URI bytes exceeded the max: "
+ + mServerUri.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mUsername)) {
+ Log.d(TAG, "Missing username");
+ return false;
+ }
+ if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+ Log.d(TAG, "Username bytes exceeded the max: "
+ + mUsername.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mBase64EncodedPassword)) {
+ Log.d(TAG, "Missing username");
+ return false;
+ }
+ if (mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+ Log.d(TAG, "Password bytes exceeded the max: "
+ + mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+ try {
+ Base64.decode(mBase64EncodedPassword, Base64.DEFAULT);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Invalid encoding for password: " + mBase64EncodedPassword);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mTrustRootCertUrl)) {
+ Log.d(TAG, "Missing trust root certificate URL");
+ return false;
+ }
+ if (mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
+ Log.d(TAG, "Trust root cert URL bytes exceeded the max: "
+ + mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (mTrustRootCertSha256Fingerprint == null) {
+ Log.d(TAG, "Missing trust root certificate SHA-256 fingerprint");
+ return false;
+ }
+ if (mTrustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
+ Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ + mTrustRootCertSha256Fingerprint.length);
+ return false;
+ }
+ return true;
+ }
+
+ public static final Creator<UpdateParameter> CREATOR =
+ new Creator<UpdateParameter>() {
+ @Override
+ public UpdateParameter createFromParcel(Parcel in) {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(in.readLong());
+ updateParam.setUpdateMethod(in.readString());
+ updateParam.setRestriction(in.readString());
+ updateParam.setServerUri(in.readString());
+ updateParam.setUsername(in.readString());
+ updateParam.setBase64EncodedPassword(in.readString());
+ updateParam.setTrustRootCertUrl(in.readString());
+ updateParam.setTrustRootCertSha256Fingerprint(in.createByteArray());
+ return updateParam;
+ }
+
+ @Override
+ public UpdateParameter[] newArray(int size) {
+ return new UpdateParameter[size];
+ }
+ };
+}
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
index 8c1eb0867298..995963d2b4cc 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -42,7 +42,7 @@ V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+VTJSbWx1WjJWeWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
index 6d86dd53eb76..3ddd09f91ff4 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -35,7 +35,7 @@ ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
-TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
+TmFtZT5DZXJ0U0hBMjU2RmluZ2VycHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
diff --git a/wifi/tests/assets/pps/PerProviderSubscription.xml b/wifi/tests/assets/pps/PerProviderSubscription.xml
index 53d38ad23b9b..7f2d95de95e9 100644
--- a/wifi/tests/assets/pps/PerProviderSubscription.xml
+++ b/wifi/tests/assets/pps/PerProviderSubscription.xml
@@ -8,6 +8,10 @@
</Type>
</RTProperties>
<Node>
+ <NodeName>UpdateIdentifier</NodeName>
+ <Value>12</Value>
+ </Node>
+ <Node>
<NodeName>i001</NodeName>
<Node>
<NodeName>HomeSP</NodeName>
@@ -23,14 +27,86 @@
<NodeName>RoamingConsortiumOI</NodeName>
<Value>112233,445566</Value>
</Node>
+ <Node>
+ <NodeName>IconURL</NodeName>
+ <Value>icon.test.com</Value>
+ </Node>
+ <Node>
+ <NodeName>NetworkID</NodeName>
+ <Node>
+ <NodeName>n001</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>TestSSID</Value>
+ </Node>
+ <Node>
+ <NodeName>HESSID</NodeName>
+ <Value>12345678</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>n002</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>NullHESSID</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>HomeOIList</NodeName>
+ <Node>
+ <NodeName>h001</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>11223344</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>true</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>h002</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>55667788</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>false</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>OtherHomePartners</NodeName>
+ <Node>
+ <NodeName>o001</NodeName>
+ <Node>
+ <NodeName>FQDN</NodeName>
+ <Value>other.fqdn.com</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
<Node>
<NodeName>Credential</NodeName>
<Node>
+ <NodeName>CreationDate</NodeName>
+ <Value>2016-01-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>ExpirationDate</NodeName>
+ <Value>2016-02-01T10:00:00Z</Value>
+ </Node>
+ <Node>
<NodeName>Realm</NodeName>
<Value>shaken.stirred.com</Value>
</Node>
<Node>
+ <NodeName>CheckAAAServerCertStatus</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>UsernamePassword</NodeName>
<Node>
<NodeName>Username</NodeName>
@@ -41,6 +117,18 @@
<Value>Ym9uZDAwNw==</Value>
</Node>
<Node>
+ <NodeName>MachineManaged</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
+ <NodeName>SoftTokenApp</NodeName>
+ <Value>TestApp</Value>
+ </Node>
+ <Node>
+ <NodeName>AbleToShare</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>EAPMethod</NodeName>
<Node>
<NodeName>EAPType</NodeName>
@@ -59,7 +147,7 @@
<Value>x509v3</Value>
</Node>
<Node>
- <NodeName>CertSHA256FingerPrint</NodeName>
+ <NodeName>CertSHA256Fingerprint</NodeName>
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
</Node>
</Node>
@@ -75,6 +163,237 @@
</Node>
</Node>
</Node>
+ <Node>
+ <NodeName>Policy</NodeName>
+ <Node>
+ <NodeName>PreferredRoamingPartnerList</NodeName>
+ <Node>
+ <NodeName>p001</NodeName>
+ <Node>
+ <NodeName>FQDN_Match</NodeName>
+ <Value>test1.fqdn.com,exactMatch</Value>
+ </Node>
+ <Node>
+ <NodeName>Priority</NodeName>
+ <Value>127</Value>
+ </Node>
+ <Node>
+ <NodeName>Country</NodeName>
+ <Value>us,fr</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>p002</NodeName>
+ <Node>
+ <NodeName>FQDN_Match</NodeName>
+ <Value>test2.fqdn.com,includeSubdomains</Value>
+ </Node>
+ <Node>
+ <NodeName>Priority</NodeName>
+ <Value>200</Value>
+ </Node>
+ <Node>
+ <NodeName>Country</NodeName>
+ <Value>*</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>MinBackhaulThreshold</NodeName>
+ <Node>
+ <NodeName>m001</NodeName>
+ <Node>
+ <NodeName>NetworkType</NodeName>
+ <Value>home</Value>
+ </Node>
+ <Node>
+ <NodeName>DLBandwidth</NodeName>
+ <Value>23412</Value>
+ </Node>
+ <Node>
+ <NodeName>ULBandwidth</NodeName>
+ <Value>9823</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>m002</NodeName>
+ <Node>
+ <NodeName>NetworkType</NodeName>
+ <Value>roaming</Value>
+ </Node>
+ <Node>
+ <NodeName>DLBandwidth</NodeName>
+ <Value>9271</Value>
+ </Node>
+ <Node>
+ <NodeName>ULBandwidth</NodeName>
+ <Value>2315</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>PolicyUpdate</NodeName>
+ <Node>
+ <NodeName>UpdateInterval</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UpdateMethod</NodeName>
+ <Value>OMA-DM-ClientInitiated</Value>
+ </Node>
+ <Node>
+ <NodeName>Restriction</NodeName>
+ <Value>HomeSP</Value>
+ </Node>
+ <Node>
+ <NodeName>URI</NodeName>
+ <Value>policy.update.com</Value>
+ </Node>
+ <Node>
+ <NodeName>UsernamePassword</NodeName>
+ <Node>
+ <NodeName>Username</NodeName>
+ <Value>updateUser</Value>
+ </Node>
+ <Node>
+ <NodeName>Password</NodeName>
+ <Value>updatePass</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>TrustRoot</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>update.cert.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SPExclusionList</NodeName>
+ <Node>
+ <NodeName>s001</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>excludeSSID</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>RequiredProtoPortTuple</NodeName>
+ <Node>
+ <NodeName>r001</NodeName>
+ <Node>
+ <NodeName>IPProtocol</NodeName>
+ <Value>12</Value>
+ </Node>
+ <Node>
+ <NodeName>PortNumber</NodeName>
+ <Value>34,92,234</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>MaximumBSSLoadValue</NodeName>
+ <Value>23</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>CredentialPriority</NodeName>
+ <Value>99</Value>
+ </Node>
+ <Node>
+ <NodeName>AAAServerTrustRoot</NodeName>
+ <Node>
+ <NodeName>a001</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>server1.trust.root.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SubscriptionUpdate</NodeName>
+ <Node>
+ <NodeName>UpdateInterval</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UpdateMethod</NodeName>
+ <Value>SSP-ClientInitiated</Value>
+ </Node>
+ <Node>
+ <NodeName>Restriction</NodeName>
+ <Value>RoamingPartner</Value>
+ </Node>
+ <Node>
+ <NodeName>URI</NodeName>
+ <Value>subscription.update.com</Value>
+ </Node>
+ <Node>
+ <NodeName>UsernamePassword</NodeName>
+ <Node>
+ <NodeName>Username</NodeName>
+ <Value>subscriptionUser</Value>
+ </Node>
+ <Node>
+ <NodeName>Password</NodeName>
+ <Value>subscriptionPass</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>TrustRoot</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>subscription.update.cert.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SubscriptionParameter</NodeName>
+ <Node>
+ <NodeName>CreationDate</NodeName>
+ <Value>2016-02-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>ExpirationDate</NodeName>
+ <Value>2016-03-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>TypeOfSubscription</NodeName>
+ <Value>Gold</Value>
+ </Node>
+ <Node>
+ <NodeName>UsageLimits</NodeName>
+ <Node>
+ <NodeName>DataLimit</NodeName>
+ <Value>921890</Value>
+ </Node>
+ <Node>
+ <NodeName>StartDate</NodeName>
+ <Value>2016-12-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>TimeLimit</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UsageTimePeriod</NodeName>
+ <Value>99910</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
</Node>
</MgmtTree>
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 0e503d5e7139..fa546a565c86 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -87,6 +87,52 @@ public class WifiEnterpriseConfigTest {
}
@Test
+ public void testSetClientKeyEntryWithNull() {
+ mEnterpriseConfig.setClientKeyEntry(null, null);
+ assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
+ assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
+ assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
+ assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ }
+
+ @Test
+ public void testSetClientCertificateChain() {
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ X509Certificate cert0 = FakeKeys.CLIENT_CERT;
+ X509Certificate cert1 = FakeKeys.CA_CERT1;
+ X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
+ assertEquals(result.length, 2);
+ assertTrue(result[0] == cert0 && result[1] == cert1);
+ assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+ }
+
+ private boolean isClientCertificateChainInvalid(X509Certificate[] clientChain) {
+ boolean exceptionThrown = false;
+ try {
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ return exceptionThrown;
+ }
+
+ @Test
+ public void testSetInvalidClientCertificateChain() {
+ X509Certificate clientCert = FakeKeys.CLIENT_CERT;
+ X509Certificate caCert = FakeKeys.CA_CERT1;
+ assertTrue("Invalid client certificate",
+ isClientCertificateChainInvalid(new X509Certificate[] {caCert, caCert}));
+ assertTrue("Invalid CA certificate",
+ isClientCertificateChainInvalid(new X509Certificate[] {clientCert, clientCert}));
+ assertTrue("Both certificates invalid",
+ isClientCertificateChainInvalid(new X509Certificate[] {caCert, clientCert}));
+ }
+
+ @Test
public void testSaveSingleCaCertificateAlias() {
final String alias = "single_alias 0";
mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index 6095929758f0..56bb4375acdd 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -21,7 +21,7 @@ import static org.junit.Assert.assertTrue;
import android.net.wifi.FakeKeys;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
import android.test.suitebuilder.annotation.SmallTest;
import java.io.BufferedReader;
@@ -33,10 +33,10 @@ import java.util.Arrays;
import org.junit.Test;
/**
- * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}.
+ * Unit tests for {@link android.net.wifi.hotspot2.ConfigParser}.
*/
@SmallTest
-public class ConfigBuilderTest {
+public class ConfigParserTest {
/**
* Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a
* CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}.
@@ -83,27 +83,33 @@ public class ConfigBuilderTest {
PasspointConfiguration config = new PasspointConfiguration();
// HomeSP configuration.
- config.homeSp = new HomeSP();
- config.homeSp.friendlyName = "Century House";
- config.homeSp.fqdn = "mi6.co.uk";
- config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFriendlyName("Century House");
+ homeSp.setFqdn("mi6.co.uk");
+ homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
+ config.setHomeSp(homeSp);
// Credential configuration.
- config.credential = new Credential();
- config.credential.realm = "shaken.stirred.com";
- config.credential.userCredential = new Credential.UserCredential();
- config.credential.userCredential.username = "james";
- config.credential.userCredential.password = "Ym9uZDAwNw==";
- config.credential.userCredential.eapType = 21;
- config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
- config.credential.certCredential = new Credential.CertificateCredential();
- config.credential.certCredential.certType = "x509v3";
- config.credential.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
- config.credential.simCredential = new Credential.SimCredential();
- config.credential.simCredential.imsi = "imsi";
- config.credential.simCredential.eapType = 24;
- config.credential.caCertificate = FakeKeys.CA_CERT0;
+ Credential credential = new Credential();
+ credential.setRealm("shaken.stirred.com");
+ Credential.UserCredential userCredential = new Credential.UserCredential();
+ userCredential.setUsername("james");
+ userCredential.setPassword("Ym9uZDAwNw==");
+ userCredential.setEapType(21);
+ userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+ credential.setUserCredential(userCredential);
+ Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+ certCredential.setCertType("x509v3");
+ byte[] certSha256Fingerprint = new byte[32];
+ Arrays.fill(certSha256Fingerprint, (byte)0x1f);
+ certCredential.setCertSha256Fingerprint(certSha256Fingerprint);
+ credential.setCertCredential(certCredential);
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("imsi");
+ simCredential.setEapType(24);
+ credential.setSimCredential(simCredential);
+ credential.setCaCertificate(FakeKeys.CA_CERT0);
+ config.setCredential(credential);
return config;
}
@@ -117,7 +123,7 @@ public class ConfigBuilderTest {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
PasspointConfiguration actualConfig =
- ConfigBuilder.buildPasspointConfig(
+ ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes());
assertTrue(actualConfig.equals(expectedConfig));
}
@@ -130,7 +136,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidMimeType() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/wifi-config", configStr.getBytes()));
}
@@ -142,7 +148,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithUnencodedData() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -154,7 +160,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidPart() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -166,7 +172,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithMissingBoundary() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -179,7 +185,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidContentType() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -191,7 +197,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithoutPasspointProfile() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
} \ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 2350d3201171..7df4fcf56e8a 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -21,28 +21,40 @@ import static org.junit.Assert.assertTrue;
import android.net.wifi.EAPConstants;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
import org.junit.Test;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* Unit tests for {@link android.net.wifi.hotspot2.PasspointConfiguration}.
*/
@SmallTest
public class PasspointConfigurationTest {
+ private static final int MAX_URL_BYTES = 1023;
+ private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
/**
* Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
*
* @return {@link android.net.wifi.hotspot2.pps.HomeSP}
*/
- private static HomeSP createHomeSp() {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+ private static HomeSp createHomeSp() {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("fqdn");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
return homeSp;
}
@@ -53,19 +65,110 @@ public class PasspointConfigurationTest {
*/
private static Credential createCredential() {
Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = null;
- cred.certCredential = null;
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
- cred.caCertificate = null;
- cred.clientCertificateChain = null;
- cred.clientPrivateKey = null;
+ cred.setRealm("realm");
+ cred.setUserCredential(null);
+ cred.setCertCredential(null);
+ cred.setSimCredential(new Credential.SimCredential());
+ cred.getSimCredential().setImsi("1234*");
+ cred.getSimCredential().setEapType(EAPConstants.EAP_SIM);
+ cred.setCaCertificate(null);
+ cred.setClientCertificateChain(null);
+ cred.setClientPrivateKey(null);
return cred;
}
/**
+ * Helper function for creating a {@link Policy} for testing.
+ *
+ * @return {@link Policy}
+ */
+ private static Policy createPolicy() {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(123);
+ policy.setMinHomeUplinkBandwidth(345);
+ policy.setMinRoamingDownlinkBandwidth(567);
+ policy.setMinRoamingUplinkBandwidth(789);
+ policy.setMaximumBssLoadValue(12);
+ policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+ HashMap<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "23,342,123");
+ requiredProtoPortMap.put(23, "789,372,1235");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("partner1.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(12);
+ partner1.setCountries("us,jp");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("partner2.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(42);
+ partner2.setCountries("ca,fr");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(1712);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("username");
+ policyUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ policyUpdate.setTrustRootCertUrl("trust.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ policy.setPolicyUpdate(policyUpdate);
+
+ return policy;
+ }
+
+ private static UpdateParameter createSubscriptionUpdate() {
+ UpdateParameter subUpdate = new UpdateParameter();
+ subUpdate.setUpdateIntervalInMinutes(9021);
+ subUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+ subUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+ subUpdate.setServerUri("subscription.update.com");
+ subUpdate.setUsername("subUsername");
+ subUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT));
+ subUpdate.setTrustRootCertUrl("subscription.trust.cert.com");
+ subUpdate.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ return subUpdate;
+ }
+ /**
+ * Helper function for creating a {@link PasspointConfiguration} for testing.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ private static PasspointConfiguration createConfig() {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setHomeSp(createHomeSp());
+ config.setCredential(createCredential());
+ config.setPolicy(createPolicy());
+ config.setSubscriptionUpdate(createSubscriptionUpdate());
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("trustRoot.cert1.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ trustRootCertList.put("trustRoot.cert2.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ config.setUpdateIdentifier(1);
+ config.setCredentialPriority(120);
+ config.setSubscriptionCreationTimeInMs(231200);
+ config.setSubscriptionExpirationTimeInMs(2134232);
+ config.setSubscriptionType("Gold");
+ config.setUsageLimitUsageTimePeriodInMinutes(3600);
+ config.setUsageLimitStartTimeInMs(124214213);
+ config.setUsageLimitDataLimit(14121);
+ config.setUsageLimitTimeLimitInMinutes(78912);
+ return config;
+ }
+
+ /**
* Verify parcel write and read consistency for the given configuration.
*
* @param writeConfig The configuration to verify
@@ -92,39 +195,73 @@ public class PasspointConfigurationTest {
}
/**
- * Verify parcel read/write for a configuration that contained both HomeSP and Credential.
+ * Verify parcel read/write for a configuration that contained the full configuration.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithHomeSPAndCredential() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
- config.credential = createCredential();
+ public void verifyParcelWithFullConfiguration() throws Exception {
+ verifyParcel(createConfig());
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain HomeSP.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutHomeSP() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setHomeSp(null);
verifyParcel(config);
}
/**
- * Verify parcel read/write for a configuration that contained only HomeSP.
+ * Verify parcel read/write for a configuration that doesn't contain Credential.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithHomeSPOnly() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
+ public void verifyParcelWithoutCredential() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setCredential(null);
verifyParcel(config);
}
/**
- * Verify parcel read/write for a configuration that contained only Credential.
+ * Verify parcel read/write for a configuration that doesn't contain Policy.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithCredentialOnly() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.credential = createCredential();
+ public void verifyParcelWithoutPolicy() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setPolicy(null);
+ verifyParcel(config);
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain subscription update.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutSubscriptionUpdate() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setSubscriptionUpdate(null);
+ verifyParcel(config);
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain trust root certificate
+ * list.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutTrustRootCertList() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setTrustRootCertList(null);
verifyParcel(config);
}
@@ -140,43 +277,114 @@ public class PasspointConfigurationTest {
}
/**
+ * Verify that a configuration contained all fields is valid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateFullConfig() throws Exception {
+ PasspointConfiguration config = createConfig();
+ assertTrue(config.validate());
+ }
+
+ /**
* Verify that a configuration without Credential is invalid.
*
* @throws Exception
*/
@Test
public void validateConfigWithoutCredential() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
+ PasspointConfiguration config = createConfig();
+ config.setCredential(null);
assertFalse(config.validate());
}
/**
- * Verify that a a configuration without HomeSP is invalid.
+ * Verify that a configuration without HomeSP is invalid.
*
* @throws Exception
*/
@Test
public void validateConfigWithoutHomeSp() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.credential = createCredential();
+ PasspointConfiguration config = createConfig();
+ config.setHomeSp(null);
assertFalse(config.validate());
}
/**
- * Verify a valid configuration.
+ * Verify that a configuration without Policy is valid, since Policy configurations
+ * are optional (applied for Hotspot 2.0 Release only).
*
* @throws Exception
*/
@Test
- public void validateValidConfig() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
- config.credential = createCredential();
+ public void validateConfigWithoutPolicy() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setPolicy(null);
assertTrue(config.validate());
}
/**
+ * Verify that a configuration without subscription update is valid, since subscription
+ * update configurations are optional (applied for Hotspot 2.0 Release only).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithoutSubscriptionUpdate() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setSubscriptionUpdate(null);
+ assertTrue(config.validate());
+ }
+
+ /**
+ * Verify that a configuration with a trust root certificate URL exceeding the max size
+ * is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithInvalidTrustRootCertUrl() throws Exception {
+ PasspointConfiguration config = createConfig();
+ byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ Arrays.fill(rawUrlBytes, (byte) 'a');
+ trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8),
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+ }
+
+ /**
+ * Verify that a configuration with an invalid trust root certificate fingerprint is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithInvalidTrustRootCertFingerprint() throws Exception {
+ PasspointConfiguration config = createConfig();
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES - 1]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", null);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+ }
+
+ /**
* Verify that copy constructor works when pass in a null source.
*
* @throws Exception
@@ -195,9 +403,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateCopyConstructorWithValidSource() throws Exception {
- PasspointConfiguration sourceConfig = new PasspointConfiguration();
- sourceConfig.homeSp = createHomeSp();
- sourceConfig.credential = createCredential();
+ PasspointConfiguration sourceConfig = createConfig();
PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
assertTrue(copyConfig.equals(sourceConfig));
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
deleted file mode 100644
index 10b02677a15b..000000000000
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.omadm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.Arrays;
-
-/**
- * Unit tests for {@link android.net.wifi.hotspot2.omadm.PPSMOParser}.
- */
-@SmallTest
-public class PPSMOParserTest {
- private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
- private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
- "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
- private static final String PPS_MO_XML_FILE_DUPLICATE_VALUE =
- "assets/pps/PerProviderSubscription_DuplicateValue.xml";
- private static final String PPS_MO_XML_FILE_MISSING_VALUE =
- "assets/pps/PerProviderSubscription_MissingValue.xml";
- private static final String PPS_MO_XML_FILE_MISSING_NAME =
- "assets/pps/PerProviderSubscription_MissingName.xml";
- private static final String PPS_MO_XML_FILE_INVALID_NODE =
- "assets/pps/PerProviderSubscription_InvalidNode.xml";
- private static final String PPS_MO_XML_FILE_INVALID_NAME =
- "assets/pps/PerProviderSubscription_InvalidName.xml";
-
- /**
- * Read the content of the given resource file into a String.
- *
- * @param filename String name of the file
- * @return String
- * @throws IOException
- */
- private String loadResourceFile(String filename) throws IOException {
- InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
- BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- StringBuilder builder = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- builder.append(line).append("\n");
- }
-
- return builder.toString();
- }
-
- /**
- * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
- * XML file {@link #VALID_PPS_MO_XML_FILE}.
- *
- * @return {@link PasspointConfiguration}
- */
- private PasspointConfiguration generateConfigurationFromPPSMOTree() {
- PasspointConfiguration config = new PasspointConfiguration();
-
- // HomeSP configuration.
- config.homeSp = new HomeSP();
- config.homeSp.friendlyName = "Century House";
- config.homeSp.fqdn = "mi6.co.uk";
- config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
-
- // Credential configuration.
- config.credential = new Credential();
- config.credential.realm = "shaken.stirred.com";
- config.credential.userCredential = new Credential.UserCredential();
- config.credential.userCredential.username = "james";
- config.credential.userCredential.password = "Ym9uZDAwNw==";
- config.credential.userCredential.eapType = 21;
- config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
- config.credential.certCredential = new Credential.CertificateCredential();
- config.credential.certCredential.certType = "x509v3";
- config.credential.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
- config.credential.simCredential = new Credential.SimCredential();
- config.credential.simCredential.imsi = "imsi";
- config.credential.simCredential.eapType = 24;
- return config;
- }
-
- /**
- * Parse and verify all supported fields under PPS MO tree (currently only fields under
- * HomeSP and Credential subtree).
- *
- * @throws Exception
- */
- @Test
- public void parseValidPPSMOTree() throws Exception {
- String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
- PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
- PasspointConfiguration actualConfig = PPSMOParser.parseMOText(ppsMoTree);
- assertTrue(actualConfig.equals(expectedConfig));
- }
-
- @Test
- public void parseNullPPSMOTree() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(null));
- }
-
- @Test
- public void parseEmptyPPSMOTree() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(new String()));
- }
-
- @Test
- public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
- }
-
- @Test
- public void parsePPSMOTreeWithDuplicateValue() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
- }
-
- @Test
- public void parsePPSMOTreeWithMissingValue() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
- }
-
- @Test
- public void parsePPSMOTreeWithMissingName() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
- }
-
- @Test
- public void parsePPSMOTreeWithInvalidNode() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
- }
-
- @Test
- public void parsePPSMOTreeWithInvalidName() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
- }
-}
-
-
-
-
-
-
-
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
new file mode 100644
index 000000000000..7cd72f03dd1b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.omadm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.omadm.PpsMoParser}.
+ */
+@SmallTest
+public class PpsMoParserTest {
+ private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
+ private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
+ "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
+ private static final String PPS_MO_XML_FILE_DUPLICATE_VALUE =
+ "assets/pps/PerProviderSubscription_DuplicateValue.xml";
+ private static final String PPS_MO_XML_FILE_MISSING_VALUE =
+ "assets/pps/PerProviderSubscription_MissingValue.xml";
+ private static final String PPS_MO_XML_FILE_MISSING_NAME =
+ "assets/pps/PerProviderSubscription_MissingName.xml";
+ private static final String PPS_MO_XML_FILE_INVALID_NODE =
+ "assets/pps/PerProviderSubscription_InvalidNode.xml";
+ private static final String PPS_MO_XML_FILE_INVALID_NAME =
+ "assets/pps/PerProviderSubscription_InvalidName.xml";
+
+ /**
+ * Read the content of the given resource file into a String.
+ *
+ * @param filename String name of the file
+ * @return String
+ * @throws IOException
+ */
+ private String loadResourceFile(String filename) throws IOException {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line).append("\n");
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
+ * XML file {@link #VALID_PPS_MO_XML_FILE}.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ byte[] certFingerprint = new byte[32];
+ Arrays.fill(certFingerprint, (byte) 0x1f);
+
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setUpdateIdentifier(12);
+ config.setCredentialPriority(99);
+
+ // AAA Server trust root.
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("server1.trust.root.com", certFingerprint);
+ config.setTrustRootCertList(trustRootCertList);
+
+ // Subscription update.
+ UpdateParameter subscriptionUpdate = new UpdateParameter();
+ subscriptionUpdate.setUpdateIntervalInMinutes(120);
+ subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+ subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+ subscriptionUpdate.setServerUri("subscription.update.com");
+ subscriptionUpdate.setUsername("subscriptionUser");
+ subscriptionUpdate.setBase64EncodedPassword("subscriptionPass");
+ subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com");
+ subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+ config.setSubscriptionUpdate(subscriptionUpdate);
+
+ // Subscription parameters.
+ config.setSubscriptionCreationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+ config.setSubscriptionExpirationTimeInMs(format.parse("2016-03-01T10:00:00Z").getTime());
+ config.setSubscriptionType("Gold");
+ config.setUsageLimitDataLimit(921890);
+ config.setUsageLimitStartTimeInMs(format.parse("2016-12-01T10:00:00Z").getTime());
+ config.setUsageLimitTimeLimitInMinutes(120);
+ config.setUsageLimitUsageTimePeriodInMinutes(99910);
+
+ // HomeSP configuration.
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFriendlyName("Century House");
+ homeSp.setFqdn("mi6.co.uk");
+ homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
+ homeSp.setIconUrl("icon.test.com");
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ homeNetworkIds.put("TestSSID", 0x12345678L);
+ homeNetworkIds.put("NullHESSID", null);
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ homeSp.setMatchAllOis(new long[] {0x11223344});
+ homeSp.setMatchAnyOis(new long[] {0x55667788});
+ homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
+ config.setHomeSp(homeSp);
+
+ // Credential configuration.
+ Credential credential = new Credential();
+ credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime());
+ credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+ credential.setRealm("shaken.stirred.com");
+ credential.setCheckAaaServerCertStatus(true);
+ Credential.UserCredential userCredential = new Credential.UserCredential();
+ userCredential.setUsername("james");
+ userCredential.setPassword("Ym9uZDAwNw==");
+ userCredential.setMachineManaged(true);
+ userCredential.setSoftTokenApp("TestApp");
+ userCredential.setAbleToShare(true);
+ userCredential.setEapType(21);
+ userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+ credential.setUserCredential(userCredential);
+ Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+ certCredential.setCertType("x509v3");
+ certCredential.setCertSha256Fingerprint(certFingerprint);
+ credential.setCertCredential(certCredential);
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("imsi");
+ simCredential.setEapType(24);
+ credential.setSimCredential(simCredential);
+ config.setCredential(credential);
+
+ // Policy configuration.
+ Policy policy = new Policy();
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("test1.fqdn.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(127);
+ partner1.setCountries("us,fr");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("test2.fqdn.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(200);
+ partner2.setCountries("*");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+ policy.setMinHomeDownlinkBandwidth(23412);
+ policy.setMinHomeUplinkBandwidth(9823);
+ policy.setMinRoamingDownlinkBandwidth(9271);
+ policy.setMinRoamingUplinkBandwidth(2315);
+ policy.setExcludedSsidList(new String[] {"excludeSSID"});
+ Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "34,92,234");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ policy.setMaximumBssLoadValue(23);
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(120);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("updateUser");
+ policyUpdate.setBase64EncodedPassword("updatePass");
+ policyUpdate.setTrustRootCertUrl("update.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+ policy.setPolicyUpdate(policyUpdate);
+ config.setPolicy(policy);
+ return config;
+ }
+
+ /**
+ * Parse and verify all supported fields under PPS MO tree.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseValidPPSMOTree() throws Exception {
+ String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
+ PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
+ PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree);
+ assertTrue(actualConfig.equals(expectedConfig));
+ }
+
+ @Test
+ public void parseNullPPSMOTree() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(null));
+ }
+
+ @Test
+ public void parseEmptyPPSMOTree() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(new String()));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithDuplicateValue() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithMissingValue() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithMissingName() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithInvalidNode() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithInvalidName() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 9c8b749e1c93..c7ade002c826 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -23,10 +23,11 @@ import android.net.wifi.EAPConstants;
import android.net.wifi.FakeKeys;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -37,6 +38,17 @@ import org.junit.Test;
*/
@SmallTest
public class CredentialTest {
+ /**
+ * Helper function for generating Credential for testing.
+ *
+ * @param userCred Instance of UserCredential
+ * @param certCred Instance of CertificateCredential
+ * @param simCred Instance of SimCredential
+ * @param caCert CA certificate
+ * @param clientCertificateChain Chain of client certificates
+ * @param clientPrivateKey Client private key
+ * @return {@link Credential}
+ */
private static Credential createCredential(Credential.UserCredential userCred,
Credential.CertificateCredential certCred,
Credential.SimCredential simCred,
@@ -44,39 +56,61 @@ public class CredentialTest {
X509Certificate[] clientCertificateChain,
PrivateKey clientPrivateKey) {
Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = userCred;
- cred.certCredential = certCred;
- cred.simCredential = simCred;
- cred.caCertificate = caCert;
- cred.clientCertificateChain = clientCertificateChain;
- cred.clientPrivateKey = clientPrivateKey;
+ cred.setCreationTimeInMs(123455L);
+ cred.setExpirationTimeInMs(2310093L);
+ cred.setRealm("realm");
+ cred.setCheckAaaServerCertStatus(true);
+ cred.setUserCredential(userCred);
+ cred.setCertCredential(certCred);
+ cred.setSimCredential(simCred);
+ cred.setCaCertificate(caCert);
+ cred.setClientCertificateChain(clientCertificateChain);
+ cred.setClientPrivateKey(clientPrivateKey);
return cred;
}
- private static Credential createCredentialWithCertificateCredential() {
+ /**
+ * Helper function for generating certificate credential for testing.
+ *
+ * @return {@link Credential}
+ */
+ private static Credential createCredentialWithCertificateCredential()
+ throws NoSuchAlgorithmException, CertificateEncodingException {
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
- certCred.certType = "x509v3";
- certCred.certSha256FingerPrint = new byte[32];
+ certCred.setCertType("x509v3");
+ certCred.setCertSha256Fingerprint(
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()));
return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
}
+ /**
+ * Helper function for generating SIM credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithSimCredential() {
Credential.SimCredential simCred = new Credential.SimCredential();
- simCred.imsi = "1234*";
- simCred.eapType = EAPConstants.EAP_SIM;
+ simCred.setImsi("1234*");
+ simCred.setEapType(EAPConstants.EAP_SIM);
return createCredential(null, null, simCred, null, null, null);
}
+ /**
+ * Helper function for generating user credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithUserCredential() {
Credential.UserCredential userCred = new Credential.UserCredential();
- userCred.username = "username";
- userCred.password = "password";
- userCred.eapType = EAPConstants.EAP_TTLS;
- userCred.nonEapInnerMethod = "MS-CHAP";
- return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
- new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
+ userCred.setUsername("username");
+ userCred.setPassword("password");
+ userCred.setMachineManaged(true);
+ userCred.setAbleToShare(true);
+ userCred.setSoftTokenApp("TestApp");
+ userCred.setEapType(EAPConstants.EAP_TTLS);
+ userCred.setNonEapInnerMethod("MS-CHAP");
+ return createCredential(userCred, null, null, FakeKeys.CA_CERT0, null, null);
}
private static void verifyParcel(Credential writeCred) {
@@ -134,14 +168,7 @@ public class CredentialTest {
*/
@Test
public void validateUserCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
assertTrue(cred.validate());
}
@@ -152,13 +179,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutCaCert() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ Credential cred = createCredentialWithUserCredential();
+ cred.setCaCertificate(null);
assertFalse(cred.validate());
}
@@ -169,14 +191,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithEapTls() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setEapType(EAPConstants.EAP_TLS);
assertFalse(cred.validate());
}
@@ -188,13 +204,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutRealm() throws Exception {
- Credential cred = new Credential();
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.setRealm(null);
assertFalse(cred.validate());
}
@@ -205,13 +216,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutUsername() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setUsername(null);
assertFalse(cred.validate());
}
@@ -222,13 +228,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutPassword() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setPassword(null);
assertFalse(cred.validate());
}
@@ -239,13 +240,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutAuthMethod() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setNonEapInnerMethod(null);
assertFalse(cred.validate());
}
@@ -258,17 +254,7 @@ public class CredentialTest {
*/
@Test
public void validateCertCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
assertTrue(cred.validate());
}
@@ -278,16 +264,8 @@ public class CredentialTest {
* @throws Exception
*/
public void validateCertCredentialWithoutCaCert() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setCaCertificate(null);
assertFalse(cred.validate());
}
@@ -298,16 +276,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithoutClientCertChain() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setClientCertificateChain(null);
assertFalse(cred.validate());
}
@@ -318,16 +288,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithoutClientPrivateKey() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setClientPrivateKey(null);
assertFalse(cred.validate());
}
@@ -339,17 +301,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithMismatchFingerprint() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0);
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.getCertCredential().setCertSha256Fingerprint(new byte[32]);
assertFalse(cred.validate());
}
@@ -360,12 +313,7 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapSim() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
assertTrue(cred.validate());
}
@@ -376,12 +324,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapAka() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_AKA;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_AKA);
assertTrue(cred.validate());
}
@@ -392,12 +336,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapAkaPrime() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME);
assertTrue(cred.validate());
}
@@ -408,11 +348,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithoutIMSI() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setImsi(null);
assertFalse(cred.validate());
}
@@ -423,12 +360,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithInvalidIMSI() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "dummy";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setImsi("dummy");
assertFalse(cred.validate());
}
@@ -439,12 +372,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapTls() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_TLS;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_TLS);
assertFalse(cred.validate());
}
@@ -455,19 +384,12 @@ public class CredentialTest {
*/
@Test
public void validateCredentialWithUserAndSimCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup user credential with EAP-TTLS.
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
// Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("1234*");
+ simCredential.setEapType(EAPConstants.EAP_SIM);
+ cred.setSimCredential(simCredential);
assertFalse(cred.validate());
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
deleted file mode 100644
index c70799332b02..000000000000
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.wifi.hotspot2.pps;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSP}.
- */
-@SmallTest
-public class HomeSPTest {
- private static HomeSP createHomeSp() {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- return homeSp;
- }
-
- private static void verifyParcel(HomeSP writeHomeSp) throws Exception {
- Parcel parcel = Parcel.obtain();
- writeHomeSp.writeToParcel(parcel, 0);
-
- parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
- HomeSP readHomeSp = HomeSP.CREATOR.createFromParcel(parcel);
- assertTrue(readHomeSp.equals(writeHomeSp));
- }
-
- /**
- * Verify parcel read/write for an empty HomeSP.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithEmptyHomeSP() throws Exception {
- verifyParcel(new HomeSP());
- }
-
- /**
- * Verify parcel read/write for a valid HomeSP.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithValidHomeSP() throws Exception {
- verifyParcel(createHomeSp());
- }
-
- /**
- * Verify that a HomeSP is valid when both FQDN and Friendly Name
- * are provided.
- *
- * @throws Exception
- */
- @Test
- public void validateValidHomeSP() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- assertTrue(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is not valid when FQDN is not provided
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithoutFqdn() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.friendlyName = "friendly name";
- assertFalse(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is not valid when Friendly Name is not provided
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithoutFriendlyName() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- assertFalse(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is valid when the optional Roaming Consortium OIs are
- * provided.
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithRoamingConsoritums() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- assertTrue(homeSp.validate());
- }
-
- /**
- * Verify that copy constructor works when pass in a null source.
- *
- * @throws Exception
- */
- @Test
- public void validateCopyConstructorFromNullSource() throws Exception {
- HomeSP copySp = new HomeSP(null);
- HomeSP defaultSp = new HomeSP();
- assertTrue(copySp.equals(defaultSp));
- }
-
- /**
- * Verify that copy constructor works when pass in a valid source.
- *
- * @throws Exception
- */
- @Test
- public void validateCopyConstructorFromValidSource() throws Exception {
- HomeSP sourceSp = new HomeSP();
- sourceSp.fqdn = "fqdn";
- sourceSp.friendlyName = "friendlyName";
- sourceSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- HomeSP copySp = new HomeSP(sourceSp);
- assertTrue(copySp.equals(sourceSp));
- }
-}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
new file mode 100644
index 000000000000..c41c11f16acf
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSp}.
+ */
+@SmallTest
+public class HomeSpTest {
+
+ /**
+ * Helper function for creating a map of home network IDs for testing.
+ *
+ * @return Map of home network IDs
+ */
+ private static Map<String, Long> createHomeNetworkIds() {
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ homeNetworkIds.put("ssid", 0x1234L);
+ homeNetworkIds.put("nullhessid", null);
+ return homeNetworkIds;
+ }
+
+ /**
+ * Helper function for creating a HomeSp for testing.
+ *
+ * @param homeNetworkIds The map of home network IDs associated with HomeSp
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSp(Map<String, Long> homeNetworkIds) {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("fqdn");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setIconUrl("icon.url");
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ homeSp.setMatchAllOis(new long[] {0x11L, 0x22L});
+ homeSp.setMatchAnyOis(new long[] {0x33L, 0x44L});
+ homeSp.setOtherHomePartners(new String[] {"partner1", "partner2"});
+ homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
+ return homeSp;
+ }
+
+ /**
+ * Helper function for creating a HomeSp with home network IDs for testing.
+ *
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSpWithHomeNetworkIds() {
+ return createHomeSp(createHomeNetworkIds());
+ }
+
+ /**
+ * Helper function for creating a HomeSp without home network IDs for testing.
+ *
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSpWithoutHomeNetworkIds() {
+ return createHomeSp(null);
+ }
+
+ /**
+ * Helper function for verifying HomeSp after parcel write then read.
+ * @param writeHomeSp
+ * @throws Exception
+ */
+ private static void verifyParcel(HomeSp writeHomeSp) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ writeHomeSp.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ HomeSp readHomeSp = HomeSp.CREATOR.createFromParcel(parcel);
+ assertTrue(readHomeSp.equals(writeHomeSp));
+ }
+
+ /**
+ * Verify parcel read/write for an empty HomeSp.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyHomeSp() throws Exception {
+ verifyParcel(new HomeSp());
+ }
+
+ /**
+ * Verify parcel read/write for a HomeSp containing Home Network IDs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithHomeNetworkIds());
+ }
+
+ /**
+ * Verify parcel read/write for a HomeSp without Home Network IDs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithoutHomeNetworkIds());
+ }
+
+ /**
+ * Verify that a HomeSp is valid when both FQDN and Friendly Name
+ * are provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateValidHomeSp() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is not valid when FQDN is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFqdn() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ homeSp.setFqdn(null);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is not valid when Friendly Name is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFriendlyName() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ homeSp.setFriendlyName(null);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is valid when the optional Home Network IDs are
+ * not provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutHomeNetworkIds() throws Exception {
+ HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is invalid when the optional Home Network IDs
+ * contained an invalid SSID (exceeding maximum number of bytes).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithInvalidHomeNetworkIds() throws Exception {
+ HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+ // HomeNetworkID with SSID exceeding the maximum length.
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ byte[] rawSsidBytes = new byte[33];
+ Arrays.fill(rawSsidBytes, (byte) 'a');
+ homeNetworkIds.put(
+ StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that copy constructor works when pass in a null source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCopyConstructorFromNullSource() throws Exception {
+ HomeSp copySp = new HomeSp(null);
+ HomeSp defaultSp = new HomeSp();
+ assertTrue(copySp.equals(defaultSp));
+ }
+
+ /**
+ * Verify that copy constructor works when pass in a valid source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCopyConstructorFromValidSource() throws Exception {
+ HomeSp sourceSp = createHomeSpWithHomeNetworkIds();
+ HomeSp copySp = new HomeSp(sourceSp);
+ assertTrue(copySp.equals(sourceSp));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
new file mode 100644
index 000000000000..2a3676463936
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
@@ -0,0 +1,312 @@
+/*
+ * 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.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.Policy}.
+ */
+@SmallTest
+public class PolicyTest {
+ private static final int MAX_NUMBER_OF_EXCLUDED_SSIDS = 128;
+ private static final int MAX_SSID_BYTES = 32;
+ private static final int MAX_PORT_STRING_BYTES = 64;
+
+ /**
+ * Helper function for creating a {@link Policy} for testing.
+ *
+ * @return {@link Policy}
+ */
+ private static Policy createPolicy() {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(123);
+ policy.setMinHomeUplinkBandwidth(345);
+ policy.setMinRoamingDownlinkBandwidth(567);
+ policy.setMinRoamingUplinkBandwidth(789);
+ policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+ Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "23,342,123");
+ requiredProtoPortMap.put(23, "789,372,1235");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ policy.setMaximumBssLoadValue(12);
+
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("partner1.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(12);
+ partner1.setCountries("us,jp");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("partner2.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(42);
+ partner2.setCountries("ca,fr");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(1712);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("username");
+ policyUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ policyUpdate.setTrustRootCertUrl("trust.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(new byte[32]);
+ policy.setPolicyUpdate(policyUpdate);
+
+ return policy;
+ }
+
+ /**
+ * Helper function for verifying Policy after parcel write then read.
+ * @param policyToWrite
+ * @throws Exception
+ */
+ private static void verifyParcel(Policy policyToWrite) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ policyToWrite.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ Policy policyFromRead = Policy.CREATOR.createFromParcel(parcel);
+ assertTrue(policyFromRead.equals(policyToWrite));
+ }
+
+ /**
+ * Verify parcel read/write for an empty Policy.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyPolicy() throws Exception {
+ verifyParcel(new Policy());
+ }
+
+ /**
+ * Verify parcel read/write for a Policy with all fields set.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithFullPolicy() throws Exception {
+ verifyParcel(createPolicy());
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without protocol port map.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutProtoPortMap() throws Exception {
+ Policy policy = createPolicy();
+ policy.setRequiredProtoPortMap(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without preferred roaming partner list.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutPreferredRoamingPartnerList() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPreferredRoamingPartnerList(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without policy update parameters.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify that policy created using copy constructor with null source should be the same
+ * as the policy created using default constructor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithNullSource() throws Exception {
+ Policy copyPolicy = new Policy(null);
+ Policy defaultPolicy = new Policy();
+ assertTrue(defaultPolicy.equals(copyPolicy));
+ }
+
+ /**
+ * Verify that policy created using copy constructor with a valid source should be the
+ * same as the source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithFullPolicy() throws Exception {
+ Policy policy = createPolicy();
+ Policy copyPolicy = new Policy(policy);
+ assertTrue(policy.equals(copyPolicy));
+ }
+
+ /**
+ * Verify that a default policy (with no informatio) is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithDefault() throws Exception {
+ Policy policy = new Policy();
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy created using {@link #createPolicy} is valid, since all fields are
+ * filled in with valid values.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithFullPolicy() throws Exception {
+ assertTrue(createPolicy().validate());
+ }
+
+ /**
+ * Verify that a policy without policy update parameters is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithoutPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(null);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with invalid policy update parameters is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(new UpdateParameter());
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a preferred roaming partner with FQDN not specified is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithRoamingPartnerWithoutFQDN() throws Exception {
+ Policy policy = createPolicy();
+ Policy.RoamingPartner partner = new Policy.RoamingPartner();
+ partner.setFqdnExactMatch(true);
+ partner.setPriority(12);
+ partner.setCountries("us,jp");
+ policy.getPreferredRoamingPartnerList().add(partner);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a preferred roaming partner with countries not specified is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithRoamingPartnerWithoutCountries() throws Exception {
+ Policy policy = createPolicy();
+ Policy.RoamingPartner partner = new Policy.RoamingPartner();
+ partner.setFqdn("test.com");
+ partner.setFqdnExactMatch(true);
+ partner.setPriority(12);
+ policy.getPreferredRoamingPartnerList().add(partner);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a proto-port tuple that contains an invalid port string is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidPortStringInProtoPortMap() throws Exception {
+ Policy policy = createPolicy();
+ byte[] rawPortBytes = new byte[MAX_PORT_STRING_BYTES + 1];
+ policy.getRequiredProtoPortMap().put(
+ 324, new String(rawPortBytes, StandardCharsets.UTF_8));
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with number of excluded SSIDs exceeded the max is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithSsidExclusionListSizeExceededMax() throws Exception {
+ Policy policy = createPolicy();
+ String[] excludedSsidList = new String[MAX_NUMBER_OF_EXCLUDED_SSIDS + 1];
+ Arrays.fill(excludedSsidList, "ssid");
+ policy.setExcludedSsidList(excludedSsidList);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with an invalid SSID in the excluded SSID list is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidSsid() throws Exception {
+ Policy policy = createPolicy();
+ byte[] rawSsidBytes = new byte[MAX_SSID_BYTES + 1];
+ Arrays.fill(rawSsidBytes, (byte) 'a');
+ String[] excludedSsidList = new String[] {
+ new String(rawSsidBytes, StandardCharsets.UTF_8)};
+ policy.setExcludedSsidList(excludedSsidList);
+ assertFalse(policy.validate());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
new file mode 100644
index 000000000000..551ed43c5efa
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
@@ -0,0 +1,348 @@
+/*
+ * 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.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.UpdateParameter}.
+ */
+@SmallTest
+public class UpdateParameterTest {
+ private static final int MAX_URI_BYTES = 1023;
+ private static final int MAX_URL_BYTES = 1023;
+ private static final int MAX_USERNAME_BYTES = 63;
+ private static final int MAX_PASSWORD_BYTES = 255;
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * Helper function for creating a {@link UpdateParameter} for testing.
+ *
+ * @return {@link UpdateParameter}
+ */
+ private static UpdateParameter createUpdateParameter() {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(1712);
+ updateParam.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ updateParam.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ updateParam.setServerUri("server.pdate.com");
+ updateParam.setUsername("username");
+ updateParam.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ updateParam.setTrustRootCertUrl("trust.cert.com");
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[32]);
+ return updateParam;
+ }
+
+ /**
+ * Helper function for verifying UpdateParameter after parcel write then read.
+ * @param paramToWrite The UpdateParamter to verify
+ * @throws Exception
+ */
+ private static void verifyParcel(UpdateParameter paramToWrite) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ paramToWrite.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ UpdateParameter paramFromRead = UpdateParameter.CREATOR.createFromParcel(parcel);
+ assertTrue(paramFromRead.equals(paramToWrite));
+ }
+
+ /**
+ * Verify parcel read/write for an empty UpdateParameter.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyUpdateParameter() throws Exception {
+ verifyParcel(new UpdateParameter());
+ }
+
+ /**
+ * Verify parcel read/write for a UpdateParameter with all fields set.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithFullUpdateParameter() throws Exception {
+ verifyParcel(createUpdateParameter());
+ }
+
+ /**
+ * Verify that UpdateParameter created using copy constructor with null source should be the
+ * same as the UpdateParameter created using default constructor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithNullSource() throws Exception {
+ UpdateParameter copyParam = new UpdateParameter(null);
+ UpdateParameter defaultParam = new UpdateParameter();
+ assertTrue(defaultParam.equals(copyParam));
+ }
+
+ /**
+ * Verify that UpdateParameter created using copy constructor with a valid source should be the
+ * same as the source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithFullUpdateParameter() throws Exception {
+ UpdateParameter origParam = createUpdateParameter();
+ UpdateParameter copyParam = new UpdateParameter(origParam);
+ assertTrue(origParam.equals(copyParam));
+ }
+
+ /**
+ * Verify that a default UpdateParameter is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithDefault() throws Exception {
+ UpdateParameter updateParam = new UpdateParameter();
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter created using {@link #createUpdateParameter} is valid,
+ * since all fields are filled in with valid values.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithFullPolicy() throws Exception {
+ assertTrue(createUpdateParameter().validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an unknown update method is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUnknowMethod() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUpdateMethod("adsfasd");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an unknown restriction is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUnknowRestriction() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setRestriction("adsfasd");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an username exceeding maximum size is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUsernameExceedingMaxSize() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUsernameBytes = new byte[MAX_USERNAME_BYTES + 1];
+ Arrays.fill(rawUsernameBytes, (byte) 'a');
+ updateParam.setUsername(new String(rawUsernameBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an empty username is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithEmptyUsername() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUsername(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with a password exceeding maximum size is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithPasswordExceedingMaxSize() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawPasswordBytes = new byte[MAX_PASSWORD_BYTES + 1];
+ Arrays.fill(rawPasswordBytes, (byte) 'a');
+ updateParam.setBase64EncodedPassword(new String(rawPasswordBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an empty password is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithEmptyPassword() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setBase64EncodedPassword(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with a Base64 encoded password that contained invalid padding
+ * is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithPasswordContainedInvalidPadding() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setBase64EncodedPassword(updateParam.getBase64EncodedPassword() + "=");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without trust root certificate URL is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutTrustRootCertUrl() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertUrl(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with invalid trust root certificate URL is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithInvalidTrustRootCertUrl() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
+ Arrays.fill(rawUrlBytes, (byte) 'a');
+ updateParam.setTrustRootCertUrl(new String(rawUrlBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without trust root certificate SHA-256 fingerprint is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithouttrustRootCertSha256Fingerprint() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertSha256Fingerprint(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an incorrect size trust root certificate SHA-256
+ * fingerprint is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithInvalidtrustRootCertSha256Fingerprint() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES + 1]);
+ assertFalse(updateParam.validate());
+
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES - 1]);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without server URI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutServerUri() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setServerUri(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an invalid server URI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidServerUri() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUriBytes = new byte[MAX_URI_BYTES + 1];
+ Arrays.fill(rawUriBytes, (byte) 'a');
+ updateParam.setServerUri(new String(rawUriBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with update interval set to "never" will not perform
+ * validation on other parameters, since update is not applicable in this case.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithNoServerCheck() throws Exception {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(UpdateParameter.UPDATE_CHECK_INTERVAL_NEVER);
+ updateParam.setUsername(null);
+ updateParam.setBase64EncodedPassword(null);
+ updateParam.setUpdateMethod(null);
+ updateParam.setRestriction(null);
+ updateParam.setServerUri(null);
+ updateParam.setTrustRootCertUrl(null);
+ updateParam.setTrustRootCertSha256Fingerprint(null);
+ assertTrue(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with unset update interval is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutUpdateInterval() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(Long.MIN_VALUE);
+ assertFalse(updateParam.validate());
+ }
+}